[med-svn] [itksnap] 01/15: Imported Upstream version 3.2.0

Gert Wollny gert-guest at moszumanska.debian.org
Wed Jan 14 15:57:18 UTC 2015


This is an automated email from the git hooks/post-receive script.

gert-guest pushed a commit to branch master
in repository itksnap.

commit 526cf298b5bac41f5a5342076f07fe2040018e83
Author: Gert Wollny <gw.fossdev at gmail.com>
Date:   Wed Jan 14 12:59:19 2015 +0100

    Imported Upstream version 3.2.0
---
 .gitignore                                         |   15 +
 CMake/CustomBuildSettings.cmake                    |   38 -
 CMake/DeployQt5.cmake                              |  339 +
 CMake/find_fltk_13.cmake                           |  158 -
 CMake/rpavlik/GetGitRevisionDescription.cmake      |  130 +
 CMake/rpavlik/GetGitRevisionDescription.cmake.in   |   38 +
 CMake/standalone.cmake                             |   57 +-
 CMakeLists.txt                                     | 1295 ++--
 CTestConfig.cmake                                  |    6 +-
 Common/AbstractModel.cxx                           |  130 +
 Common/AbstractModel.h                             |  111 +
 Common/AbstractPropertyContainerModel.cxx          |   86 +
 Common/AbstractPropertyContainerModel.h            |  360 +
 Common/CommandLineArgumentParser.cxx               |   21 +-
 Common/CommandLineArgumentParser.h                 |   11 +
 Common/EventBucket.cxx                             |   80 +
 Common/EventBucket.h                               |   75 +
 Common/GPUSettings.h.in                            |    2 +
 Common/HistoryManager.cxx                          |  133 +
 Common/HistoryManager.h                            |  136 +
 Common/IPCHandler.cxx                              |  218 +
 Common/IPCHandler.h                                |   83 +
 Common/IRISException.cxx                           |   31 +-
 Common/IRISException.h                             |   32 +-
 Common/IRISVectorTypes.h                           |   62 +-
 Common/ITKExtras/itkVoxBoCUBImageIO.cxx            |   42 +-
 Common/PresetManager.h                             |  111 +
 Common/PresetManager.hxx                           |  151 +
 Common/PropertyModel.h                             | 1188 ++++
 Common/Rebroadcaster.cxx                           |  231 +
 Common/Rebroadcaster.h                             |  116 +
 Common/Registry.cxx                                |  329 +-
 Common/Registry.h                                  |   89 +-
 Common/SNAPCommon.cxx.in                           |   19 +
 Common/SNAPCommon.h                                |  196 +-
 Common/SNAPEventListenerCallbacks.h                |   77 +
 Common/SNAPEvents.h                                |  180 +
 Common/SNAPOpenGL.cxx                              |   39 +
 Common/SNAPOpenGL.h                                |   25 +-
 Common/SystemInterface.cxx                         |  853 +--
 Common/SystemInterface.h                           |  129 +-
 Common/ThreadSpecificData.cxx                      |  115 +
 Common/ThreadSpecificData.h                        |   76 +
 {UserInterface/Window3D => Common}/Trackball.cxx   |    0
 Common/Trackball.h                                 |  129 +
 Documentation/DesignNotes/gui_design.txt           |   56 +
 Documentation/Shortcuts/Shortcuts_SNAP3.pages      |  Bin 0 -> 110336 bytes
 Documentation/Shortcuts/Shortcuts_SNAP3.pdf        |  Bin 0 -> 50039 bytes
 GUI/Model/AbstractLayerAssociatedModel.h           |  258 +
 GUI/Model/AbstractLayerInfoItemSetDomain.h         |   62 +
 GUI/Model/CollectionModel.cxx                      |    5 +
 GUI/Model/CollectionModel.h                        |  210 +
 GUI/Model/ColorLabelPropertyModel.cxx              |  143 +
 GUI/Model/ColorLabelPropertyModel.h                |  117 +
 GUI/Model/ColorLabelQuickListModel.cxx             |  131 +
 GUI/Model/ColorLabelQuickListModel.h               |   59 +
 GUI/Model/ColorMapModel.cxx                        |  661 ++
 GUI/Model/ColorMapModel.h                          |  234 +
 GUI/Model/CursorInspectionModel.cxx                |  162 +
 GUI/Model/CursorInspectionModel.h                  |   99 +
 GUI/Model/DisplayLayoutModel.cxx                   |  215 +
 GUI/Model/DisplayLayoutModel.h                     |  113 +
 GUI/Model/Generic3DModel.cxx                       |  453 ++
 GUI/Model/Generic3DModel.h                         |  173 +
 GUI/Model/GenericSliceModel.cxx                    |  598 ++
 GUI/Model/GenericSliceModel.h                      |  343 +
 GUI/Model/GlobalPreferencesModel.cxx               |  203 +
 GUI/Model/GlobalPreferencesModel.h                 |  134 +
 GUI/Model/GlobalUIModel.cxx                        |  873 +++
 GUI/Model/GlobalUIModel.h                          |  428 ++
 GUI/Model/ImageIOWizardModel.cxx                   |  405 ++
 GUI/Model/ImageIOWizardModel.h                     |  229 +
 GUI/Model/ImageInfoModel.cxx                       |  204 +
 GUI/Model/ImageInfoModel.h                         |   97 +
 GUI/Model/IntensityCurveModel.cxx                  |  748 +++
 GUI/Model/IntensityCurveModel.h                    |  242 +
 GUI/Model/LabelEditorModel.cxx                     |  374 ++
 GUI/Model/LabelEditorModel.h                       |  126 +
 GUI/Model/LayerGeneralPropertiesModel.cxx          |  357 +
 GUI/Model/LayerGeneralPropertiesModel.h            |  142 +
 GUI/Model/LayerSelectionModel.cxx                  |   22 +
 GUI/Model/LayerSelectionModel.h                    |   54 +
 GUI/Model/LayerTableRowModel.cxx                   |  371 ++
 GUI/Model/LayerTableRowModel.h                     |  175 +
 GUI/Model/MeshExportModel.cxx                      |  179 +
 GUI/Model/MeshExportModel.h                        |  105 +
 GUI/Model/NumericPropertyToggleAdaptor.h           |  122 +
 GUI/Model/OrthogonalSliceCursorNavigationModel.cxx |  185 +
 GUI/Model/OrthogonalSliceCursorNavigationModel.h   |   93 +
 GUI/Model/PaintbrushModel.cxx                      |  490 ++
 GUI/Model/PaintbrushModel.h                        |   69 +
 GUI/Model/PaintbrushSettingsModel.cxx              |  136 +
 GUI/Model/PaintbrushSettingsModel.h                |   65 +
 GUI/Model/PolygonDrawingModel.cxx                  |  862 +++
 GUI/Model/PolygonDrawingModel.h                    |  192 +
 GUI/Model/RandomAccessCollectionModel.cxx          |    2 +
 GUI/Model/RandomAccessCollectionModel.h            |  242 +
 GUI/Model/RegistryEntryPropertyModel.h             |   75 +
 GUI/Model/ReorientImageModel.cxx                   |  332 +
 GUI/Model/ReorientImageModel.h                     |  145 +
 GUI/Model/SNAPUIFlag.h                             |   79 +
 GUI/Model/SNAPUIFlag.txx                           |    0
 GUI/Model/SaveModifiedLayersModel.cxx              |  301 +
 GUI/Model/SaveModifiedLayersModel.h                |  207 +
 GUI/Model/SliceWindowCoordinator.cxx               |  471 ++
 GUI/Model/SliceWindowCoordinator.h                 |  188 +
 GUI/Model/SnakeParameterModel.cxx                  |  379 ++
 GUI/Model/SnakeParameterModel.h                    |  126 +
 GUI/Model/SnakeROIModel.cxx                        |  299 +
 GUI/Model/SnakeROIModel.h                          |  141 +
 GUI/Model/SnakeROIResampleModel.cxx                |  256 +
 GUI/Model/SnakeROIResampleModel.h                  |  100 +
 GUI/Model/SnakeWizardModel.cxx                     | 1579 +++++
 GUI/Model/SnakeWizardModel.h                       |  446 ++
 GUI/Model/StateManagement.cxx                      |   79 +
 GUI/Model/StateManagement.h                        |  134 +
 GUI/Model/SynchronizationModel.cxx                 |  221 +
 GUI/Model/SynchronizationModel.h                   |   60 +
 GUI/Model/UIAction.cxx                             |    9 +
 GUI/Model/UIAction.h                               |   51 +
 GUI/Model/UIReporterDelegates.cxx                  |    5 +
 GUI/Model/UIReporterDelegates.h                    |   90 +
 GUI/Model/UIState.h                                |   22 +
 GUI/Qt/Components/.DS_Store                        |  Bin 0 -> 6148 bytes
 GUI/Qt/Components/CollapsableGroupBox.cxx          |   35 +
 GUI/Qt/Components/CollapsableGroupBox.h            |   31 +
 GUI/Qt/Components/CollapsableGroupBox.ui           |  102 +
 GUI/Qt/Components/ColorLabelQuickListWidget.cxx    |  124 +
 GUI/Qt/Components/ColorLabelQuickListWidget.h      |   57 +
 GUI/Qt/Components/ColorMapInspector.cxx            |  180 +
 GUI/Qt/Components/ColorMapInspector.h              |   61 +
 GUI/Qt/Components/ColorMapInspector.ui             |  602 ++
 GUI/Qt/Components/ContrastInspector.cxx            |  103 +
 GUI/Qt/Components/ContrastInspector.h              |   51 +
 GUI/Qt/Components/ContrastInspector.ui             |  721 ++
 GUI/Qt/Components/CursorInspector.cxx              |  163 +
 GUI/Qt/Components/CursorInspector.h                |   47 +
 GUI/Qt/Components/CursorInspector.ui               |  348 +
 GUI/Qt/Components/DisplayLayoutInspector.cxx       |   35 +
 GUI/Qt/Components/DisplayLayoutInspector.h         |   28 +
 GUI/Qt/Components/DisplayLayoutInspector.ui        |  339 +
 GUI/Qt/Components/FileChooserPanelWithHistory.cxx  |  631 ++
 GUI/Qt/Components/FileChooserPanelWithHistory.h    |  125 +
 GUI/Qt/Components/FileChooserPanelWithHistory.ui   |  224 +
 GUI/Qt/Components/GeneralLayerInspector.cxx        |   55 +
 GUI/Qt/Components/GeneralLayerInspector.h          |   29 +
 GUI/Qt/Components/GeneralLayerInspector.ui         |  208 +
 GUI/Qt/Components/HistoryQListModel.cxx            |   81 +
 GUI/Qt/Components/HistoryQListModel.h              |   45 +
 GUI/Qt/Components/ImageInfoInspector.cxx           |   52 +
 GUI/Qt/Components/ImageInfoInspector.h             |   29 +
 GUI/Qt/Components/ImageInfoInspector.ui            |  964 +++
 GUI/Qt/Components/LabelInspector.cxx               |   54 +
 GUI/Qt/Components/LabelInspector.h                 |   33 +
 GUI/Qt/Components/LabelInspector.ui                |  431 ++
 GUI/Qt/Components/LabelMiniInspector.cxx           |   52 +
 GUI/Qt/Components/LabelMiniInspector.h             |   33 +
 GUI/Qt/Components/LabelMiniInspector.ui            |  280 +
 GUI/Qt/Components/LabelSelectionButton.cxx         |  307 +
 GUI/Qt/Components/LabelSelectionButton.h           |   73 +
 GUI/Qt/Components/LatentITKEventNotifier.cxx       |  186 +
 GUI/Qt/Components/LatentITKEventNotifier.h         |   88 +
 GUI/Qt/Components/LayerInspectorRowDelegate.cxx    |  473 ++
 GUI/Qt/Components/LayerInspectorRowDelegate.h      |  111 +
 GUI/Qt/Components/LayerInspectorRowDelegate.ui     |  433 ++
 GUI/Qt/Components/MetadataInspector.cxx            |   82 +
 GUI/Qt/Components/MetadataInspector.h              |   63 +
 GUI/Qt/Components/MetadataInspector.ui             |  103 +
 GUI/Qt/Components/PaintbrushToolPanel.cxx          |   58 +
 GUI/Qt/Components/PaintbrushToolPanel.h            |   27 +
 GUI/Qt/Components/PaintbrushToolPanel.ui           |  421 ++
 GUI/Qt/Components/QActionButton.cxx                |   46 +
 GUI/Qt/Components/QActionButton.h                  |   31 +
 GUI/Qt/Components/QColorButtonWidget.cxx           |   35 +
 GUI/Qt/Components/QColorButtonWidget.h             |   33 +
 GUI/Qt/Components/QDoubleSlider.cxx                |   46 +
 GUI/Qt/Components/QDoubleSlider.h                  |   69 +
 GUI/Qt/Components/QDoubleSliderWithEditor.cxx      |  162 +
 GUI/Qt/Components/QDoubleSliderWithEditor.h        |   65 +
 GUI/Qt/Components/QDoubleSliderWithEditor.ui       |   44 +
 GUI/Qt/Components/QtCursorOverride.h               |   42 +
 GUI/Qt/Components/QtIPCManager.cxx                 |   33 +
 GUI/Qt/Components/QtIPCManager.h                   |   38 +
 GUI/Qt/Components/QtRendererPlatformSupport.cxx    |  128 +
 GUI/Qt/Components/QtRendererPlatformSupport.h      |   23 +
 GUI/Qt/Components/QtReporterDelegates.cxx          |  154 +
 GUI/Qt/Components/QtReporterDelegates.h            |   92 +
 GUI/Qt/Components/QtWarningDialog.cxx              |   56 +
 GUI/Qt/Components/QtWarningDialog.h                |   40 +
 GUI/Qt/Components/QtWarningDialog.ui               |  105 +
 GUI/Qt/Components/QtWidgetActivator.cxx            |   75 +
 GUI/Qt/Components/QtWidgetActivator.h              |  102 +
 GUI/Qt/Components/RecentHistoryItemsView.cxx       |   98 +
 GUI/Qt/Components/RecentHistoryItemsView.h         |   51 +
 GUI/Qt/Components/RecentHistoryItemsView.ui        |  505 ++
 GUI/Qt/Components/SNAPComponent.cxx                |   46 +
 GUI/Qt/Components/SNAPComponent.h                  |   46 +
 GUI/Qt/Components/SNAPQtCommon.cxx                 |  533 ++
 GUI/Qt/Components/SNAPQtCommon.h                   |  155 +
 GUI/Qt/Components/SliceViewPanel.cxx               |  503 ++
 GUI/Qt/Components/SliceViewPanel.h                 |  108 +
 GUI/Qt/Components/SliceViewPanel.ui                |  983 +++
 GUI/Qt/Components/SnakeToolROIPanel.cxx            |   75 +
 GUI/Qt/Components/SnakeToolROIPanel.h              |   35 +
 GUI/Qt/Components/SnakeToolROIPanel.ui             |  342 +
 GUI/Qt/Components/SnakeWizardPanel.cxx             |  475 ++
 GUI/Qt/Components/SnakeWizardPanel.h               |  134 +
 GUI/Qt/Components/SnakeWizardPanel.ui              | 2081 ++++++
 GUI/Qt/Components/SynchronizationInspector.cxx     |   41 +
 GUI/Qt/Components/SynchronizationInspector.h       |   28 +
 GUI/Qt/Components/SynchronizationInspector.ui      |  204 +
 GUI/Qt/Components/ViewPanel3D.cxx                  |  288 +
 GUI/Qt/Components/ViewPanel3D.h                    |  109 +
 GUI/Qt/Components/ViewPanel3D.ui                   |  312 +
 GUI/Qt/Components/VoxelIntensityQTableModel.cxx    |  116 +
 GUI/Qt/Components/VoxelIntensityQTableModel.h      |  100 +
 GUI/Qt/Components/ZoomInspector.cxx                |   96 +
 GUI/Qt/Components/ZoomInspector.h                  |   65 +
 GUI/Qt/Components/ZoomInspector.ui                 |  380 ++
 GUI/Qt/Coupling/QtAbstractButtonCoupling.h         |  160 +
 GUI/Qt/Coupling/QtAbstractItemViewCoupling.h       |  294 +
 GUI/Qt/Coupling/QtActionCoupling.h                 |   36 +
 GUI/Qt/Coupling/QtActionGroupCoupling.h            |   49 +
 GUI/Qt/Coupling/QtCheckBoxCoupling.h               |   59 +
 GUI/Qt/Coupling/QtCheckableWidgetGroupCoupling.h   |   97 +
 GUI/Qt/Coupling/QtColorWheelCoupling.h             |   51 +
 GUI/Qt/Coupling/QtComboBoxCoupling.h               |  267 +
 GUI/Qt/Coupling/QtDoubleSliderWithEditorCoupling.h |   84 +
 GUI/Qt/Coupling/QtDoubleSpinBoxCoupling.h          |   98 +
 GUI/Qt/Coupling/QtLabelCoupling.h                  |   43 +
 GUI/Qt/Coupling/QtLineEditCoupling.h               |  122 +
 GUI/Qt/Coupling/QtListWidgetCoupling.h             |  141 +
 GUI/Qt/Coupling/QtPagedWidgetCoupling.h            |  106 +
 GUI/Qt/Coupling/QtRadioButtonCoupling.h            |   73 +
 GUI/Qt/Coupling/QtScrollbarCoupling.h              |   74 +
 GUI/Qt/Coupling/QtSliderCoupling.h                 |  120 +
 GUI/Qt/Coupling/QtSpinBoxCoupling.h                |   88 +
 GUI/Qt/Coupling/QtTableWidgetCoupling.cxx          |    5 +
 GUI/Qt/Coupling/QtTableWidgetCoupling.h            |  299 +
 GUI/Qt/Coupling/QtToolbarCoupling.h                |  146 +
 GUI/Qt/Coupling/QtWidgetArrayCoupling.h            |  433 ++
 GUI/Qt/Coupling/QtWidgetCoupling.h                 |  719 ++
 GUI/Qt/External/ColorWheel/ColorWheel.cxx          |  321 +
 GUI/Qt/External/ColorWheel/ColorWheel.h            |   65 +
 GUI/Qt/ModelView/GMMTableModel.cxx                 |  351 +
 GUI/Qt/ModelView/GMMTableModel.h                   |   91 +
 GUI/Qt/Resources/COPYING                           |  674 ++
 GUI/Qt/Resources/SNAPResources.qrc                 |  115 +
 GUI/Qt/Resources/arrow_down_16.png                 |  Bin 0 -> 939 bytes
 GUI/Qt/Resources/arrow_up_16.png                   |  Bin 0 -> 907 bytes
 GUI/Qt/Resources/brush_shape_adaptive.png          |  Bin 0 -> 1210 bytes
 GUI/Qt/Resources/brush_shape_round.png             |  Bin 0 -> 1199 bytes
 GUI/Qt/Resources/brush_shape_square.png            |  Bin 0 -> 1153 bytes
 GUI/Qt/Resources/combo_all_labels.png              |  Bin 0 -> 937 bytes
 GUI/Qt/Resources/combo_visible_labels.png          |  Bin 0 -> 6502 bytes
 GUI/Qt/Resources/configure.png                     |  Bin 0 -> 1962 bytes
 GUI/Qt/Resources/credits.html                      |   25 +
 GUI/Qt/Resources/crosshair.gif                     |  Bin 0 -> 1753 bytes
 GUI/Qt/Resources/crosshair3D.gif                   |  Bin 0 -> 2405 bytes
 .../Qt/Resources}/crosshair3Dtiny.gif              |  Bin
 GUI/Qt/Resources/crosshair_cursor_bitmap.png       |  Bin 0 -> 163 bytes
 GUI/Qt/Resources/crosshair_cursor_mask.png         |  Bin 0 -> 146 bytes
 GUI/Qt/Resources/delete_22.png                     |  Bin 0 -> 1586 bytes
 GUI/Qt/Resources/dl_3d.png                         |  Bin 0 -> 1396 bytes
 GUI/Qt/Resources/dl_axial.png                      |  Bin 0 -> 1332 bytes
 GUI/Qt/Resources/dl_coronal.png                    |  Bin 0 -> 1368 bytes
 GUI/Qt/Resources/dl_fourviews.png                  |  Bin 0 -> 1182 bytes
 GUI/Qt/Resources/dl_sagittal.png                   |  Bin 0 -> 1380 bytes
 GUI/Qt/Resources/dl_toolbox.png                    |  Bin 0 -> 1204 bytes
 GUI/Qt/Resources/dlg_error_32.png                  |  Bin 0 -> 1929 bytes
 GUI/Qt/Resources/dlg_warning_32.png                |  Bin 0 -> 1797 bytes
 GUI/Qt/Resources/edgefunction.png                  |  Bin 0 -> 9457 bytes
 GUI/Qt/Resources/expand_16.png                     |  Bin 0 -> 1218 bytes
 GUI/Qt/Resources/fancyslider.css                   |   53 +
 GUI/Qt/Resources/fltkbutton.png                    |  Bin 0 -> 1158 bytes
 GUI/Qt/Resources/fltkbutton_pressed.png            |  Bin 0 -> 1043 bytes
 GUI/Qt/Resources/fltkpanel.png                     |  Bin 0 -> 1101 bytes
 .../Artwork => GUI/Qt/Resources}/formula01.gif     |  Bin
 .../Artwork => GUI/Qt/Resources}/formula02.gif     |  Bin
 .../Artwork => GUI/Qt/Resources}/formula03.gif     |  Bin
 GUI/Qt/Resources/icons8_close_16.png               |  Bin 0 -> 1552 bytes
 GUI/Qt/Resources/icons8_down_18.png                |  Bin 0 -> 1570 bytes
 GUI/Qt/Resources/icons8_fantasy_16.png             |  Bin 0 -> 1693 bytes
 GUI/Qt/Resources/icons8_invisible_16.png           |  Bin 0 -> 842 bytes
 GUI/Qt/Resources/icons8_pin_16.png                 |  Bin 0 -> 1622 bytes
 GUI/Qt/Resources/icons8_unpin_16.png               |  Bin 0 -> 1725 bytes
 GUI/Qt/Resources/icons8_up_18.png                  |  Bin 0 -> 1560 bytes
 GUI/Qt/Resources/icons8_visible_16.png             |  Bin 0 -> 827 bytes
 GUI/Qt/Resources/icons8_zoomin_16.png              |  Bin 0 -> 1710 bytes
 GUI/Qt/Resources/icons8_zoomout_16.png             |  Bin 0 -> 1701 bytes
 GUI/Qt/Resources/icontabwidget.css                 |   30 +
 .../itkLogoSmallTransparentBackground.gif          |  Bin
 GUI/Qt/Resources/itksnap.css                       |   35 +
 GUI/Qt/Resources/itksnap.qss                       |   38 +
 GUI/Qt/Resources/layer_Inspector_16.png            |  Bin 0 -> 989 bytes
 GUI/Qt/Resources/layer_invisible_16.png            |  Bin 0 -> 3517 bytes
 GUI/Qt/Resources/layer_visible_16.png              |  Bin 0 -> 3790 bytes
 GUI/Qt/Resources/layout_overlay_16.png             |  Bin 0 -> 1303 bytes
 GUI/Qt/Resources/layout_tile_16.png                |  Bin 0 -> 1287 bytes
 GUI/Qt/Resources/license.txt                       |  674 ++
 GUI/Qt/Resources/lock_blue_16.png                  |  Bin 0 -> 1834 bytes
 GUI/Qt/Resources/lock_gray_16.png                  |  Bin 0 -> 1730 bytes
 .../Artwork => GUI/Qt/Resources}/logo.gif          |  Bin
 .../Artwork => GUI/Qt/Resources}/logo_new.gif      |  Bin
 GUI/Qt/Resources/logo_square.png                   |  Bin 0 -> 19028 bytes
 GUI/Qt/Resources/logo_square_shadow.png            |  Bin 0 -> 33426 bytes
 GUI/Qt/Resources/mb_left.png                       |  Bin 0 -> 3071 bytes
 GUI/Qt/Resources/media-playback-pause-4.png        |  Bin 0 -> 783 bytes
 GUI/Qt/Resources/media-playback-singlestep.png     |  Bin 0 -> 2009 bytes
 GUI/Qt/Resources/media-playback-start-10x-4.png    |  Bin 0 -> 2042 bytes
 GUI/Qt/Resources/media-playback-start-1x-4.png     |  Bin 0 -> 1946 bytes
 GUI/Qt/Resources/media-playback-start-4.png        |  Bin 0 -> 1178 bytes
 GUI/Qt/Resources/media-playback-stop-4.png         |  Bin 0 -> 765 bytes
 GUI/Qt/Resources/media-seek-backward-4.png         |  Bin 0 -> 1028 bytes
 GUI/Qt/Resources/media-skip-forward-4.png          |  Bin 0 -> 1139 bytes
 GUI/Qt/Resources/menu-arrow.png                    |  Bin 0 -> 1425 bytes
 GUI/Qt/Resources/network-wireless.png              |  Bin 0 -> 1678 bytes
 GUI/Qt/Resources/open_22.png                       |  Bin 0 -> 3496 bytes
 GUI/Qt/Resources/open_popup_16.png                 |  Bin 0 -> 1732 bytes
 .../Qt/Resources}/outputintensity.gif              |  Bin
 GUI/Qt/Resources/paintbrush.gif                    |  Bin 0 -> 1766 bytes
 GUI/Qt/Resources/poly.gif                          |  Bin 0 -> 1949 bytes
 GUI/Qt/Resources/popup_clear_16.png                |  Bin 0 -> 1215 bytes
 GUI/Qt/Resources/popup_delete_16.png               |  Bin 0 -> 1083 bytes
 GUI/Qt/Resources/popup_edit_16.png                 |  Bin 0 -> 1197 bytes
 GUI/Qt/Resources/popup_ok_16.png                   |  Bin 0 -> 1056 bytes
 GUI/Qt/Resources/popup_paste_16.png                |  Bin 0 -> 1073 bytes
 GUI/Qt/Resources/popup_split_16.png                |  Bin 0 -> 985 bytes
 GUI/Qt/Resources/popup_undo_16.png                 |  Bin 0 -> 1063 bytes
 .../Artwork => GUI/Qt/Resources}/ra.gif            |  Bin
 .../Artwork => GUI/Qt/Resources}/rb.gif            |  Bin
 .../Artwork => GUI/Qt/Resources}/rc.gif            |  Bin
 GUI/Qt/Resources/redo_22.png                       |  Bin 0 -> 2091 bytes
 GUI/Qt/Resources/revertaxis_16.png                 |  Bin 0 -> 1421 bytes
 GUI/Qt/Resources/rotate3d.gif                      |  Bin 0 -> 2488 bytes
 .../Artwork => GUI/Qt/Resources}/rotate3dTiny.gif  |  Bin
 GUI/Qt/Resources/save_22.png                       |  Bin 0 -> 1883 bytes
 GUI/Qt/Resources/scalpel.gif                       |  Bin 0 -> 2455 bytes
 .../Artwork => GUI/Qt/Resources}/screencapture.gif |  Bin
 .../Qt/Resources}/screencapture2.gif               |  Bin
 GUI/Qt/Resources/snake.gif                         |  Bin 0 -> 2592 bytes
 GUI/Qt/Resources/snap_splash_172.png               |  Bin 0 -> 24326 bytes
 GUI/Qt/Resources/snapres/EdgeForcesExample.png     |  Bin 0 -> 1658 bytes
 GUI/Qt/Resources/snapres/RegionForcesExample.png   |  Bin 0 -> 1111 bytes
 .../snapres/SnakeParameterPreviewCurve.txt         |   12 +
 GUI/Qt/Resources/source/CVS/Entries                |    2 +
 GUI/Qt/Resources/source/CVS/Repository             |    1 +
 GUI/Qt/Resources/source/CVS/Root                   |    1 +
 .../Qt/Resources}/source/snaplogo_gimp.xcf.gz      |  Bin
 GUI/Qt/Resources/speed_bluegray.png                |  Bin 0 -> 2431 bytes
 GUI/Qt/Resources/speed_redoverlay.png              |  Bin 0 -> 2344 bytes
 GUI/Qt/Resources/spray.gif                         |  Bin 0 -> 2566 bytes
 GUI/Qt/Resources/thresh_both.png                   |  Bin 0 -> 2019 bytes
 GUI/Qt/Resources/thresh_lower.png                  |  Bin 0 -> 1888 bytes
 GUI/Qt/Resources/thresh_upper.png                  |  Bin 0 -> 1890 bytes
 GUI/Qt/Resources/tools.png                         |  Bin 0 -> 1543 bytes
 GUI/Qt/Resources/triangle_small_down_16.png        |  Bin 0 -> 1599 bytes
 GUI/Qt/Resources/triangle_small_right_16.png       |  Bin 0 -> 1603 bytes
 GUI/Qt/Resources/undo_22.png                       |  Bin 0 -> 2098 bytes
 GUI/Qt/Resources/view-refresh-4.png                |  Bin 0 -> 2307 bytes
 GUI/Qt/Resources/zoom.gif                          |  Bin 0 -> 1839 bytes
 .../Artwork => GUI/Qt/Resources}/zoom3d.gif        |  Bin
 GUI/Qt/View/ColorMapBox.cxx                        |   66 +
 GUI/Qt/View/ColorMapBox.h                          |   73 +
 GUI/Qt/View/CrosshairsInteractionMode.cxx          |  284 +
 GUI/Qt/View/CrosshairsInteractionMode.h            |   85 +
 GUI/Qt/View/GenericSliceView.cxx                   |   71 +
 GUI/Qt/View/GenericSliceView.h                     |   77 +
 GUI/Qt/View/GenericView3D.cxx                      |  258 +
 GUI/Qt/View/GenericView3D.h                        |   42 +
 GUI/Qt/View/InteractionMode.cxx                    |   27 +
 GUI/Qt/View/InteractionMode.h                      |   53 +
 GUI/Qt/View/InteractionModeClient.cxx              |   94 +
 GUI/Qt/View/InteractionModeClient.h                |   87 +
 GUI/Qt/View/PaintbrushInteractionMode.cxx          |   97 +
 GUI/Qt/View/PaintbrushInteractionMode.h            |   45 +
 GUI/Qt/View/PolygonDrawingInteractionMode.cxx      |  220 +
 GUI/Qt/View/PolygonDrawingInteractionMode.h        |   63 +
 GUI/Qt/View/QtAbstractOpenGLBox.cxx                |  157 +
 GUI/Qt/View/QtAbstractOpenGLBox.h                  |  107 +
 GUI/Qt/View/QtInteractionDelegateWidget.cxx        |  163 +
 GUI/Qt/View/QtInteractionDelegateWidget.h          |   96 +
 GUI/Qt/View/QtSimpleOpenGLBox.cxx                  |   27 +
 GUI/Qt/View/QtSimpleOpenGLBox.h                    |   38 +
 GUI/Qt/View/QtVTKInteractionDelegateWidget.cxx     |   80 +
 GUI/Qt/View/QtVTKInteractionDelegateWidget.h       |   39 +
 GUI/Qt/View/QtVTKRenderWindowBox.cxx               |   54 +
 GUI/Qt/View/QtVTKRenderWindowBox.h                 |   35 +
 .../View/SliceWindowInteractionDelegateWidget.cxx  |  105 +
 GUI/Qt/View/SliceWindowInteractionDelegateWidget.h |   39 +
 GUI/Qt/View/SnakeROIInteractionMode.cxx            |   85 +
 GUI/Qt/View/SnakeROIInteractionMode.h              |   37 +
 GUI/Qt/View/ThumbnailInteractionMode.cxx           |   90 +
 GUI/Qt/View/ThumbnailInteractionMode.h             |   54 +
 GUI/Qt/Windows/.DS_Store                           |  Bin 0 -> 12292 bytes
 GUI/Qt/Windows/AboutDialog.cxx                     |   29 +
 GUI/Qt/Windows/AboutDialog.h                       |   23 +
 GUI/Qt/Windows/AboutDialog.ui                      |  235 +
 GUI/Qt/Windows/DropActionDialog.cxx                |  107 +
 GUI/Qt/Windows/DropActionDialog.h                  |   49 +
 GUI/Qt/Windows/DropActionDialog.ui                 |  252 +
 GUI/Qt/Windows/ImageIODialog.cxx                   |   14 +
 GUI/Qt/Windows/ImageIODialog.h                     |   22 +
 GUI/Qt/Windows/ImageIODialog.ui                    |   68 +
 GUI/Qt/Windows/ImageIOWizard.cxx                   |  758 +++
 GUI/Qt/Windows/ImageIOWizard.h                     |  178 +
 GUI/Qt/Windows/ImageIOWizardSummaryPage.ui         |   19 +
 GUI/Qt/Windows/LabelEditorDialog.cxx               |  198 +
 GUI/Qt/Windows/LabelEditorDialog.h                 |   48 +
 GUI/Qt/Windows/LabelEditorDialog.ui                |  780 +++
 GUI/Qt/Windows/LabelSelectionPopup.cxx             |  114 +
 GUI/Qt/Windows/LabelSelectionPopup.h               |   41 +
 GUI/Qt/Windows/LabelSelectionPopup.ui              |  141 +
 GUI/Qt/Windows/LayerInspectorDialog.cxx            |  433 ++
 GUI/Qt/Windows/LayerInspectorDialog.h              |   85 +
 GUI/Qt/Windows/LayerInspectorDialog.ui             |  291 +
 GUI/Qt/Windows/MainControlPanel.cxx                |  238 +
 GUI/Qt/Windows/MainControlPanel.h                  |   53 +
 GUI/Qt/Windows/MainControlPanel.ui                 |  476 ++
 GUI/Qt/Windows/MainImageWindow.cxx                 | 1634 +++++
 GUI/Qt/Windows/MainImageWindow.h                   |  351 +
 GUI/Qt/Windows/MainImageWindow.ui                  | 1381 ++++
 .../MeshExportWizard/MeshExportBrowsePage.cxx      |  104 +
 .../MeshExportWizard/MeshExportBrowsePage.h        |   32 +
 .../MeshExportWizard/MeshExportBrowsePage.ui       |   58 +
 .../MeshExportWizard/MeshExportModePage.cxx        |   44 +
 .../Windows/MeshExportWizard/MeshExportModePage.h  |   30 +
 .../Windows/MeshExportWizard/MeshExportModePage.ui |  161 +
 .../Windows/MeshExportWizard/MeshExportWizard.cxx  |   21 +
 GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.h |   29 +
 .../Windows/MeshExportWizard/MeshExportWizard.ui   |   46 +
 GUI/Qt/Windows/PreferencesDialog.cxx               |  269 +
 GUI/Qt/Windows/PreferencesDialog.h                 |   61 +
 GUI/Qt/Windows/PreferencesDialog.ui                | 1488 +++++
 GUI/Qt/Windows/QtStyles.cxx                        |   97 +
 GUI/Qt/Windows/QtStyles.h                          |   38 +
 GUI/Qt/Windows/ReorientImageDialog.cxx             |  105 +
 GUI/Qt/Windows/ReorientImageDialog.h               |   46 +
 GUI/Qt/Windows/ReorientImageDialog.ui              |  634 ++
 GUI/Qt/Windows/ResampleDialog.cxx                  |   97 +
 GUI/Qt/Windows/ResampleDialog.h                    |   40 +
 GUI/Qt/Windows/ResampleDialog.ui                   |  463 ++
 GUI/Qt/Windows/SaveModifiedLayersDialog.cxx        |  247 +
 GUI/Qt/Windows/SaveModifiedLayersDialog.h          |   96 +
 GUI/Qt/Windows/SaveModifiedLayersDialog.ui         |   60 +
 GUI/Qt/Windows/SimpleFileDialogWithHistory.cxx     |   73 +
 GUI/Qt/Windows/SimpleFileDialogWithHistory.h       |   47 +
 GUI/Qt/Windows/SimpleFileDialogWithHistory.ui      |   93 +
 GUI/Qt/Windows/SnakeParameterDialog.cxx            |  218 +
 GUI/Qt/Windows/SnakeParameterDialog.h              |   46 +
 GUI/Qt/Windows/SnakeParameterDialog.ui             | 1019 +++
 GUI/Qt/Windows/SpeedImageDialog.cxx                |  158 +
 GUI/Qt/Windows/SpeedImageDialog.h                  |   69 +
 GUI/Qt/Windows/SpeedImageDialog.ui                 | 1260 ++++
 GUI/Qt/Windows/SplashPanel.cxx                     |   16 +
 GUI/Qt/Windows/SplashPanel.h                       |   22 +
 GUI/Qt/Windows/SplashPanel.ui                      |  154 +
 GUI/Qt/Windows/StatisticsDialog.cxx                |  163 +
 GUI/Qt/Windows/StatisticsDialog.h                  |   44 +
 GUI/Qt/Windows/StatisticsDialog.ui                 |  125 +
 GUI/Qt/main.cxx                                    |  698 ++
 GUI/Renderer/AbstractRenderer.cxx                  |   13 +
 GUI/Renderer/AbstractRenderer.h                    |   62 +
 GUI/Renderer/AbstractVTKRenderer.cxx               |  127 +
 GUI/Renderer/AbstractVTKRenderer.h                 |   65 +
 GUI/Renderer/AbstractVTKSceneRenderer.cxx          |   29 +
 GUI/Renderer/AbstractVTKSceneRenderer.h            |   49 +
 GUI/Renderer/ColorMapRenderer.cxx                  |  223 +
 GUI/Renderer/ColorMapRenderer.h                    |   33 +
 GUI/Renderer/CrosshairsRenderer.cxx                |   95 +
 GUI/Renderer/CrosshairsRenderer.h                  |   55 +
 GUI/Renderer/EdgePreprocessingSettingsRenderer.cxx |   87 +
 GUI/Renderer/EdgePreprocessingSettingsRenderer.h   |   44 +
 GUI/Renderer/GLToPNG.cxx                           |   92 +
 GUI/Renderer/GLToPNG.h                             |   58 +
 GUI/Renderer/GMMRenderer.cxx                       |  177 +
 GUI/Renderer/GMMRenderer.h                         |   46 +
 GUI/Renderer/Generic3DRenderer.cxx                 |  796 +++
 GUI/Renderer/Generic3DRenderer.h                   |  157 +
 GUI/Renderer/GenericSliceRenderer.cxx              |  594 ++
 GUI/Renderer/GenericSliceRenderer.h                |  149 +
 GUI/Renderer/IntensityCurveVTKRenderer.cxx         |  578 ++
 GUI/Renderer/IntensityCurveVTKRenderer.h           |   63 +
 GUI/Renderer/LayerHistogramPlotAssembly.cxx        |  101 +
 GUI/Renderer/LayerHistogramPlotAssembly.h          |   67 +
 GUI/Renderer/OpenGLSliceTexture.cxx                |  252 +
 GUI/Renderer/OpenGLSliceTexture.h                  |  144 +
 GUI/Renderer/OrientationGraphicRenderer.cxx        |   93 +
 GUI/Renderer/OrientationGraphicRenderer.h          |   40 +
 .../Reorient/AbstractScannerHelper.cxx             |   29 +
 .../Reorient/AbstractScannerHelper.h               |   28 +
 .../OrientationWidget/Reorient/AxesWidget.cxx      |  105 +
 .../OrientationWidget/Reorient/AxesWidget.h        |   36 +
 .../Reorient/PolyDataAlgorithm2ActorPipe.cxx       |   37 +
 .../Reorient/PolyDataAlgorithm2ActorPipe.h         |   28 +
 .../OrientationWidget/Reorient/ReorientProps.cxx   |  103 +
 .../OrientationWidget/Reorient/ReorientProps.h     |   36 +
 .../OrientationWidget/Reorient/ScannedHuman.cxx    |  131 +
 .../OrientationWidget/Reorient/ScannedHuman.h      |   45 +
 .../OrientationWidget/Reorient/ScanningROI.cxx     |  320 +
 .../OrientationWidget/Reorient/ScanningROI.h       |   75 +
 .../Test_OrientationWidget/CMakeLists.txt          |   78 +
 .../OrientationWidgetGUI.cxx                       |  149 +
 .../Test_OrientationWidget/OrientationWidgetGUI.h  |   39 +
 .../Test_OrientationWidget/OrientationWidgetGUI.ui |  586 ++
 .../Test_OrientationWidget/main.cxx                |   27 +
 .../Test_ReorientGUI/CMakeLists.txt                |   57 +
 .../Test_ReorientGUI/Reorient.cxx                  |   65 +
 .../OrientationWidget/Test_ReorientGUI/Reorient.h  |   35 +
 .../Test_ReorientGUI/ReorientGUI.cxx               |  136 +
 .../Test_ReorientGUI/ReorientGUI.h                 |   34 +
 .../Test_ReorientGUI/ReorientGUI.ui                |  582 ++
 .../OrientationWidget/Test_ReorientGUI/main.cxx    |   23 +
 GUI/Renderer/PaintbrushRenderer.cxx                |  124 +
 GUI/Renderer/PaintbrushRenderer.h                  |   31 +
 GUI/Renderer/PolygonDrawingRenderer.cxx            |  220 +
 GUI/Renderer/PolygonDrawingRenderer.h              |   37 +
 GUI/Renderer/PolygonScanConvert.cxx                |  177 +
 GUI/Renderer/PolygonScanConvert.h                  |   94 +
 GUI/Renderer/SliceWindowDecorationRenderer.cxx     |  280 +
 GUI/Renderer/SliceWindowDecorationRenderer.h       |   30 +
 GUI/Renderer/SnakeModeRenderer.cxx                 |  162 +
 GUI/Renderer/SnakeModeRenderer.h                   |   31 +
 GUI/Renderer/SnakeParameterPreviewRenderer.cxx     |  189 +
 GUI/Renderer/SnakeParameterPreviewRenderer.h       |   58 +
 GUI/Renderer/SnakeROIRenderer.cxx                  |   79 +
 GUI/Renderer/SnakeROIRenderer.h                    |   27 +
 GUI/Renderer/ThresholdSettingsRenderer.cxx         |  115 +
 GUI/Renderer/ThresholdSettingsRenderer.h           |   47 +
 GUI/Renderer/Window3DPicker.cxx                    |  119 +
 GUI/Renderer/Window3DPicker.h                      |   34 +
 Logic/Common/ColorLabel.h                          |   34 +-
 Logic/Common/ColorLabelTable.cxx                   |  371 +-
 Logic/Common/ColorLabelTable.h                     |   97 +-
 Logic/Common/ColorMap.cxx                          |  325 +-
 Logic/Common/ColorMap.h                            |  191 +-
 Logic/Common/ColorMapPresetManager.cxx             |    5 +
 Logic/Common/ColorMapPresetManager.h               |   38 +
 Logic/Common/IRISDisplayGeometry.cxx               |   66 +
 Logic/Common/IRISDisplayGeometry.h                 |   41 +
 Logic/Common/ImageCoordinateGeometry.cxx           |  150 +-
 Logic/Common/ImageCoordinateGeometry.h             |   65 +-
 Logic/Common/ImageRayIntersectionFinder.h          |    2 +-
 Logic/Common/ImageRayIntersectionFinder.txx        |    2 +-
 Logic/Common/LabelUseHistory.cxx                   |  153 +
 Logic/Common/LabelUseHistory.h                     |   73 +
 Logic/Common/MetaDataAccess.cxx                    |  159 +
 Logic/Common/MetaDataAccess.h                      |   35 +
 Logic/Common/SNAPAppearanceSettings.cxx            |  401 ++
 Logic/Common/SNAPAppearanceSettings.h              |  222 +
 Logic/Common/SNAPRegistryIO.cxx                    |  375 +-
 Logic/Common/SNAPRegistryIO.h                      |   48 +-
 Logic/Common/SNAPSegmentationROISettings.cxx       |   44 +-
 Logic/Common/SNAPSegmentationROISettings.h         |   37 +-
 Logic/Common/SegmentationStatistics.cxx            |  217 +-
 Logic/Common/SegmentationStatistics.h              |   39 +-
 Logic/Framework/DefaultBehaviorSettings.cxx        |   32 +
 Logic/Framework/DefaultBehaviorSettings.h          |   66 +
 Logic/Framework/GenericImageData.cxx               |  453 +-
 Logic/Framework/GenericImageData.h                 |  245 +-
 Logic/Framework/GlobalState.cxx                    |  196 +-
 Logic/Framework/GlobalState.h                      |  443 +-
 Logic/Framework/IRISApplication.cxx                | 1914 +++++-
 Logic/Framework/IRISApplication.h                  |  511 +-
 Logic/Framework/IRISImageData.cxx                  |   35 +-
 Logic/Framework/IRISImageData.h                    |   39 +-
 Logic/Framework/ImageIODelegates.cxx               |  259 +
 Logic/Framework/ImageIODelegates.h                 |  183 +
 Logic/Framework/LayerAssociation.h                 |   80 +
 Logic/Framework/LayerAssociation.txx               |  112 +
 Logic/Framework/LayerIterator.cxx                  |  219 +
 Logic/Framework/LayerIterator.h                    |   97 +
 Logic/Framework/SNAPImageData.cxx                  |  342 +-
 Logic/Framework/SNAPImageData.h                    |  105 +-
 Logic/Framework/UndoDataManager.h                  |   15 +
 Logic/Framework/UndoDataManager.txx                |   12 +
 Logic/ImageWrapper/CPUImageToGPUImageFilter.h      |  106 +
 Logic/ImageWrapper/CPUImageToGPUImageFilter.hxx    |   96 +
 Logic/ImageWrapper/CommonRepresentationPolicy.cxx  |  101 +
 Logic/ImageWrapper/CommonRepresentationPolicy.h    |  107 +
 Logic/ImageWrapper/DisplayMappingPolicy.cxx        |  975 +++
 Logic/ImageWrapper/DisplayMappingPolicy.h          |  552 ++
 Logic/ImageWrapper/GreyImageWrapper.cxx            |  202 -
 Logic/ImageWrapper/GreyImageWrapper.h              |  226 -
 Logic/ImageWrapper/GuidedNativeImageIO.cxx         | 1022 ++-
 Logic/ImageWrapper/GuidedNativeImageIO.h           |  186 +-
 Logic/ImageWrapper/ImageIORoutines.h               |   82 -
 Logic/ImageWrapper/ImageWrapper.cxx                | 1371 ++++
 Logic/ImageWrapper/ImageWrapper.h                  |  602 +-
 Logic/ImageWrapper/ImageWrapper.txx                |  565 --
 Logic/ImageWrapper/ImageWrapperBase.cxx            |   97 +
 Logic/ImageWrapper/ImageWrapperBase.h              |  545 ++
 Logic/ImageWrapper/ImageWrapperTraits.cxx          |    2 +
 Logic/ImageWrapper/ImageWrapperTraits.h            |  247 +
 Logic/ImageWrapper/InputSelectionImageFilter.cxx   |   61 +
 Logic/ImageWrapper/InputSelectionImageFilter.h     |   71 +
 Logic/ImageWrapper/LabelImageWrapper.cxx           |  154 -
 Logic/ImageWrapper/LabelImageWrapper.h             |  154 -
 Logic/ImageWrapper/LabelToRGBAFilter.h             |   39 +-
 Logic/ImageWrapper/LevelSetImageWrapper.cxx        |  141 -
 Logic/ImageWrapper/LevelSetImageWrapper.h          |  116 -
 Logic/ImageWrapper/NativeIntensityMappingPolicy.h  |   83 +
 Logic/ImageWrapper/RGBImageWrapper.cxx             |   98 -
 Logic/ImageWrapper/RGBImageWrapper.h               |   90 -
 Logic/ImageWrapper/ScalarImageHistogram.cxx        |  126 +
 Logic/ImageWrapper/ScalarImageHistogram.h          |   90 +
 Logic/ImageWrapper/ScalarImageWrapper.cxx          |  357 +
 Logic/ImageWrapper/ScalarImageWrapper.h            |  242 +-
 Logic/ImageWrapper/ScalarImageWrapper.txx          |  269 -
 Logic/ImageWrapper/SpeedColorMap.cxx               |  105 -
 Logic/ImageWrapper/SpeedColorMap.h                 |  134 -
 Logic/ImageWrapper/SpeedImageWrapper.cxx           |  219 -
 Logic/ImageWrapper/SpeedImageWrapper.h             |  241 -
 Logic/ImageWrapper/ThreadedHistogramImageFilter.h  |  137 +
 .../ImageWrapper/ThreadedHistogramImageFilter.hxx  |  167 +
 Logic/ImageWrapper/UnaryValueToValueFilter.h       |   73 +
 Logic/ImageWrapper/VectorImageWrapper.cxx          |  477 ++
 Logic/ImageWrapper/VectorImageWrapper.h            |  245 +-
 Logic/ImageWrapper/VectorImageWrapper.txx          |   42 -
 Logic/ImageWrapper/VectorToScalarImageAccessor.h   |  201 +
 Logic/LevelSet/SNAPAdvectionFieldImageFilter.h     |    8 +-
 Logic/LevelSet/SNAPAdvectionFieldImageFilter.txx   |    2 +-
 Logic/LevelSet/SNAPLevelSetDriver.cxx              |  351 -
 Logic/LevelSet/SNAPLevelSetDriver.h                |   49 +-
 Logic/LevelSet/SNAPLevelSetDriver.txx              |   85 +-
 Logic/LevelSet/SNAPLevelSetFunction.h              |  236 +-
 Logic/LevelSet/SNAPLevelSetFunction.txx            |  274 +-
 Logic/LevelSet/SnakeParameters.cxx                 |    2 +-
 Logic/LevelSet/SnakeParameters.h                   |    4 +
 Logic/LevelSet/SnakeParametersPreviewPipeline.cxx  |  630 ++
 Logic/LevelSet/SnakeParametersPreviewPipeline.h    |  230 +
 Logic/Mesh/GuidedMeshIO.cxx                        |   13 +-
 Logic/Mesh/GuidedMeshIO.h                          |    2 +-
 Logic/Mesh/IRISMeshPipeline.cxx                    |  211 -
 Logic/Mesh/IRISMeshPipeline.h                      |  135 -
 Logic/Mesh/LevelSetMeshPipeline.cxx                |   38 +-
 Logic/Mesh/LevelSetMeshPipeline.h                  |   34 +-
 .../Mesh}/MeshExportSettings.h                     |    0
 Logic/Mesh/MeshManager.cxx                         |  443 ++
 Logic/Mesh/MeshManager.h                           |  206 +
 Logic/Mesh/MeshObject.cxx                          |  741 ---
 Logic/Mesh/MeshObject.h                            |  265 -
 Logic/Mesh/MeshOptions.cxx                         |   55 +-
 Logic/Mesh/MeshOptions.h                           |  172 +-
 Logic/Mesh/MultiLabelMeshPipeline.cxx              |  392 ++
 Logic/Mesh/MultiLabelMeshPipeline.h                |  187 +
 Logic/Mesh/VTKMeshPipeline.cxx                     |   88 +-
 Logic/Mesh/VTKMeshPipeline.h                       |   12 +-
 Logic/Preprocessing/EdgePreprocessingImageFilter.h |  139 +-
 .../Preprocessing/EdgePreprocessingImageFilter.txx |  176 +-
 Logic/Preprocessing/EdgePreprocessingSettings.cxx  |   42 +-
 Logic/Preprocessing/EdgePreprocessingSettings.h    |   39 +-
 Logic/Preprocessing/GMM/EMGaussianMixtures.cxx     |  471 ++
 Logic/Preprocessing/GMM/EMGaussianMixtures.h       |   70 +
 Logic/Preprocessing/GMM/Gaussian.cxx               |  132 +
 Logic/Preprocessing/GMM/Gaussian.h                 |   51 +
 Logic/Preprocessing/GMM/GaussianMixtureModel.cxx   |  182 +
 Logic/Preprocessing/GMM/GaussianMixtureModel.h     |   67 +
 Logic/Preprocessing/GMM/KMeansPlusPlus.cxx         |  180 +
 Logic/Preprocessing/GMM/KMeansPlusPlus.h           |   28 +
 Logic/Preprocessing/GMM/UnsupervisedClustering.cxx |  263 +
 Logic/Preprocessing/GMM/UnsupervisedClustering.h   |   65 +
 Logic/Preprocessing/GMMClassifyImageFilter.h       |   75 +
 Logic/Preprocessing/GMMClassifyImageFilter.txx     |  161 +
 Logic/Preprocessing/ImageCollectionToImageFilter.h |  301 +
 .../PreprocessingFilterConfigTraits.cxx            |  252 +
 .../PreprocessingFilterConfigTraits.h              |  158 +
 .../RandomForest/Library/classification.h          |  167 +
 .../RandomForest/Library/classifier.h              |  180 +
 Logic/Preprocessing/RandomForest/Library/data.h    |  360 +
 Logic/Preprocessing/RandomForest/Library/forest.h  |  114 +
 Logic/Preprocessing/RandomForest/Library/imageio.h |  149 +
 .../RandomForest/Library/linearalgebra.h           |  227 +
 Logic/Preprocessing/RandomForest/Library/node.h    |  302 +
 Logic/Preprocessing/RandomForest/Library/random.h  |   45 +
 .../RandomForest/Library/statistics.h              |  567 ++
 Logic/Preprocessing/RandomForest/Library/trainer.h |  325 +
 .../RandomForest/Library/trainingcontext.h         |  140 +
 Logic/Preprocessing/RandomForest/Library/tree.h    |  563 ++
 Logic/Preprocessing/RandomForest/Library/type.h    |   16 +
 Logic/Preprocessing/RandomForest/Library/utility.h |  142 +
 .../RandomForest/RFClassificationEngine.cxx        |  194 +
 .../RandomForest/RFClassificationEngine.h          |   70 +
 .../RandomForest/RandomForestClassifier.cxx        |   51 +
 .../RandomForest/RandomForestClassifier.h          |   75 +
 .../RandomForestClassifyImageFilter.h              |   83 +
 .../RandomForestClassifyImageFilter.txx            |  172 +
 Logic/Preprocessing/SlicePreviewFilterWrapper.h    |  188 +
 Logic/Preprocessing/SlicePreviewFilterWrapper.txx  |  203 +
 .../SmoothBinaryThresholdImageFilter.h             |  153 +-
 .../SmoothBinaryThresholdImageFilter.txx           |  169 +-
 Logic/Preprocessing/ThresholdSettings.cxx          |  148 +-
 Logic/Preprocessing/ThresholdSettings.h            |   84 +-
 Logic/Slicing/IRISSlicer.h                         |   56 +-
 Logic/Slicing/IRISSlicer.txx                       |  474 +-
 Logic/Slicing/IntensityCurveInterface.h            |   22 +-
 Logic/Slicing/IntensityCurveVTK.cxx                |   21 +
 Logic/Slicing/IntensityCurveVTK.h                  |    7 +-
 .../IntensityToColorLookupTableImageFilter.cxx     |  244 +
 .../IntensityToColorLookupTableImageFilter.h       |  190 +
 .../Slicing/LookupTableIntensityMappingFilter.cxx  |   93 +
 Logic/Slicing/LookupTableIntensityMappingFilter.h  |   63 +
 Logic/Slicing/LookupTableTraits.h                  |  114 +
 ...omponentImageToScalarLookupTableImageFilter.cxx |  136 +
 ...iComponentImageToScalarLookupTableImageFilter.h |   81 +
 .../RGBALookupTableIntensityMappingFilter.cxx      |   66 +
 .../RGBALookupTableIntensityMappingFilter.h        |   55 +
 Logic/Slicing/UnaryFunctorCache.h                  |  199 -
 Logic/Slicing/UnaryFunctorCache.txx                |  103 -
 ReleaseNotes.txt                                   |  420 +-
 Testing/GUI/Qt/SNAPTestQt.cxx                      |  481 ++
 Testing/GUI/Qt/SNAPTestQt.h                        |  118 +
 Testing/GUI/Qt/Scripts/test_Library.js             |  101 +
 Testing/GUI/Qt/Scripts/test_ProbeIntensity.js      |   16 +
 Testing/GUI/Qt/Scripts/test_RandomForest.js        |   89 +
 Testing/GUI/Qt/Scripts/test_RegionCompetition.js   |   56 +
 Testing/GUI/Qt/Scripts/test_Workspace.js           |   40 +
 Testing/GUI/Qt/TestingScripts.qrc                  |    9 +
 Testing/Logic/SNAPTestDriver.cxx                   |  256 +
 Testing/{ => Logic}/SNAPTestDriver.h               |    0
 Testing/{ => Logic}/TestBase.h                     |    0
 Testing/{ => Logic}/TestCompareLevelSets.cxx       |    0
 Testing/{ => Logic}/TestCompareLevelSets.h         |    0
 Testing/Logic/TestImageWrapper.h                   |   93 +
 Testing/{ => Logic}/TestMain.cxx                   |    0
 Testing/{ => Logic}/TutorialTest.cxx               |    0
 Testing/SNAPTestDriver.cxx                         |  256 -
 Testing/TestData/MRIcrop-orig.gipl.gz              |  Bin 0 -> 399537 bytes
 Testing/TestData/MRIcrop-seg.gipl.gz               |  Bin 0 -> 13417 bytes
 Testing/TestData/MRIcrop-seg.label                 |   13 +
 Testing/TestData/tensor.itksnap                    |  338 +
 Testing/TestData/tensor_fa.nii.gz                  |  Bin 0 -> 92693 bytes
 Testing/TestData/tensor_rgb.nii.gz                 |  Bin 0 -> 87979 bytes
 Testing/TestData/tensor_t1.nii.gz                  |  Bin 0 -> 31807 bytes
 Testing/TestData/tensor_tr.nii.gz                  |  Bin 0 -> 90432 bytes
 Testing/TestImageWrapper.h                         |   97 -
 UserInterface/BasicComponents/ColorMapBox.cxx      |   96 -
 UserInterface/BasicComponents/ColorMapBox.h        |   67 -
 UserInterface/BasicComponents/ColorMapWidget.cxx   |  420 --
 UserInterface/BasicComponents/ColorMapWidget.h     |  112 -
 UserInterface/BasicComponents/FLTKCanvas.cxx       |  232 -
 UserInterface/BasicComponents/FLTKCanvas.h         |  113 -
 UserInterface/BasicComponents/FLTKEvent.h          |  101 -
 .../BasicComponents/FLTKWidgetActivationManager.h  |  324 -
 UserInterface/BasicComponents/FunctionPlot2D.cxx   |  178 -
 UserInterface/BasicComponents/FunctionPlot2D.h     |  141 -
 .../BasicComponents/FunctionPlot2DBox.cxx          |   81 -
 UserInterface/BasicComponents/FunctionPlot2DBox.h  |   64 -
 .../BasicComponents/IntensityCurveBox.cxx          |  633 --
 UserInterface/BasicComponents/IntensityCurveBox.h  |  181 -
 UserInterface/BasicComponents/InteractionMode.h    |  157 -
 .../BasicComponents/InteractionModeClient.cxx      |  104 -
 .../BasicComponents/InteractionModeClient.h        |   81 -
 UserInterface/BasicComponents/MetaDataTable.cxx    |  313 -
 UserInterface/BasicComponents/MetaDataTable.h      |   75 -
 .../BasicComponents/RecursiveInteractionMode.cxx   |  144 -
 .../BasicComponents/RecursiveInteractionMode.h     |   60 -
 .../BasicComponents/SNAPFormattedOutput.h          |   72 -
 UserInterface/BasicComponents/SNAPValueOutput.h    |   68 -
 .../BasicComponents/SnakeParametersPreviewBox.cxx  |  346 -
 .../BasicComponents/SnakeParametersPreviewBox.h    |  125 -
 .../SnakeParametersPreviewPipeline.cxx             |  628 --
 .../SnakeParametersPreviewPipeline.h               |  219 -
 UserInterface/BasicComponents/StatisticsTable.cxx  |  220 -
 UserInterface/BasicComponents/StatisticsTable.h    |   69 -
 UserInterface/Common/SNAPAppearanceSettings.cxx    |  422 --
 UserInterface/Common/SNAPAppearanceSettings.h      |  220 -
 UserInterface/Common/SNAPCommonUI.h                |   51 -
 UserInterface/ImageIOWizard/Artwork/dollAIR.gif    |  Bin 7856 -> 0 bytes
 UserInterface/ImageIOWizard/Artwork/dollARI.gif    |  Bin 8439 -> 0 bytes
 UserInterface/ImageIOWizard/Artwork/dollIAR.gif    |  Bin 7532 -> 0 bytes
 UserInterface/ImageIOWizard/Artwork/dollIRA.gif    |  Bin 7523 -> 0 bytes
 .../ImageIOWizard/Artwork/dollInvalid.gif          |  Bin 8361 -> 0 bytes
 UserInterface/ImageIOWizard/Artwork/dollRAI.gif    |  Bin 8427 -> 0 bytes
 UserInterface/ImageIOWizard/Artwork/dollRIA.gif    |  Bin 7721 -> 0 bytes
 UserInterface/ImageIOWizard/Artwork/x01.png        |  Bin 768 -> 0 bytes
 UserInterface/ImageIOWizard/Artwork/x02.png        |  Bin 759 -> 0 bytes
 UserInterface/ImageIOWizard/Artwork/y01.png        |  Bin 795 -> 0 bytes
 UserInterface/ImageIOWizard/Artwork/y02.png        |  Bin 809 -> 0 bytes
 UserInterface/ImageIOWizard/Artwork/z01.png        |  Bin 636 -> 0 bytes
 UserInterface/ImageIOWizard/Artwork/z02.png        |  Bin 618 -> 0 bytes
 UserInterface/ImageIOWizard/ImageIOWizard.fl       |  421 --
 UserInterface/ImageIOWizard/ImageIOWizardBase.h    |   69 -
 UserInterface/ImageIOWizard/ImageIOWizardLogic.cxx | 1194 ----
 UserInterface/ImageIOWizard/ImageIOWizardLogic.h   |  329 -
 .../ImageIOWizard/RestrictedImageIOWizardLogic.cxx |  165 -
 .../ImageIOWizard/RestrictedImageIOWizardLogic.h   |   85 -
 UserInterface/MainComponents/AppearanceDialogUI.fl |  518 --
 .../MainComponents/AppearanceDialogUIBase.h        |   64 -
 .../MainComponents/AppearanceDialogUILogic.cxx     |  683 --
 .../MainComponents/AppearanceDialogUILogic.h       |  117 -
 UserInterface/MainComponents/Artwork/crosshair.gif |  Bin 1039 -> 0 bytes
 .../MainComponents/Artwork/crosshair3D.gif         |  Bin 1053 -> 0 bytes
 .../MainComponents/Artwork/paintbrush.gif          |  Bin 1065 -> 0 bytes
 UserInterface/MainComponents/Artwork/poly.gif      |  Bin 1143 -> 0 bytes
 UserInterface/MainComponents/Artwork/rotate3d.gif  |  Bin 1148 -> 0 bytes
 UserInterface/MainComponents/Artwork/scalpel.gif   |  Bin 1108 -> 0 bytes
 UserInterface/MainComponents/Artwork/snake.gif     |  Bin 1260 -> 0 bytes
 UserInterface/MainComponents/Artwork/spray.gif     |  Bin 1245 -> 0 bytes
 UserInterface/MainComponents/Artwork/zoom.gif      |  Bin 1124 -> 0 bytes
 UserInterface/MainComponents/HelpViewer.fl         |   40 -
 UserInterface/MainComponents/HelpViewerBase.h      |   48 -
 UserInterface/MainComponents/HelpViewerLogic.cxx   |  188 -
 UserInterface/MainComponents/HelpViewerLogic.h     |   86 -
 UserInterface/MainComponents/LabelEditorUI.fl      |  214 -
 UserInterface/MainComponents/LabelEditorUIBase.h   |   61 -
 .../MainComponents/LabelEditorUILogic.cxx          |  644 --
 UserInterface/MainComponents/LabelEditorUILogic.h  |  103 -
 UserInterface/MainComponents/LayerInspectorUI.fl   |  412 --
 .../MainComponents/LayerInspectorUIBase.h          |   79 -
 .../MainComponents/LayerInspectorUILogic.cxx       | 1115 ----
 .../MainComponents/LayerInspectorUILogic.h         |  146 -
 UserInterface/MainComponents/PreprocessingUI.fl    |  163 -
 UserInterface/MainComponents/PreprocessingUIBase.h |   67 -
 .../MainComponents/PreprocessingUILogic.cxx        |  778 ---
 .../MainComponents/PreprocessingUILogic.h          |  149 -
 UserInterface/MainComponents/ReorientImageUI.fl    |  219 -
 UserInterface/MainComponents/ReorientImageUIBase.h |   52 -
 .../MainComponents/ReorientImageUILogic.cxx        |  320 -
 .../MainComponents/ReorientImageUILogic.h          |   83 -
 UserInterface/MainComponents/ResizeRegionDialog.fl |  251 -
 .../MainComponents/ResizeRegionDialogBase.h        |   47 -
 .../MainComponents/ResizeRegionDialogLogic.cxx     |  182 -
 .../MainComponents/ResizeRegionDialogLogic.h       |   76 -
 .../MainComponents/RestoreSettingsDialog.fl        |   70 -
 .../MainComponents/RestoreSettingsDialogBase.h     |   46 -
 .../MainComponents/RestoreSettingsDialogLogic.cxx  |  159 -
 .../MainComponents/RestoreSettingsDialogLogic.h    |  109 -
 UserInterface/MainComponents/SimpleFileDialog.fl   |   41 -
 .../MainComponents/SimpleFileDialogBase.h          |   48 -
 .../MainComponents/SimpleFileDialogLogic.cxx       |  203 -
 .../MainComponents/SimpleFileDialogLogic.h         |  155 -
 UserInterface/MainComponents/SnakeParametersUI.fl  |  435 --
 .../MainComponents/SnakeParametersUIBase.h         |   77 -
 .../MainComponents/SnakeParametersUILogic.cxx      |  751 ---
 .../MainComponents/SnakeParametersUILogic.h        |  165 -
 UserInterface/MainComponents/UserInterface.fl      | 1942 ------
 UserInterface/MainComponents/UserInterfaceBase.h   |  330 -
 .../MainComponents/UserInterfaceLogic.cxx          | 7030 --------------------
 UserInterface/MainComponents/UserInterfaceLogic.h  | 1543 -----
 UserInterface/MeshIOWizard/MeshIOWizardUI.fl       |  128 -
 UserInterface/MeshIOWizard/MeshIOWizardUIBase.h    |   61 -
 UserInterface/MeshIOWizard/MeshIOWizardUILogic.cxx |  426 --
 UserInterface/MeshIOWizard/MeshIOWizardUILogic.h   |  133 -
 UserInterface/SNAPMain.cxx                         |  777 ---
 .../SliceWindow/AnnotationInteractionMode.cxx      |  240 -
 .../SliceWindow/AnnotationInteractionMode.h        |   87 -
 .../SliceWindow/BubblesInteractionMode.cxx         |  191 -
 UserInterface/SliceWindow/BubblesInteractionMode.h |   58 -
 .../SliceWindow/CrosshairsInteractionMode.cxx      |  431 --
 .../SliceWindow/CrosshairsInteractionMode.h        |   99 -
 UserInterface/SliceWindow/GLToPNG.cxx              |  100 -
 UserInterface/SliceWindow/GLToPNG.h                |   60 -
 UserInterface/SliceWindow/GenericSliceWindow.cxx   |  950 ---
 UserInterface/SliceWindow/GenericSliceWindow.h     |  361 -
 UserInterface/SliceWindow/IRISSliceWindow.cxx      |  300 -
 UserInterface/SliceWindow/IRISSliceWindow.h        |  185 -
 UserInterface/SliceWindow/OpenGLSliceTexture.cxx   |  238 -
 UserInterface/SliceWindow/OpenGLSliceTexture.h     |  150 -
 .../SliceWindow/PaintbrushInteractionMode.cxx      |  760 ---
 .../SliceWindow/PaintbrushInteractionMode.h        |  101 -
 UserInterface/SliceWindow/PolygonDrawing.cxx       | 1399 ----
 UserInterface/SliceWindow/PolygonDrawing.h         |  246 -
 .../SliceWindow/PolygonInteractionMode.cxx         |  113 -
 UserInterface/SliceWindow/PolygonInteractionMode.h |  108 -
 UserInterface/SliceWindow/PolygonScanConvert.cxx   |  177 -
 UserInterface/SliceWindow/PolygonScanConvert.h     |   94 -
 .../SliceWindow/PopupButtonInteractionMode.cxx     |  120 -
 .../SliceWindow/PopupButtonInteractionMode.h       |   56 -
 .../SliceWindow/RegionInteractionMode.cxx          |  350 -
 UserInterface/SliceWindow/RegionInteractionMode.h  |   94 -
 UserInterface/SliceWindow/SNAPSliceWindow.cxx      |  179 -
 UserInterface/SliceWindow/SNAPSliceWindow.h        |   85 -
 .../SliceWindow/SliceWindowCoordinator.cxx         |  239 -
 UserInterface/SliceWindow/SliceWindowCoordinator.h |  141 -
 .../SliceWindow/ThumbnailInteractionMode.cxx       |  124 -
 .../SliceWindow/ThumbnailInteractionMode.h         |   64 -
 .../SliceWindow/ZoomPanInteractionMode.cxx         |  137 -
 UserInterface/SliceWindow/ZoomPanInteractionMode.h |   67 -
 UserInterface/Window3D/Trackball.h                 |  129 -
 UserInterface/Window3D/Window3D.cxx                | 1551 -----
 UserInterface/Window3D/Window3D.h                  |  365 -
 .../FLTK/Fl_Native_File_Chooser/.TAR_RELEASE.sh    |   53 -
 Utilities/FLTK/Fl_Native_File_Chooser/CHANGES      |  166 -
 .../FLTK/Fl_Native_File_Chooser/CMakeLists.txt     |    3 -
 Utilities/FLTK/Fl_Native_File_Chooser/COPYING      |  529 --
 Utilities/FLTK/Fl_Native_File_Chooser/CREDITS      |   13 -
 .../FL/Fl_Native_File_Chooser.H                    |   40 -
 .../FL/Fl_Native_File_Chooser_FLTK.H               |   98 -
 .../FL/Fl_Native_File_Chooser_MAC.H                |  138 -
 .../FL/Fl_Native_File_Chooser_WIN32.H              |  108 -
 .../Fl_Native_File_Chooser.cxx                     |   36 -
 .../Fl_Native_File_Chooser_FLTK.cxx                |  374 --
 .../Fl_Native_File_Chooser_MAC.cxx                 |  867 ---
 .../Fl_Native_File_Chooser_WIN32.cxx               |  806 ---
 Utilities/FLTK/Fl_Native_File_Chooser/Makefile     |   68 -
 .../FLTK/Fl_Native_File_Chooser/Makefile-fltk1     |   94 -
 .../Makefile-fltk1.MICROSOFT                       |   65 -
 .../FLTK/Fl_Native_File_Chooser/Makefile-fltk2     |   93 -
 .../Makefile-fltk2.MICROSOFT                       |   62 -
 .../FLTK/Fl_Native_File_Chooser/Makefile.MICROSOFT |   45 -
 Utilities/FLTK/Fl_Native_File_Chooser/README.txt   |  119 -
 Utilities/FLTK/Fl_Native_File_Chooser/TODO         |  318 -
 Utilities/FLTK/Fl_Native_File_Chooser/common.cxx   |   78 -
 .../documentation/Fl_Native_File_Chooser.html      |  361 -
 .../documentation/NativeFileChooser.html           |  361 -
 .../documentation/build-output-FEDORA3.txt         |   30 -
 .../documentation/build-output-MAC.txt             |   26 -
 .../documentation/build-output-WIN32.txt           |   86 -
 .../documentation/how-to-use.html                  |   69 -
 .../documentation/images/native-small.png          |  Bin 50588 -> 0 bytes
 .../documentation/index.html                       |   34 -
 .../fltk/NativeFileChooser.h                       |   40 -
 .../fltk/NativeFileChooser_FLTK.h                  |  100 -
 .../fltk/NativeFileChooser_MAC.h                   |  142 -
 .../fltk/NativeFileChooser_WIN32.h                 |  113 -
 Utilities/FLTK/Fl_Native_File_Chooser/make.bat     |    2 -
 .../reference/README-natev-mods.txt                |   71 -
 .../reference/REFERENCE-MAC.txt                    |   30 -
 .../reference/erco-merge-trick.cxx                 |   49 -
 .../Fl_Native_File_Chooser/simple-app-fltk2.cxx    |   78 -
 .../simple-app.app/Contents/Info.plist             |   15 -
 .../FLTK/Fl_Native_File_Chooser/simple-app.cxx     |   76 -
 .../Fl_Native_File_Chooser/test-browser-fltk2.cxx  |  299 -
 .../test-browser.app/Contents/Info.plist           |   15 -
 .../FLTK/Fl_Native_File_Chooser/test-browser.cxx   |  304 -
 Utilities/FLTK/Fl_Table/CHANGES                    |  289 -
 Utilities/FLTK/Fl_Table/CMakeLists.txt             |    3 -
 Utilities/FLTK/Fl_Table/COPYING                    |  528 --
 Utilities/FLTK/Fl_Table/CREDITS                    |   27 -
 Utilities/FLTK/Fl_Table/FL/Fl_Table.H              |  451 --
 Utilities/FLTK/Fl_Table/FL/Fl_Table_Row.H          |  150 -
 Utilities/FLTK/Fl_Table/Fl_Table.cxx               | 1218 ----
 Utilities/FLTK/Fl_Table/Fl_Table_Row.cxx           |  317 -
 Utilities/FLTK/Fl_Table/README                     |  106 -
 Utilities/FLTK/Fl_Table/TODO                       |  120 -
 Utilities/MacOS/BundleResources/Info.plist         |   23 +-
 Utilities/MacOS/BundleResources/README.txt         |   19 +
 Utilities/MacOS/BundleResources/background.png     |  Bin 0 -> 16258 bytes
 Utilities/MacOS/BundleResources/dsstore.bin        |  Bin 0 -> 15364 bytes
 Utilities/MacOS/BundleResources/itksnap            |   43 +
 Utilities/Win32/itksnap.rc                         |    1 +
 Utilities/Win32/snaplogo.ico                       |  Bin 0 -> 59222 bytes
 Utilities/licensetemplate.txt                      |   25 +
 944 files changed, 104375 insertions(+), 60134 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..252540c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+# VIM swap files
+.*.sw?
+*.un~
+
+# MACOS files
+.DS_Store*
+Thumbs.db
+
+# Backup files
+*.bak
+
+# Qt Creator stuff
+CMakeLists.txt.user*
+CTestConfig.cmake.user*
+*.autosave
diff --git a/CMake/CustomBuildSettings.cmake b/CMake/CustomBuildSettings.cmake
deleted file mode 100644
index c6238a9..0000000
--- a/CMake/CustomBuildSettings.cmake
+++ /dev/null
@@ -1,38 +0,0 @@
-SITE_NAME(SNAP_BUILD_MACHINE)
-
-SET(INSTALL_LIBS lib/snap-${SNAP_VERSION_FULL})
-
-IF(SNAP_BUILD_MACHINE STREQUAL "pauly-laptop" AND NOT WIN32)
-  INSTALL(
-    FILES /usr/lib/libstdc++.so.6.0.9 
-    DESTINATION ${INSTALL_LIBS}
-    COMPONENT RUNTIME
-    RENAME libstdc++.so.6)
-  INSTALL(
-    FILES /lib/libgcc_s.so.1
-    DESTINATION ${INSTALL_LIBS}
-    COMPONENT RUNTIME)
-  INSTALL(
-    FILES /usr/lib/libGLU.so.1.3.070001
-    DESTINATION ${INSTALL_LIBS}
-    RENAME libGLU.so.1
-    COMPONENT RUNTIME)
-ENDIF(SNAP_BUILD_MACHINE STREQUAL "pauly-laptop" AND NOT WIN32)
-
-IF(SNAP_BUILD_MACHINE STREQUAL "mingus.uphs.upenn.edu" AND NOT WIN32)
-  INSTALL(
-    FILES /usr/lib/libstdc++.so.5.0.3 
-    DESTINATION ${INSTALL_LIBS}
-    COMPONENT RUNTIME
-    RENAME libstdc++.so.5)
-  INSTALL(
-    FILES /lib/libgcc_s-3.2.2-20030225.so.1
-    DESTINATION ${INSTALL_LIBS}
-    RENAME libgcc_s.so.1
-    COMPONENT RUNTIME)
-  INSTALL(
-    FILES /usr/X11R6/lib/libGLU.so.1.3
-    DESTINATION ${INSTALL_LIBS}
-    RENAME libGLU.so.1
-    COMPONENT RUNTIME)
-ENDIF(SNAP_BUILD_MACHINE STREQUAL "mingus.uphs.upenn.edu" AND NOT WIN32)
diff --git a/CMake/DeployQt5.cmake b/CMake/DeployQt5.cmake
new file mode 100644
index 0000000..d015b90
--- /dev/null
+++ b/CMake/DeployQt5.cmake
@@ -0,0 +1,339 @@
+#.rst:
+# DeployQt5
+# ---------
+#
+# Functions to help assemble a standalone Qt5 executable.
+#
+# A collection of CMake utility functions useful for deploying Qt5
+# executables.
+#
+# The following functions are provided by this module:
+#
+# ::
+#
+#    write_qt5_conf
+#    resolve_qt5_paths
+#    fixup_qt5_executable
+#    install_qt5_plugin_path
+#    install_qt5_plugin
+#    install_qt5_executable
+#
+# Requires CMake 2.8.9 or greater because Qt 5 does.
+# Also depends on BundleUtilities.cmake.
+#
+# ::
+#
+#   WRITE_QT5_CONF(<qt_conf_dir> <qt_conf_contents>)
+#
+# Writes a qt.conf file with the <qt_conf_contents> into <qt_conf_dir>.
+#
+# ::
+#
+#   RESOLVE_QT5_PATHS(<paths_var> [<executable_path>])
+#
+# Loop through <paths_var> list and if any don't exist resolve them
+# relative to the <executable_path> (if supplied) or the
+# CMAKE_INSTALL_PREFIX.
+#
+# ::
+#
+#   FIXUP_QT5_EXECUTABLE(<executable> [<qtplugins> <libs> <dirs> <plugins_dir> <request_qt_conf>])
+#
+# Copies Qt plugins, writes a Qt configuration file (if needed) and
+# fixes up a Qt5 executable using BundleUtilities so it is standalone
+# and can be drag-and-drop copied to another machine as long as all of
+# the system libraries are compatible.
+#
+# <executable> should point to the executable to be fixed-up.
+#
+# <qtplugins> should contain a list of the names or paths of any Qt
+# plugins to be installed.
+#
+# <libs> will be passed to BundleUtilities and should be a list of any
+# already installed plugins, libraries or executables to also be
+# fixed-up.
+#
+# <dirs> will be passed to BundleUtilities and should contain and
+# directories to be searched to find library dependencies.
+#
+# <plugins_dir> allows an custom plugins directory to be used.
+#
+# <request_qt_conf> will force a qt.conf file to be written even if not
+# needed.
+#
+# ::
+#
+#   INSTALL_QT5_PLUGIN_PATH(plugin executable copy installed_plugin_path_var <plugins_dir> <component> <configurations>)
+#
+# Install (or copy) a resolved <plugin> to the default plugins directory
+# (or <plugins_dir>) relative to <executable> and store the result in
+# <installed_plugin_path_var>.
+#
+# If <copy> is set to TRUE then the plugins will be copied rather than
+# installed.  This is to allow this module to be used at CMake time
+# rather than install time.
+#
+# If <component> is set then anything installed will use this COMPONENT.
+#
+# ::
+#
+#   INSTALL_QT5_PLUGIN(plugin executable copy installed_plugin_path_var <plugins_dir> <component>)
+#
+# Install (or copy) an unresolved <plugin> to the default plugins
+# directory (or <plugins_dir>) relative to <executable> and store the
+# result in <installed_plugin_path_var>.  See documentation of
+# INSTALL_QT5_PLUGIN_PATH.
+#
+# ::
+#
+#   INSTALL_QT5_EXECUTABLE(<executable> [<qtplugins> <libs> <dirs> <plugins_dir> <request_qt_conf> <component>])
+#
+# Installs Qt plugins, writes a Qt configuration file (if needed) and
+# fixes up a Qt5 executable using BundleUtilities so it is standalone
+# and can be drag-and-drop copied to another machine as long as all of
+# the system libraries are compatible.  The executable will be fixed-up
+# at install time.  <component> is the COMPONENT used for bundle fixup
+# and plugin installation.  See documentation of FIXUP_QT5_BUNDLE.
+
+#=============================================================================
+# Copyright 2011 Mike McQuaid <mike at mikemcquaid.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# The functions defined in this file depend on the fixup_bundle function
+# (and others) found in BundleUtilities.cmake
+
+include(BundleUtilities)
+set(DeployQt5_cmake_dir "${CMAKE_CURRENT_LIST_DIR}")
+set(DeployQt5_apple_plugins_dir "PlugIns")
+
+function(write_qt5_conf qt_conf_dir qt_conf_contents)
+  set(qt_conf_path "${qt_conf_dir}/qt.conf")
+  message(STATUS "Writing ${qt_conf_path}")
+  file(WRITE "${qt_conf_path}" "${qt_conf_contents}")
+endfunction()
+
+function(resolve_qt5_paths paths_var)
+  set(executable_path ${ARGV1})
+
+  set(paths_resolved)
+  foreach(path ${${paths_var}})
+    if(EXISTS "${path}")
+      list(APPEND paths_resolved "${path}")
+    else()
+      if(${executable_path})
+        list(APPEND paths_resolved "${executable_path}/${path}")
+      else()
+        list(APPEND paths_resolved "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${path}")
+      endif()
+    endif()
+  endforeach()
+  set(${paths_var} ${paths_resolved} PARENT_SCOPE)
+endfunction()
+
+function(fixup_qt5_executable executable)
+  set(qtplugins ${ARGV1})
+  set(libs ${ARGV2})
+  set(dirs ${ARGV3})
+  set(plugins_dir ${ARGV4})
+  set(request_qt_conf ${ARGV5})
+
+  message(STATUS "fixup_qt5_executable")
+  message(STATUS "  executable='${executable}'")
+  message(STATUS "  qtplugins='${qtplugins}'")
+  message(STATUS "  libs='${libs}'")
+  message(STATUS "  dirs='${dirs}'")
+  message(STATUS "  plugins_dir='${plugins_dir}'")
+  message(STATUS "  request_qt_conf='${request_qt_conf}'")
+
+  if(QT_LIBRARY_DIR)
+    list(APPEND dirs "${QT_LIBRARY_DIR}")
+  endif()
+  if(QT_BINARY_DIR)
+    list(APPEND dirs "${QT_BINARY_DIR}")
+  endif()
+
+  if(APPLE)
+    set(qt_conf_dir "${executable}/Contents/Resources")
+    set(executable_path "${executable}")
+    set(write_qt_conf TRUE)
+    if(NOT plugins_dir)
+      set(plugins_dir "${DeployQt5_apple_plugins_dir}")
+    endif()
+  else()
+    get_filename_component(executable_path "${executable}" PATH)
+    if(NOT executable_path)
+      set(executable_path ".")
+    endif()
+    set(qt_conf_dir "${executable_path}")
+    set(write_qt_conf ${request_qt_conf})
+  endif()
+
+  foreach(plugin ${qtplugins})
+    set(installed_plugin_path "")
+    install_qt5_plugin("${plugin}" "${executable}" 1 installed_plugin_path)
+    list(APPEND libs ${installed_plugin_path})
+  endforeach()
+
+  foreach(lib ${libs})
+    if(NOT EXISTS "${lib}")
+      message(FATAL_ERROR "Library does not exist: ${lib}")
+    endif()
+  endforeach()
+
+  resolve_qt5_paths(libs "${executable_path}")
+
+  if(write_qt_conf)
+    set(qt_conf_contents "[Paths]\nPlugins = ${plugins_dir}")
+    write_qt5_conf("${qt_conf_dir}" "${qt_conf_contents}")
+  endif()
+
+  fixup_bundle("${executable}" "${libs}" "${dirs}")
+endfunction()
+
+function(install_qt5_plugin_path plugin executable copy installed_plugin_path_var)
+  set(plugins_dir ${ARGV4})
+  set(component ${ARGV5})
+  set(configurations ${ARGV6})
+  if(EXISTS "${plugin}")
+    if(APPLE)
+      if(NOT plugins_dir)
+        set(plugins_dir "${DeployQt5_apple_plugins_dir}")
+      endif()
+      set(plugins_path "${executable}/Contents/${plugins_dir}")
+    else()
+      get_filename_component(plugins_path "${executable}" PATH)
+      if(NOT plugins_path)
+        set(plugins_path ".")
+      endif()
+      if(plugins_dir)
+        set(plugins_path "${plugins_path}/${plugins_dir}")
+      endif()
+    endif()
+
+    set(plugin_group "")
+
+    get_filename_component(plugin_path "${plugin}" PATH)
+    get_filename_component(plugin_parent_path "${plugin_path}" PATH)
+    get_filename_component(plugin_parent_dir_name "${plugin_parent_path}" NAME)
+    get_filename_component(plugin_name "${plugin}" NAME)
+    string(TOLOWER "${plugin_parent_dir_name}" plugin_parent_dir_name)
+
+    if("${plugin_parent_dir_name}" STREQUAL "plugins")
+      get_filename_component(plugin_group "${plugin_path}" NAME)
+      set(${plugin_group_var} "${plugin_group}")
+    endif()
+    set(plugins_path "${plugins_path}/${plugin_group}")
+
+    if(${copy})
+      file(MAKE_DIRECTORY "${plugins_path}")
+      file(COPY "${plugin}" DESTINATION "${plugins_path}")
+    else()
+      if(configurations AND (CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE))
+        set(configurations CONFIGURATIONS ${configurations})
+      else()
+        unset(configurations)
+      endif()
+      install(FILES "${plugin}" DESTINATION "${plugins_path}" ${configurations} ${component})
+    endif()
+    set(${installed_plugin_path_var} "${plugins_path}/${plugin_name}" PARENT_SCOPE)
+  endif()
+endfunction()
+
+function(install_qt5_plugin plugin executable copy installed_plugin_path_var)
+  set(plugins_dir ${ARGV4})
+  set(component ${ARGV5})
+  if(EXISTS "${plugin}")
+    install_qt5_plugin_path("${plugin}" "${executable}" "${copy}" "${installed_plugin_path_var}" "${plugins_dir}" "${component}")
+  else()
+    string(TOUPPER "QT_${plugin}_PLUGIN" plugin_var)
+    set(plugin_release_var "${plugin_var}_RELEASE")
+    set(plugin_debug_var "${plugin_var}_DEBUG")
+    set(plugin_release "${${plugin_release_var}}")
+    set(plugin_debug "${${plugin_debug_var}}")
+    if(DEFINED "${plugin_release_var}" AND DEFINED "${plugin_debug_var}" AND NOT EXISTS "${plugin_release}" AND NOT EXISTS "${plugin_debug}")
+      message(WARNING "Qt plugin \"${plugin}\" not recognized or found.")
+    endif()
+    if(NOT EXISTS "${${plugin_debug_var}}")
+      set(plugin_debug "${plugin_release}")
+    endif()
+
+
+    if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE)
+      install_qt5_plugin_path("${plugin_release}" "${executable}" "${copy}" "${installed_plugin_path_var}_release" "${plugins_dir}" "${component}" "Release|RelWithDebInfo|MinSizeRel")
+      install_qt5_plugin_path("${plugin_debug}" "${executable}" "${copy}" "${installed_plugin_path_var}_debug" "${plugins_dir}" "${component}" "Debug")
+
+      if(CMAKE_BUILD_TYPE MATCHES "^Debug$")
+        set(${installed_plugin_path_var} ${${installed_plugin_path_var}_debug})
+      else()
+        set(${installed_plugin_path_var} ${${installed_plugin_path_var}_release})
+      endif()
+    else()
+      install_qt5_plugin_path("${plugin_release}" "${executable}" "${copy}" "${installed_plugin_path_var}" "${plugins_dir}" "${component}")
+    endif()
+  endif()
+  set(${installed_plugin_path_var} ${${installed_plugin_path_var}} PARENT_SCOPE)
+endfunction()
+
+function(install_qt5_executable executable)
+  set(qtplugins ${ARGV1})
+  set(libs ${ARGV2})
+  set(dirs ${ARGV3})
+  set(plugins_dir ${ARGV4})
+  set(request_qt_conf ${ARGV5})
+  set(component ${ARGV6})
+  if(QT_LIBRARY_DIR)
+    list(APPEND dirs "${QT_LIBRARY_DIR}")
+  endif()
+  if(QT_BINARY_DIR)
+    list(APPEND dirs "${QT_BINARY_DIR}")
+  endif()
+  if(component)
+    set(component COMPONENT ${component})
+  else()
+    unset(component)
+  endif()
+
+  get_filename_component(executable_absolute "${executable}" ABSOLUTE)
+  if(EXISTS "${QT_QTCORE_LIBRARY_RELEASE}")
+    gp_file_type("${executable_absolute}" "${QT_QTCORE_LIBRARY_RELEASE}" qtcore_type)
+  elseif(EXISTS "${QT_QTCORE_LIBRARY_DEBUG}")
+    gp_file_type("${executable_absolute}" "${QT_QTCORE_LIBRARY_DEBUG}" qtcore_type)
+  endif()
+  if(qtcore_type STREQUAL "system")
+    set(qt_plugins_dir "")
+  endif()
+
+  if(QT_IS_STATIC)
+    message(WARNING "Qt built statically: not installing plugins.")
+  else()
+    if(APPLE)
+      get_property(loc TARGET Qt5::QCocoaIntegrationPlugin
+        PROPERTY LOCATION_RELEASE)
+      install_qt5_plugin("${loc}" "${executable}" 0 installed_plugin_paths "PlugIns" "${component}")
+      list(APPEND libs ${installed_plugin_paths})
+    endif()
+    foreach(plugin ${qtplugins})
+      set(installed_plugin_paths "")
+      install_qt5_plugin("${plugin}" "${executable}" 0 installed_plugin_paths "${plugins_dir}" "${component}")
+      list(APPEND libs ${installed_plugin_paths})
+    endforeach()
+  endif()
+
+  resolve_qt5_paths(libs "")
+
+  install(CODE
+  "include(\"${DeployQt5_cmake_dir}/DeployQt5.cmake\")
+  set(BU_CHMOD_BUNDLE_ITEMS TRUE)
+  FIXUP_QT5_EXECUTABLE(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${executable}\" \"\" \"${libs}\" \"${dirs}\" \"${plugins_dir}\" \"${request_qt_conf}\")"
+    ${component}
+    )
+endfunction()
diff --git a/CMake/find_fltk_13.cmake b/CMake/find_fltk_13.cmake
deleted file mode 100644
index 10f6159..0000000
--- a/CMake/find_fltk_13.cmake
+++ /dev/null
@@ -1,158 +0,0 @@
-# This script sets up FLTK 1.3 because FindFLTK does not work very well
-
-# The name of the FLTK library will vary depending on the system
-# Options are libfltk_forms.a fltkforms.lib and fltkformsd.lib
-IF(MSVC)
-  SET(PREF "")
-  IF(CMAKE_BUILD_TYPE MATCHES "Debug")
-    SET(SUFF "d")
-  ELSE(CMAKE_BUILD_TYPE MATCHES "Debug")
-    SET(SUFF "")
-  ENDIF(CMAKE_BUILD_TYPE MATCHES "Debug")
-ELSE(MSVC)
-  SET(PREF "_")
-  SET(SUFF "")
-ENDIF(MSVC)
-
-# What is the target name of the fltk library
-SET(BASETARG "fltk${SUFF}")
-
-# Search for the base library
-FIND_LIBRARY(FLTK_BASE_LIBRARY NAMES ${BASETARG} PATHS "/usr/lib" "/usr/local/lib")
-
-IF(FLTK_BASE_LIBRARY)
-  MESSAGE(STATUS "FLTK base: ${FLTK_BASE_LIBRARY}")
-
-  # Search for the other libraries
-  GET_FILENAME_COMPONENT(FLTK_LIB_DIR ${FLTK_BASE_LIBRARY} PATH)
-  MESSAGE(STATUS "FLTK lib dir: ${FLTK_LIB_DIR}")
-  MESSAGE(STATUS "FLTK target: fltk${PREF}forms${SUFF}")
-  FIND_LIBRARY(FLTK_FORMS_LIBRARY NAMES "fltk${PREF}forms${SUFF}" PATHS ${FLTK_LIB_DIR})
-  FIND_LIBRARY(FLTK_GL_LIBRARY NAMES "fltk${PREF}gl${SUFF}" PATHS ${FLTK_LIB_DIR})
-  FIND_LIBRARY(FLTK_IMAGES_LIBRARY NAMES "fltk${PREF}images${SUFF}" PATHS ${FLTK_LIB_DIR})
-
-  # Search for the fluid executable. It can be in a couple of places.
-  # 1. In the bin directory, same level as lib
-  # 2. In the fluid directiry, same level as lib (if built 'in-place')
-  GET_FILENAME_COMPONENT(FLTK_ROOT_DIR ${FLTK_LIB_DIR} PATH)
-  FIND_PROGRAM(FLTK_FLUID_EXECUTABLE 
-    NAMES "fluid${SUFF}"
-    PATHS "${FLTK_ROOT_DIR}/bin" "${FLTK_ROOT_DIR}/fluid")
-
-  # Search for the FLTK include directory. Again, two places to look
-  # 1. In the include directory
-  # 2. In the root directory
-  FIND_PATH(FLTK_INCLUDE_DIR
-    NAMES "FL/Fl.H"
-    PATHS "${FLTK_ROOT_DIR}/include" "${FLTK_ROOT_DIR}")
-  MESSAGE(STATUS "FLTK include directory: ${FLTK_INCLUDE_DIR}")
-
-  # For now, we let the user decide about the additional image libraries
-  # TODO: figure this out from fltk-config file
-  OPTION(SNAP_USE_FLTK_PNG "Should we link with the FLTK png library?" OFF)
-  OPTION(SNAP_USE_FLTK_JPEG "Should we link with the FLTK jpeg library?" OFF)
-  OPTION(SNAP_USE_FLTK_ZLIB "Should we link with the FLTK zlib library?" OFF)
-
-  # Look for these libs if specified
-  IF(SNAP_USE_FLTK_PNG)
-    FIND_LIBRARY(FLTK_PNG_LIBRARY NAMES "fltk${PREF}png${SUFF}" PATHS ${FLTK_LIB_DIR})
-    SET(FLTK_IMAGES_LIBS ${FLTK_IMAGES_LIBS} ${FLTK_PNG_LIBRARY})
-    IF(FLTK_PNG_LIBRARY)
-      SET(FLTK_PNG_LIBRARY_OK ON)
-    ELSE(FLTK_PNG_LIBRARY)
-      SET(FLTK_PNG_LIBRARY_OK OFF)
-    ENDIF(FLTK_PNG_LIBRARY)
-  ELSE(SNAP_USE_FLTK_PNG)
-    FIND_PACKAGE(PNG REQUIRED)
-    IF(PNG_FOUND)
-      SET(FLTK_PNG_LIBRARY_OK ON)
-      SET(FLTK_IMAGES_LIBS ${FLTK_IMAGES_LIBS} ${PNG_LIBRARY})
-    ELSE(PNG_FOUND)
-      SET(FLTK_PNG_LIBRARY_OK OFF)
-    ENDIF(PNG_FOUND)
-  ENDIF(SNAP_USE_FLTK_PNG)
-
-  IF(SNAP_USE_FLTK_JPEG)
-    FIND_LIBRARY(FLTK_JPEG_LIBRARY NAMES "fltk${PREF}jpeg${SUFF}" PATHS ${FLTK_LIB_DIR})
-    SET(FLTK_IMAGES_LIBS ${FLTK_IMAGES_LIBS} ${FLTK_JPEG_LIBRARY})
-    IF(FLTK_JPEG_LIBRARY)
-      SET(FLTK_JPEG_LIBRARY_OK ON)
-    ELSE(FLTK_JPEG_LIBRARY)
-      SET(FLTK_JPEG_LIBRARY_OK OFF)
-    ENDIF(FLTK_JPEG_LIBRARY)
-  ELSE(SNAP_USE_FLTK_JPEG)
-    FIND_PACKAGE(JPEG REQUIRED)
-    IF(JPEG_FOUND)
-      SET(FLTK_JPEG_LIBRARY_OK ON)
-      SET(FLTK_IMAGES_LIBS ${FLTK_IMAGES_LIBS} ${JPEG_LIBRARY})
-    ELSE(JPEG_FOUND)
-      SET(FLTK_JPEG_LIBRARY_OK OFF)
-    ENDIF(JPEG_FOUND)
-  ENDIF(SNAP_USE_FLTK_JPEG)
-
-  IF(SNAP_USE_FLTK_ZLIB)
-    FIND_LIBRARY(FLTK_ZLIB_LIBRARY NAMES "fltk${PREF}z${SUFF}" "zlib${SUFF}" PATHS ${FLTK_LIB_DIR})
-    SET(FLTK_IMAGES_LIBS ${FLTK_IMAGES_LIBS} ${FLTK_ZLIB_LIBRARY})
-    IF(FLTK_ZLIB_LIBRARY)
-      SET(FLTK_ZLIB_LIBRARY_OK ON)
-    ELSE(FLTK_ZLIB_LIBRARY)
-      SET(FLTK_ZLIB_LIBRARY_OK OFF)
-    ENDIF(FLTK_ZLIB_LIBRARY)
-  ELSE(SNAP_USE_FLTK_ZLIB)
-    FIND_PACKAGE(ZLIB REQUIRED)
-    IF(ZLIB_FOUND)
-      SET(FLTK_ZLIB_LIBRARY_OK ON)
-      SET(FLTK_IMAGES_LIBS ${FLTK_IMAGES_LIBS} ${ZLIB_LIBRARY})
-    ELSE(ZLIB_FOUND)
-      SET(FLTK_ZLIB_LIBRARY_OK OFF)
-    ENDIF(ZLIB_FOUND)
-  ENDIF(SNAP_USE_FLTK_ZLIB)
-
-ENDIF(FLTK_BASE_LIBRARY)
-
-# Check if all components have been found
-IF(FLTK_BASE_LIBRARY AND FLTK_FORMS_LIBRARY AND FLTK_GL_LIBRARY AND FLTK_IMAGES_LIBRARY
-    AND FLTK_INCLUDE_DIR AND FLTK_FLUID_EXECUTABLE 
-    AND FLTK_PNG_LIBRARY_OK AND FLTK_ZLIB_LIBRARY_OK AND FLTK_JPEG_LIBRARY_OK)
-  SET(FLTK_FOUND ON)
-ELSE(FLTK_BASE_LIBRARY AND FLTK_FORMS_LIBRARY AND FLTK_GL_LIBRARY AND FLTK_IMAGES_LIBRARY
-    AND FLTK_INCLUDE_DIR AND FLTK_FLUID_EXECUTABLE 
-    AND FLTK_PNG_LIBRARY_OK AND FLTK_ZLIB_LIBRARY_OK AND FLTK_JPEG_LIBRARY_OK)
-  SET(FLTK_FOUND OFF)
-ENDIF(FLTK_BASE_LIBRARY AND FLTK_FORMS_LIBRARY AND FLTK_GL_LIBRARY AND FLTK_IMAGES_LIBRARY
-    AND FLTK_INCLUDE_DIR AND FLTK_FLUID_EXECUTABLE 
-    AND FLTK_PNG_LIBRARY_OK AND FLTK_ZLIB_LIBRARY_OK AND FLTK_JPEG_LIBRARY_OK)
-
-# Taken from findfltk.cmake
-#  Platform dependent libraries required by FLTK
-IF(WIN32)
-  IF(NOT CYGWIN)
-    IF(BORLAND)
-      SET( FLTK_PLATFORM_DEPENDENT_LIBS import32 )
-    ELSE(BORLAND)
-      SET( FLTK_PLATFORM_DEPENDENT_LIBS wsock32 comctl32 )
-    ENDIF(BORLAND)
-  ENDIF(NOT CYGWIN)
-ENDIF(WIN32)
-
-IF(UNIX)
-  INCLUDE(${CMAKE_ROOT}/Modules/FindX11.cmake)
-  FIND_LIBRARY(FLTK_MATH_LIBRARY m)
-  SET( FLTK_PLATFORM_DEPENDENT_LIBS ${X11_LIBRARIES} ${X11_Xft_LIB} ${X11_Xinerama_LIB} ${FLTK_MATH_LIBRARY})
-ENDIF(UNIX)
-
-IF(APPLE)
-  SET( FLTK_PLATFORM_DEPENDENT_LIBS  "-framework Carbon -framework Cocoa -framework ApplicationServices -framework AudioToolbox -lz")
-ENDIF(APPLE)
-
-IF(CYGWIN)
-  FIND_LIBRARY(FLTK_MATH_LIBRARY m)
-  SET( FLTK_PLATFORM_DEPENDENT_LIBS ole32 uuid comctl32 wsock32 supc++ ${FLTK_MATH_LIBRARY} -lgdi32)
-ENDIF(CYGWIN)
-
-# Set the FLTK libraries
-SET(FLTK_LIBRARIES
-  ${FLTK_BASE_LIBRARY} ${FLTK_FORMS_LIBRARY} ${FLTK_IMAGES_LIBRARY} ${FLTK_GL_LIBRARY}
-  ${FLTK_IMAGES_LIBS} ${FLTK_PLATFORM_DEPENDENT_LIBS})
-
-SET(FLTK_INCLUDE_PATH ${FLTK_INCLUDE_DIR})
diff --git a/CMake/rpavlik/GetGitRevisionDescription.cmake b/CMake/rpavlik/GetGitRevisionDescription.cmake
new file mode 100644
index 0000000..e5e991a
--- /dev/null
+++ b/CMake/rpavlik/GetGitRevisionDescription.cmake
@@ -0,0 +1,130 @@
+# - Returns a version string from Git
+#
+# These functions force a re-configure on each git commit so that you can
+# trust the values of the variables in your build system.
+#
+#  get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
+#
+# Returns the refspec and sha hash of the current head revision
+#
+#  git_describe(<var> [<additional arguments to git describe> ...])
+#
+# Returns the results of git describe on the source tree, and adjusting
+# the output so that it tests false if an error occurs.
+#
+#  git_get_exact_tag(<var> [<additional arguments to git describe> ...])
+#
+# Returns the results of git describe --exact-match on the source tree,
+# and adjusting the output so that it tests false if there was no exact
+# matching tag.
+#
+# Requires CMake 2.6 or newer (uses the 'function' command)
+#
+# Original Author:
+# 2009-2010 Ryan Pavlik <rpavlik at iastate.edu> <abiryan at ryand.net>
+# http://academic.cleardefinition.com
+# Iowa State University HCI Graduate Program/VRAC
+#
+# Copyright Iowa State University 2009-2010.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+if(__get_git_revision_description)
+  return()
+endif()
+set(__get_git_revision_description YES)
+
+# We must run the following at "include" time, not at function call time,
+# to find the path to this module rather than the path to a calling list file
+get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
+
+function(get_git_head_revision _refspecvar _hashvar)
+  set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+  set(GIT_DIR "${GIT_PARENT_DIR}/.git")
+  while(NOT EXISTS "${GIT_DIR}")  # .git dir not found, search parent directories
+    set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
+    get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
+    if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
+      # We have reached the root directory, we are not in git
+      set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
+      set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
+      return()
+    endif()
+    set(GIT_DIR "${GIT_PARENT_DIR}/.git")
+  endwhile()
+  # check if this is a submodule
+  if(NOT IS_DIRECTORY ${GIT_DIR})
+    file(READ ${GIT_DIR} submodule)
+    string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
+    get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
+    get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
+  endif()
+  set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
+  if(NOT EXISTS "${GIT_DATA}")
+    file(MAKE_DIRECTORY "${GIT_DATA}")
+  endif()
+
+  if(NOT EXISTS "${GIT_DIR}/HEAD")
+    return()
+  endif()
+  set(HEAD_FILE "${GIT_DATA}/HEAD")
+  configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
+
+  configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
+    "${GIT_DATA}/grabRef.cmake"
+    @ONLY)
+  include("${GIT_DATA}/grabRef.cmake")
+
+  set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
+  set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
+endfunction()
+
+function(git_describe _var)
+  if(NOT GIT_FOUND)
+    find_package(Git QUIET)
+  endif()
+  get_git_head_revision(refspec hash)
+  if(NOT GIT_FOUND)
+    set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
+    return()
+  endif()
+  if(NOT hash)
+    set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
+    return()
+  endif()
+
+  # TODO sanitize
+  #if((${ARGN}" MATCHES "&&") OR
+  # (ARGN MATCHES "||") OR
+  # (ARGN MATCHES "\\;"))
+  # message("Please report the following error to the project!")
+  # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
+  #endif()
+
+  #message(STATUS "Arguments to execute_process: ${ARGN}")
+
+  execute_process(COMMAND
+    "${GIT_EXECUTABLE}"
+    describe
+    ${hash}
+    ${ARGN}
+    WORKING_DIRECTORY
+    "${CMAKE_SOURCE_DIR}"
+    RESULT_VARIABLE
+    res
+    OUTPUT_VARIABLE
+    out
+    ERROR_QUIET
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+  if(NOT res EQUAL 0)
+    set(out "${out}-${res}-NOTFOUND")
+  endif()
+
+  set(${_var} "${out}" PARENT_SCOPE)
+endfunction()
+
+function(git_get_exact_tag _var)
+  git_describe(out --exact-match ${ARGN})
+  set(${_var} "${out}" PARENT_SCOPE)
+endfunction()
diff --git a/CMake/rpavlik/GetGitRevisionDescription.cmake.in b/CMake/rpavlik/GetGitRevisionDescription.cmake.in
new file mode 100644
index 0000000..8a085b2
--- /dev/null
+++ b/CMake/rpavlik/GetGitRevisionDescription.cmake.in
@@ -0,0 +1,38 @@
+# 
+# Internal file for GetGitRevisionDescription.cmake
+#
+# Requires CMake 2.6 or newer (uses the 'function' command)
+#
+# Original Author:
+# 2009-2010 Ryan Pavlik <rpavlik at iastate.edu> <abiryan at ryand.net>
+# http://academic.cleardefinition.com
+# Iowa State University HCI Graduate Program/VRAC
+#
+# Copyright Iowa State University 2009-2010.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+set(HEAD_HASH)
+
+file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
+
+string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
+if(HEAD_CONTENTS MATCHES "ref")
+  # named branch
+  string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
+  if(EXISTS "@GIT_DIR@/${HEAD_REF}")
+    configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
+  elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
+    configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
+    set(HEAD_HASH "${HEAD_REF}")
+  endif()
+else()
+  # detached HEAD
+  configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
+endif()
+
+if(NOT HEAD_HASH)
+  file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
+  string(STRIP "${HEAD_HASH}" HEAD_HASH)
+endif()
diff --git a/CMake/standalone.cmake b/CMake/standalone.cmake
index 6ccfaab..de4162d 100644
--- a/CMake/standalone.cmake
+++ b/CMake/standalone.cmake
@@ -1,50 +1,45 @@
 #############################################
 # REQUIRE ITK 3.20 OR LATER                 #
 #############################################
-FIND_PACKAGE(ITK 3.20 REQUIRED)
+FIND_PACKAGE(ITK REQUIRED)
 INCLUDE(${ITK_USE_FILE})
 
 #############################################
 # REQUIRE VTK                               #
 #############################################
-FIND_PACKAGE(VTK 5.6 REQUIRED)
+FIND_PACKAGE(VTK REQUIRED)
 INCLUDE (${VTK_USE_FILE})
 
 #############################################
-# REQUIRE FLTK                              #
+# REQUIRE QT                                #
 #############################################
-INCLUDE(${SNAP_SOURCE_DIR}/CMake/find_fltk_13.cmake)
-
-# Allow FLTK 1.1 for older systems. This is an optional flag
-OPTION(SNAP_USE_FLTK_1_1 OFF "Build with older FLTK 1.1")
-MARK_AS_ADVANCED(SNAP_USE_FLTK_1_1)
-IF(SNAP_USE_FLTK_1_1)
-  SUBDIRS(Utilities/FLTK/Fl_Table)
-  SUBDIRS(Utilities/FLTK/Fl_Native_File_Chooser)
-  SET(FLTK_LIBRARIES fltk_table fltk_native_file_chooser ${FLTK_LIBRARIES})
-  SET(FLTK_INCLUDE_PATH ${FLTK_INCLUDE_PATH} 
-    ${SNAP_SOURCE_DIR}/Utilities/FLTK/Fl_Table
-    ${SNAP_SOURCE_DIR}/Utilities/FLTK/Fl_Native_File_Chooser)
-ENDIF(SNAP_USE_FLTK_1_1)
+FIND_PACKAGE(Qt5Widgets)
+FIND_PACKAGE(Qt5OpenGL)
+FIND_PACKAGE(Qt5Concurrent)
+FIND_PACKAGE(Qt5Qml)
+
+SET(SNAP_QT5_INCLUDE_DIRS
+  ${Qt5Widgets_INCLUDE_DIRS}
+  ${Qt5OpenGL_INCLUDE_DIRS}
+  ${Qt5Concurrent_INCLUDE_DIRS}
+  ${Qt5Qml_INCLUDE_DIRS}
+)
+
+SET(SNAP_QT5_LIBRARIES
+  Qt5::Widgets
+  Qt5::OpenGL
+  Qt5::Concurrent
+  Qt5::Qml
+)
+
+# Set vars for the QT binary and library directories
+GET_FILENAME_COMPONENT(QT_BINARY_DIR "${Qt5Core_DIR}/../../../bin" ABSOLUTE)
+GET_FILENAME_COMPONENT(QT_LIBRARY_DIR "${Qt5Core_DIR}/../../" ABSOLUTE)
 
 # Look for OpenGL.
 FIND_PACKAGE(OpenGL REQUIRED)
 
-# The fluid-generated fltk sources have many warnings.  This macro
-# will disable warnings for the generated files on some compilers.
-MACRO(ITK_DISABLE_FLTK_GENERATED_WARNINGS files)
-  IF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 1.6)
-    IF(CMAKE_COMPILER_IS_GNUCXX)
-      FOREACH(f ${files})
-        STRING(REGEX REPLACE "\\.fl$" ".cxx" SRC "${f}")
-        STRING(REGEX REPLACE ".*/([^/]*)$" "\\1" SRC "${SRC}")
-        SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS -w)
-      ENDFOREACH(f)
-    ENDIF(CMAKE_COMPILER_IS_GNUCXX)
-  ENDIF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 1.6)
-ENDMACRO(ITK_DISABLE_FLTK_GENERATED_WARNINGS)
-
 # Link libraries from the parent CMAKE file
-LINK_LIBRARIES(ITKAlgorithms ITKCommon ITKBasicFilters)
+#LINK_LIBRARIES(ITKAlgorithms ITKCommon ITKBasicFilters)
 
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dae30c9..8350e69 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,41 +1,102 @@
-#############################################
-# CMAKE PRELIMINARIES                       #
-#############################################
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6.2)
-IF(COMMAND CMAKE_POLICY)
-  CMAKE_POLICY(SET CMP0003 NEW)
-ENDIF(COMMAND CMAKE_POLICY)  
-
-#############################################
-# PROJECT: SNAP                             #
-#############################################
+#--------------------------------------------------------------------------------
+# PROJECT: SNAP                             
+#--------------------------------------------------------------------------------
+# This CMake file is modeled after QtTest example project from
+# http://www.cmake.org/Wiki/BundleUtilitiesExample
+
 PROJECT(SNAP)
 
-#############################################
-# VERSION INFORMATION                       #
-#############################################
+#--------------------------------------------------------------------------------
+# CMAKE PRELIMINARIES                       
+#--------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 2.8.12)
+
+SET(CMAKE_MODULE_PATH ${SNAP_SOURCE_DIR}/CMake)
+
+#--------------------------------------------------------------------------------
+# MACROS
+#--------------------------------------------------------------------------------
+# Get today's date (see http://cmake.3232098.n2.nabble.com/How-to-get-the-current-date-td5776870.html)
+MACRO (TODAY RESULT)
+    IF (WIN32)
+        EXECUTE_PROCESS(COMMAND "cmd" " /C date /T" OUTPUT_VARIABLE ${RESULT})
+        string(REGEX REPLACE "(..)/(..)/(....).*" "\\1/\\2/\\3" ${RESULT} ${${RESULT}})
+    ELSEIF(UNIX)
+        EXECUTE_PROCESS(COMMAND "date" "+%b %d, %Y" OUTPUT_VARIABLE ${RESULT})
+        string(REGEX REPLACE "(...) (..), (....).*" "\\1 \\2, \\3" ${RESULT} ${${RESULT}})
+    ELSE (WIN32)
+        MESSAGE(SEND_ERROR "date not implemented")
+        SET(${RESULT} 000000)
+    ENDIF (WIN32)
+	string(REPLACE "\n" "" ${RESULT} ${${RESULT}})
+	string(REPLACE " " "" ${RESULT} ${${RESULT}})
+ENDMACRO (TODAY)
+
+get_cmake_property(_variableNames VARIABLES)
+foreach (_variableName ${_variableNames})
+    message(STATUS "${_variableName}=${${_variableName}}")
+endforeach()
+
+
+#--------------------------------------------------------------------------------
+# VERSION INFORMATION                       
+#--------------------------------------------------------------------------------
 # On SNAP versions.
 # =================
 # The SNAP version consists of four fields: major, minor, patch and qualifier
 # for example, version 1.7.3-beta has major version 1, minor version 7, patch 3
 # and qualifier "-beta". Major, minor and patch must be numbers, but the qualifier
 # is an arbitrary string and may be blank. 
-# 
-# Important:
-#   - The qualifier is just a descriptor. No two version should have the same 
-#     major/minor/patch and different qualifiers. So it's completely wrong to 
-#     release version 1.7.3-beta and then version 1.7.3. The right way to do it
-#     is to have 1.7.3-beta followed by 1.7.5-rc1 followed by 1.8.0 and so on
-SET(SNAP_VERSION_MAJOR 2)
+
+# These four fields should be modified when versions change
+SET(SNAP_VERSION_MAJOR 3)
 SET(SNAP_VERSION_MINOR 2)
 SET(SNAP_VERSION_PATCH 0)
 SET(SNAP_VERSION_QUALIFIER "")
-SET(SNAP_VERSION_FULL "${SNAP_VERSION_MAJOR}.${SNAP_VERSION_MINOR}.${SNAP_VERSION_PATCH}${SNAP_VERSION_QUALIFIER}")
-SET(SNAP_VERSION_RELEASE_DATE "20110504")
-SET(SNAP_VERSION_LAST_COMPATIBLE_RELEASE_DATE "20090731")
-SET(SNAP_VERSION_RELEASE_DATE_FORMATTED "May 4, 2011")
 
-# Shamelessly stolen from ParaView
+# These fields should also be modified each time
+SET(SNAP_VERSION_RELEASE_DATE "20141023")
+SET(SNAP_VERSION_RELEASE_DATE_FORMATTED "Oct 23, 2014")
+
+# This field should only change when the format of the settings files changes
+# in a non backwards-compatible way
+SET(SNAP_VERSION_LAST_COMPATIBLE_RELEASE_DATE "20131201")
+
+# This should not need to change
+SET(SNAP_VERSION_FULL 
+  "${SNAP_VERSION_MAJOR}.${SNAP_VERSION_MINOR}.${SNAP_VERSION_PATCH}${SNAP_VERSION_QUALIFIER}")
+
+# Get today's date (see http://cmake.3232098.n2.nabble.com/How-to-get-the-current-date-td5776870.html)
+TODAY(SNAP_VERSION_COMPILE_DATE)
+
+# Get the current git hash
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake/rpavlik/")
+include(GetGitRevisionDescription)
+get_git_head_revision(GIT_REFSPEC SNAP_VERSION_GIT_SHA1)
+
+#--------------------------------------------------------------------------------
+# FIND PACKAGES IF BUILDING OUTSIDE INSIGHTAPPLICATIONS 
+#--------------------------------------------------------------------------------
+IF(DEFINED InsightApplications_SOURCE_DIR)
+  SET(BUILD_OUTSIDE_INSIGHT_APPLICATIONS FALSE CACHE BOOL 
+	"Is SNAP being built separate from InsightApplications?")
+ELSE(DEFINED InsightApplications_SOURCE_DIR)
+  SET(BUILD_OUTSIDE_INSIGHT_APPLICATIONS TRUE CACHE BOOL 
+	"Is SNAP being built separate from InsightApplications?")
+ENDIF(DEFINED InsightApplications_SOURCE_DIR)			
+
+IF( BUILD_OUTSIDE_INSIGHT_APPLICATIONS )
+  INCLUDE(${SNAP_SOURCE_DIR}/CMake/standalone.cmake)
+ENDIF( BUILD_OUTSIDE_INSIGHT_APPLICATIONS )
+
+#--------------------------------------------------------------------------------
+# CPACK PACKAGE NAME
+# Create a complete name for the package, including the system information
+# (Shamelessly stolen from ParaView's CMakeLists.txt)
+#--------------------------------------------------------------------------------
+# *** THIS CODE MUST APPEAR BEFORE CALLING CONFIGURE_FILE on SNAPCommon.cxx ***
+#--------------------------------------------------------------------------------
+
 SET(CPACK_SOURCE_PACKAGE_FILE_NAME "itksnap-${SNAP_VERSION_FULL}-${SNAP_VERSION_RELEASE_DATE}")
 IF (CMAKE_SYSTEM_PROCESSOR MATCHES "unknown")
   EXEC_PROGRAM(uname ARGS "-m" OUTPUT_VARIABLE CMAKE_SYSTEM_PROCESSOR)
@@ -53,85 +114,126 @@ ENDIF(${CPACK_SYSTEM_NAME} MATCHES Windows)
 
 # For Apple, we need to base the filename on the architecture
 IF(CMAKE_SYSTEM_NAME MATCHES Darwin)
-  STRING(REPLACE ";" "-" ARCHBIT ${CMAKE_OSX_ARCHITECTURES})
-  SET(CPACK_SYSTEM_NAME "MacOS-${ARCHBIT}")
+  MESSAGE(STATUS "   INARCH ${CMAKE_OSX_ARCHITECTURES}")
+
+  # TODO: when CMAKE_OSX_ARCHITECTURES is not set this causes an obscure
+  # CMake error. Should generate a meaningful message instead
+  STRING(REPLACE ";" "-" ARCH ${CMAKE_OSX_ARCHITECTURES})
+  SET(CPACK_SYSTEM_NAME "MacOS-${ARCH}")
+  MESSAGE(STATUS "   ARCH ${ARCH}")
+  MESSAGE(STATUS "   CMAKE_OSX_ARCHITECTURES ${CMAKE_OSX_ARCHITECTURES}")
 ENDIF(CMAKE_SYSTEM_NAME MATCHES Darwin)
 
-IF(NOT DEFINED CPACK_PACKAGE_FILE_NAME)
-  SET(CPACK_PACKAGE_FILE_NAME "${CPACK_SOURCE_PACKAGE_FILE_NAME}-${CPACK_SYSTEM_NAME}")
-ENDIF(NOT DEFINED CPACK_PACKAGE_FILE_NAME)
+MESSAGE(STATUS "   CPACK_SYSTEM_NAME ${CPACK_SYSTEM_NAME}")
 
-#########################################################
-# FIND PACKAGES IF BUILDING OUTSIDE INSIGHTAPPLICATIONS #
-#########################################################
-IF(DEFINED InsightApplications_SOURCE_DIR)
-  SET(BUILD_OUTSIDE_INSIGHT_APPLICATIONS FALSE CACHE BOOL 
-	"Is SNAP being built separate from InsightApplications?")
-ELSE(DEFINED InsightApplications_SOURCE_DIR)
-  SET(BUILD_OUTSIDE_INSIGHT_APPLICATIONS TRUE CACHE BOOL 
-	"Is SNAP being built separate from InsightApplications?")
-ENDIF(DEFINED InsightApplications_SOURCE_DIR)			
+SET(CPACK_PACKAGE_FILE_NAME "${CPACK_SOURCE_PACKAGE_FILE_NAME}-${CPACK_SYSTEM_NAME}")
 
-IF( BUILD_OUTSIDE_INSIGHT_APPLICATIONS )
-  INCLUDE(${SNAP_SOURCE_DIR}/CMake/standalone.cmake)
-ENDIF( BUILD_OUTSIDE_INSIGHT_APPLICATIONS )
+MESSAGE(STATUS "   CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_FILE_NAME}")
+
+# Additional CPack resources
+SET(CPACK_RESOURCE_FILE_LICENSE "${SNAP_SOURCE_DIR}/COPYING")
 
-#############################################
-# SOURCE FILE SPECIFICATION                 #
-#############################################
+
+#--------------------------------------------------------------------------------
+# SOURCE FILE SPECIFICATION                 
+#--------------------------------------------------------------------------------
 
 # One of the files needs to be configured (to insert version info)
 CONFIGURE_FILE(
   ${SNAP_SOURCE_DIR}/Common/SNAPCommon.cxx.in
   ${SNAP_BINARY_DIR}/SNAPCommon.cxx @ONLY IMMEDIATE)
 
+# Option to use GPU for SNAP
+OPTION(SNAP_USE_GPU "Use GPU in SNAP" OFF) 
+
+# Pass the option SNAP_USE_GPU to a header file
+CONFIGURE_FILE(
+  ${SNAP_SOURCE_DIR}/Common/GPUSettings.h.in
+  ${SNAP_BINARY_DIR}/GPUSettings.h @ONLY IMMEDIATE)
+
 # The part of the source code devoted to the SNAP application logic
 # is organized into a separate library
 SET(LOGIC_CXX
   ${SNAP_BINARY_DIR}/SNAPCommon.cxx
+  Common/AbstractModel.cxx
+  Common/AbstractPropertyContainerModel.cxx
   Common/CommandLineArgumentParser.cxx
+  Common/EventBucket.cxx
+  Common/HistoryManager.cxx
+  Common/IPCHandler.cxx
   Common/IRISException.cxx
+  Common/Rebroadcaster.cxx
   Common/Registry.cxx
+  Common/SNAPOpenGL.cxx
   Common/SystemInterface.cxx
+  Common/ThreadSpecificData.cxx
   Common/ITKExtras/itkVoxBoCUBImageIO.cxx
   Common/ITKExtras/itkVoxBoCUBImageIOFactory.cxx
-  Logic/Common/ColorMap.cxx
+  Common/Trackball.cxx
   Logic/Common/ColorLabelTable.cxx
+  Logic/Common/ColorMap.cxx
+  Logic/Common/ColorMapPresetManager.cxx
   Logic/Common/ImageCoordinateGeometry.cxx
   Logic/Common/ImageCoordinateTransform.cxx
+  Logic/Common/IRISDisplayGeometry.cxx
+  Logic/Common/LabelUseHistory.cxx
+  Logic/Common/MetaDataAccess.cxx
   Logic/Common/SegmentationStatistics.cxx
+  Logic/Common/SNAPAppearanceSettings.cxx
   Logic/Common/SNAPRegistryIO.cxx
   Logic/Common/SNAPSegmentationROISettings.cxx
+  Logic/Framework/DefaultBehaviorSettings.cxx
   Logic/Framework/GenericImageData.cxx
   Logic/Framework/GlobalState.cxx
+  Logic/Framework/ImageIODelegates.cxx
   Logic/Framework/IRISApplication.cxx
   Logic/Framework/IRISImageData.cxx
+  Logic/Framework/LayerIterator.cxx
   Logic/Framework/SNAPImageData.cxx
   Logic/Framework/UndoDataManager_LabelType.cxx
-  Logic/ImageWrapper/GreyImageWrapper.cxx
+  Logic/ImageWrapper/CommonRepresentationPolicy.cxx
+  Logic/ImageWrapper/DisplayMappingPolicy.cxx
+  Logic/ImageWrapper/ImageWrapperBase.cxx
+  Logic/ImageWrapper/ImageWrapper.cxx
+  Logic/ImageWrapper/InputSelectionImageFilter.cxx
   Logic/ImageWrapper/GuidedNativeImageIO.cxx
-  Logic/ImageWrapper/LabelImageWrapper.cxx
-  Logic/ImageWrapper/LevelSetImageWrapper.cxx
-  Logic/ImageWrapper/RGBImageWrapper.cxx
-  Logic/ImageWrapper/SpeedColorMap.cxx
-  Logic/ImageWrapper/SpeedImageWrapper.cxx
+  Logic/ImageWrapper/ScalarImageHistogram.cxx
+  Logic/ImageWrapper/ScalarImageWrapper.cxx
+  Logic/ImageWrapper/VectorImageWrapper.cxx
   Logic/LevelSet/SnakeParameters.cxx
+  Logic/LevelSet/SnakeParametersPreviewPipeline.cxx
   Logic/Mesh/AllPurposeProgressAccumulator.cxx
   Logic/Mesh/GuidedMeshIO.cxx
-  Logic/Mesh/IRISMeshPipeline.cxx
+  Logic/Mesh/MultiLabelMeshPipeline.cxx
   Logic/Mesh/LevelSetMeshPipeline.cxx
-  Logic/Mesh/MeshObject.cxx
+  Logic/Mesh/MeshManager.cxx
   Logic/Mesh/MeshOptions.cxx
   Logic/Mesh/VTKMeshPipeline.cxx
   Logic/Preprocessing/EdgePreprocessingSettings.cxx
+  Logic/Preprocessing/PreprocessingFilterConfigTraits.cxx
   Logic/Preprocessing/ThresholdSettings.cxx
+  Logic/Preprocessing/GMM/EMGaussianMixtures.cxx
+  Logic/Preprocessing/GMM/Gaussian.cxx
+  Logic/Preprocessing/GMM/GaussianMixtureModel.cxx
+  Logic/Preprocessing/GMM/KMeansPlusPlus.cxx
+  Logic/Preprocessing/GMM/UnsupervisedClustering.cxx
+  Logic/Preprocessing/RandomForest/RFClassificationEngine.cxx
+  Logic/Preprocessing/RandomForest/RandomForestClassifier.cxx
   Logic/Slicing/IntensityCurveVTK.cxx
+  Logic/Slicing/IntensityToColorLookupTableImageFilter.cxx
+  Logic/Slicing/LookupTableIntensityMappingFilter.cxx
+  Logic/Slicing/RGBALookupTableIntensityMappingFilter.cxx
 )
 
 # The headers for the Logic code
 SET(LOGIC_HEADERS
+  ${SNAP_BINARY_DIR}/GPUSettings.h
+  Common/AbstractModel.h
+  Common/AbstractPropertyContainerModel.h
   Common/CommandLineArgumentParser.h
   Common/Credits.h
+  Common/HistoryManager.h
+  Common/IPCHandler.h
   Common/IRISException.h
   Common/IRISVectorTypes.h
   Common/IRISVectorTypes.txx
@@ -148,43 +250,63 @@ SET(LOGIC_HEADERS
   Common/ITKExtras/itkTopologyPreservingDigitalSurfaceEvolutionImageFilter.txx
   Common/ITKExtras/itkVoxBoCUBImageIO.h
   Common/ITKExtras/itkVoxBoCUBImageIOFactory.h
+  Common/PresetManager.h
+  Common/PresetManager.hxx
+  Common/PropertyModel.h
+  Common/Rebroadcaster.h
   Common/Registry.h
   Common/SNAPBorlandDummyTypes.h
   Common/SNAPCommon.h
   Common/SNAPOpenGL.h
+  Common/SNAPEvents.h
   Common/SystemInterface.h
+  Common/ThreadSpecificData.h
+  Common/Trackball.h
   Logic/Common/ColorLabel.h
   Logic/Common/ColorLabelTable.h
   Logic/Common/ColorMap.h
+  Logic/Common/ColorMapPresetManager.h
   Logic/Common/ImageCoordinateGeometry.h
   Logic/Common/ImageCoordinateTransform.h
+  Logic/Common/IRISDisplayGeometry.h
+  Logic/Common/LabelUseHistory.h
   Logic/Common/SegmentationStatistics.h
   Logic/Common/ImageRayIntersectionFinder.h
   Logic/Common/ImageRayIntersectionFinder.txx
+  Logic/Common/MetaDataAccess.h
+  Logic/Common/SNAPAppearanceSettings.h
   Logic/Common/SNAPRegistryIO.h
   Logic/Common/SNAPSegmentationROISettings.h
+  Logic/Framework/DefaultBehaviorSettings.h
   Logic/Framework/GenericImageData.h
   Logic/Framework/GlobalState.h
+  Logic/Framework/ImageIODelegates.h
   Logic/Framework/IRISApplication.h
   Logic/Framework/IRISImageData.h
+  Logic/Framework/LayerAssociation.h
+  Logic/Framework/LayerAssociation.txx
+  Logic/Framework/LayerIterator.h
   Logic/Framework/SNAPImageData.h
   Logic/Framework/UndoDataManager.h
   Logic/Framework/UndoDataManager.txx
-  Logic/ImageWrapper/GreyImageWrapper.h
-  Logic/ImageWrapper/ImageIORoutines.h
+  Logic/ImageWrapper/CommonRepresentationPolicy.h
+  Logic/ImageWrapper/DisplayMappingPolicy.h
+  Logic/ImageWrapper/GuidedNativeImageIO.h
   Logic/ImageWrapper/ImageWrapper.h
-  Logic/ImageWrapper/ImageWrapper.txx
-  Logic/ImageWrapper/LabelImageWrapper.h
+  Logic/ImageWrapper/ImageWrapperBase.h
+  Logic/ImageWrapper/ImageWrapperTraits.h
+  Logic/ImageWrapper/InputSelectionImageFilter.h
   Logic/ImageWrapper/LabelToRGBAFilter.h
-  Logic/ImageWrapper/LevelSetImageWrapper.h
-  Logic/ImageWrapper/RGBImageWrapper.h
+  Logic/ImageWrapper/NativeIntensityMappingPolicy.h
+  Logic/ImageWrapper/ScalarImageHistogram.h
   Logic/ImageWrapper/ScalarImageWrapper.h
-  Logic/ImageWrapper/ScalarImageWrapper.txx
-  Logic/ImageWrapper/SpeedColorMap.h
-  Logic/ImageWrapper/SpeedImageWrapper.h
+  Logic/ImageWrapper/ThreadedHistogramImageFilter.h
+  Logic/ImageWrapper/ThreadedHistogramImageFilter.hxx
   Logic/ImageWrapper/VectorImageWrapper.h
-  Logic/ImageWrapper/VectorImageWrapper.txx
+  Logic/ImageWrapper/CPUImageToGPUImageFilter.h
+  Logic/ImageWrapper/CPUImageToGPUImageFilter.hxx
   Logic/LevelSet/LevelSetExtensionFilter.h
+  Logic/LevelSet/SnakeParametersPreviewPipeline.h
   Logic/LevelSet/SNAPAdvectionFieldImageFilter.h
   Logic/LevelSet/SNAPAdvectionFieldImageFilter.txx
   Logic/LevelSet/SNAPLevelSetDriver.h
@@ -198,180 +320,426 @@ SET(LOGIC_HEADERS
   Logic/LevelSet/SnakeParameters.h
   Logic/Mesh/AllPurposeProgressAccumulator.h
   Logic/Mesh/GuidedMeshIO.h
-  Logic/Mesh/IRISMeshPipeline.h
+  Logic/Mesh/MultiLabelMeshPipeline.h
   Logic/Mesh/LevelSetMeshPipeline.h
-  Logic/Mesh/MeshObject.h
+  Logic/Mesh/MeshManager.h
   Logic/Mesh/MeshOptions.h
   Logic/Mesh/VTKMeshPipeline.h
   Logic/Preprocessing/EdgePreprocessingImageFilter.h
   Logic/Preprocessing/EdgePreprocessingImageFilter.txx
   Logic/Preprocessing/EdgePreprocessingSettings.h
+  Logic/Preprocessing/GMMClassifyImageFilter.h
+  Logic/Preprocessing/GMMClassifyImageFilter.txx
+  Logic/Preprocessing/PreprocessingFilterConfigTraits.h
+  Logic/Preprocessing/RandomForestClassifyImageFilter.h
+  Logic/Preprocessing/RandomForestClassifyImageFilter.txx
+  Logic/Preprocessing/SlicePreviewFilterWrapper.h
+  Logic/Preprocessing/SlicePreviewFilterWrapper.txx
   Logic/Preprocessing/SmoothBinaryThresholdImageFilter.h
   Logic/Preprocessing/SmoothBinaryThresholdImageFilter.txx
   Logic/Preprocessing/ThresholdSettings.h
+  Logic/Preprocessing/GMM/EMGaussianMixtures.h
+  Logic/Preprocessing/GMM/Gaussian.h
+  Logic/Preprocessing/GMM/GaussianMixtureModel.h
+  Logic/Preprocessing/GMM/KMeansPlusPlus.h
+  Logic/Preprocessing/GMM/UnsupervisedClustering.h
+  Logic/Preprocessing/RandomForest/RFClassificationEngine.h
+  Logic/Preprocessing/RandomForest/RandomForestClassifier.h
   Logic/Slicing/IRISSlicer.h
   Logic/Slicing/IRISSlicer.txx
   Logic/Slicing/IntensityCurveInterface.h
   Logic/Slicing/IntensityCurveVTK.h
-  Logic/Slicing/UnaryFunctorCache.h
-  Logic/Slicing/UnaryFunctorCache.txx  
+  Logic/Slicing/IntensityToColorLookupTableImageFilter.h
+  Logic/Slicing/LookupTableIntensityMappingFilter.h
+  Logic/Slicing/RGBALookupTableIntensityMappingFilter.h
 )
 
-# These files contain the user interface source code
-SET(UI_CXX
-  UserInterface/BasicComponents/ColorMapBox.cxx
-  UserInterface/BasicComponents/ColorMapWidget.cxx
-  UserInterface/BasicComponents/FLTKCanvas.cxx
-  UserInterface/BasicComponents/FunctionPlot2DBox.cxx
-  UserInterface/BasicComponents/FunctionPlot2D.cxx
-  UserInterface/BasicComponents/IntensityCurveBox.cxx
-  UserInterface/BasicComponents/InteractionModeClient.cxx
-  UserInterface/BasicComponents/MetaDataTable.cxx
-  UserInterface/BasicComponents/RecursiveInteractionMode.cxx
-  UserInterface/BasicComponents/SnakeParametersPreviewBox.cxx
-  UserInterface/BasicComponents/SnakeParametersPreviewPipeline.cxx
-  UserInterface/BasicComponents/StatisticsTable.cxx
-  UserInterface/Common/SNAPAppearanceSettings.cxx
-  UserInterface/ImageIOWizard/ImageIOWizardLogic.cxx
-  UserInterface/ImageIOWizard/RestrictedImageIOWizardLogic.cxx
-  UserInterface/MainComponents/AppearanceDialogUILogic.cxx
-  UserInterface/MainComponents/HelpViewerLogic.cxx
-  UserInterface/MainComponents/LabelEditorUILogic.cxx
-  UserInterface/MainComponents/LayerInspectorUILogic.cxx
-  UserInterface/MainComponents/PreprocessingUILogic.cxx
-  UserInterface/MainComponents/ReorientImageUILogic.cxx
-  UserInterface/MainComponents/ResizeRegionDialogLogic.cxx
-  UserInterface/MainComponents/RestoreSettingsDialogLogic.cxx
-  UserInterface/MainComponents/SimpleFileDialogLogic.cxx
-  UserInterface/MainComponents/SnakeParametersUILogic.cxx
-  UserInterface/MainComponents/UserInterfaceLogic.cxx
-  UserInterface/MeshIOWizard/MeshIOWizardUILogic.cxx
-  UserInterface/SliceWindow/AnnotationInteractionMode.cxx
-  UserInterface/SliceWindow/BubblesInteractionMode.cxx
-  UserInterface/SliceWindow/CrosshairsInteractionMode.cxx
-  UserInterface/SliceWindow/GenericSliceWindow.cxx
-  UserInterface/SliceWindow/IRISSliceWindow.cxx
-  UserInterface/SliceWindow/GLToPNG.cxx
-  UserInterface/SliceWindow/OpenGLSliceTexture.cxx  
-  UserInterface/SliceWindow/PaintbrushInteractionMode.cxx
-  UserInterface/SliceWindow/PolygonDrawing.cxx
-  UserInterface/SliceWindow/PolygonInteractionMode.cxx
-  UserInterface/SliceWindow/PolygonScanConvert.cxx
-  UserInterface/SliceWindow/PopupButtonInteractionMode.cxx
-  UserInterface/SliceWindow/RegionInteractionMode.cxx
-  UserInterface/SliceWindow/SNAPSliceWindow.cxx
-  UserInterface/SliceWindow/SliceWindowCoordinator.cxx
-  UserInterface/SliceWindow/ThumbnailInteractionMode.cxx
-  UserInterface/Window3D/Trackball.cxx
-  UserInterface/Window3D/Window3D.cxx
+# These files have the UI model code, which is GUI-TK independent
+SET(UI_GENERIC_CXX
+  GUI/Model/ColorLabelQuickListModel.cxx
+  GUI/Model/ColorLabelPropertyModel.cxx
+  GUI/Model/ColorMapModel.cxx
+  GUI/Model/CursorInspectionModel.cxx
+  GUI/Model/DisplayLayoutModel.cxx
+  GUI/Model/Generic3DModel.cxx
+  GUI/Model/GenericSliceModel.cxx
+  GUI/Model/GlobalPreferencesModel.cxx
+  GUI/Model/GlobalUIModel.cxx
+  GUI/Model/ImageIOWizardModel.cxx
+  GUI/Model/ImageInfoModel.cxx
+  GUI/Model/IntensityCurveModel.cxx
+  GUI/Model/LabelEditorModel.cxx
+  GUI/Model/LayerGeneralPropertiesModel.cxx
+  GUI/Model/LayerTableRowModel.cxx
+  GUI/Model/LayerSelectionModel.cxx
+  GUI/Model/MeshExportModel.cxx
+  GUI/Model/OrthogonalSliceCursorNavigationModel.cxx
+  GUI/Model/PaintbrushModel.cxx
+  GUI/Model/PaintbrushSettingsModel.cxx
+  GUI/Model/PolygonDrawingModel.cxx
+  GUI/Model/ReorientImageModel.cxx
+  GUI/Model/SaveModifiedLayersModel.cxx
+  GUI/Model/SliceWindowCoordinator.cxx
+  GUI/Model/SnakeParameterModel.cxx
+  GUI/Model/SnakeROIModel.cxx
+  GUI/Model/SnakeROIResampleModel.cxx
+  GUI/Model/SnakeWizardModel.cxx
+  GUI/Model/StateManagement.cxx
+  GUI/Model/SynchronizationModel.cxx
+  GUI/Model/UIAction.cxx
+  GUI/Renderer/AbstractRenderer.cxx
+  GUI/Renderer/AbstractVTKRenderer.cxx
+  GUI/Renderer/AbstractVTKSceneRenderer.cxx
+  GUI/Renderer/ColorMapRenderer.cxx
+  GUI/Renderer/CrosshairsRenderer.cxx
+  GUI/Renderer/EdgePreprocessingSettingsRenderer.cxx
+  GUI/Renderer/GenericSliceRenderer.cxx
+  GUI/Renderer/Generic3DRenderer.cxx
+  GUI/Renderer/GLToPNG.cxx
+  GUI/Renderer/GMMRenderer.cxx
+  GUI/Renderer/IntensityCurveVTKRenderer.cxx
+  GUI/Renderer/LayerHistogramPlotAssembly.cxx
+  GUI/Renderer/OpenGLSliceTexture.cxx
+  GUI/Renderer/OrientationGraphicRenderer.cxx
+  GUI/Renderer/PaintbrushRenderer.cxx
+  GUI/Renderer/PolygonDrawingRenderer.cxx
+  GUI/Renderer/PolygonScanConvert.cxx
+  GUI/Renderer/SliceWindowDecorationRenderer.cxx
+  GUI/Renderer/SnakeParameterPreviewRenderer.cxx
+  GUI/Renderer/SnakeROIRenderer.cxx
+  GUI/Renderer/SnakeModeRenderer.cxx
+  GUI/Renderer/ThresholdSettingsRenderer.cxx
+  GUI/Renderer/Window3DPicker.cxx
+  GUI/Renderer/OrientationWidget/Reorient/AbstractScannerHelper.cxx
+  GUI/Renderer/OrientationWidget/Reorient/AxesWidget.cxx
+  GUI/Renderer/OrientationWidget/Reorient/ScannedHuman.cxx
+  GUI/Renderer/OrientationWidget/Reorient/ScanningROI.cxx
+  GUI/Renderer/OrientationWidget/Reorient/ReorientProps.cxx
+  GUI/Renderer/OrientationWidget/Reorient/PolyDataAlgorithm2ActorPipe.cxx
+)
+
+SET(UI_GENERIC_HEADERS
+  GUI/Model/AbstractLayerAssociatedModel.h
+  GUI/Model/AbstractLayerInfoItemSetDomain.h
+  GUI/Model/ColorMapModel.h
+  GUI/Model/ColorLabelQuickListModel.h
+  GUI/Model/ColorLabelPropertyModel.h
+  GUI/Model/CursorInspectionModel.h
+  GUI/Model/DisplayLayoutModel.h
+  GUI/Model/Generic3DModel.h
+  GUI/Model/GenericSliceModel.h
+  GUI/Model/GlobalPreferencesModel.h
+  GUI/Model/GlobalUIModel.h
+  GUI/Model/ImageInfoModel.h
+  GUI/Model/ImageIOWizardModel.h
+  GUI/Model/IntensityCurveModel.h
+  GUI/Model/LabelEditorModel.h
+  GUI/Model/LayerGeneralPropertiesModel.h
+  GUI/Model/LayerSelectionModel.h
+  GUI/Model/LayerTableRowModel.h
+  GUI/Model/MeshExportModel.h
+  GUI/Model/OrthogonalSliceCursorNavigationModel.h
+  GUI/Model/PaintbrushModel.h
+  GUI/Model/PaintbrushSettingsModel.h
+  GUI/Model/PolygonDrawingModel.h
+  GUI/Model/ReorientImageModel.h
+  GUI/Model/SaveModifiedLayersModel.h
+  GUI/Model/SNAPUIFlag.h
+  GUI/Model/SNAPUIFlag.txx
+  GUI/Model/SliceWindowCoordinator.h
+  GUI/Model/SnakeParameterModel.h
+  GUI/Model/SnakeROIModel.h
+  GUI/Model/SnakeROIResampleModel.h
+  GUI/Model/SnakeWizardModel.h
+  GUI/Model/StateManagement.h
+  GUI/Model/SynchronizationModel.h
+  GUI/Model/UIAction.h
+  GUI/Model/UIReporterDelegates.h
+  GUI/Model/UIState.h
+  GUI/Renderer/AbstractRenderer.h
+  GUI/Renderer/AbstractVTKRenderer.h
+  GUI/Renderer/AbstractVTKSceneRenderer.h
+  GUI/Renderer/ColorMapRenderer.h
+  GUI/Renderer/CrosshairsRenderer.h
+  GUI/Renderer/EdgePreprocessingSettingsRenderer.h
+  GUI/Renderer/Generic3DRenderer.h
+  GUI/Renderer/GenericSliceRenderer.h
+  GUI/Renderer/GLToPNG.h
+  GUI/Renderer/GMMRenderer.h
+  GUI/Renderer/IntensityCurveVTKRenderer.h
+  GUI/Renderer/LayerHistogramPlotAssembly.h
+  GUI/Renderer/OrientationGraphicRenderer.h
+  GUI/Renderer/PaintbrushRenderer.h
+  GUI/Renderer/PolygonDrawingRenderer.h
+  GUI/Renderer/PolygonScanConvert.h
+  GUI/Renderer/SliceWindowDecorationRenderer.h
+  GUI/Renderer/SnakeParameterPreviewRenderer.h
+  GUI/Renderer/SnakeROIRenderer.h
+  GUI/Renderer/SnakeModeRenderer.h
+  GUI/Renderer/ThresholdSettingsRenderer.h
+  GUI/Renderer/Window3DPicker.h
+  GUI/Renderer/OrientationWidget/Reorient/AbstractScannerHelper.h
+  GUI/Renderer/OrientationWidget/Reorient/AxesWidget.h
+  GUI/Renderer/OrientationWidget/Reorient/ScannedHuman.h
+  GUI/Renderer/OrientationWidget/Reorient/ScanningROI.h
+  GUI/Renderer/OrientationWidget/Reorient/ReorientProps.h
+  GUI/Renderer/OrientationWidget/Reorient/PolyDataAlgorithm2ActorPipe.h
+)
+
+# These files contain the Qt-specific user interface source code
+SET(UI_QT_CXX
+  GUI/Qt/Components/CollapsableGroupBox.cxx
+  GUI/Qt/Components/ColorLabelQuickListWidget.cxx
+  GUI/Qt/Components/ColorMapInspector.cxx
+  GUI/Qt/Components/ContrastInspector.cxx
+  GUI/Qt/Components/CursorInspector.cxx
+  GUI/Qt/Components/DisplayLayoutInspector.cxx
+  GUI/Qt/Components/FileChooserPanelWithHistory.cxx
+  GUI/Qt/Components/HistoryQListModel.cxx
+  GUI/Qt/Components/ImageInfoInspector.cxx
+  GUI/Qt/Components/LabelInspector.cxx
+  GUI/Qt/Components/LabelMiniInspector.cxx
+  GUI/Qt/Components/LabelSelectionButton.cxx
+  GUI/Qt/Components/LatentITKEventNotifier.cxx
+  GUI/Qt/Components/LayerInspectorRowDelegate.cxx
+  GUI/Qt/Components/MetadataInspector.cxx
+  GUI/Qt/Components/GeneralLayerInspector.cxx
+  GUI/Qt/Components/PaintbrushToolPanel.cxx
+  GUI/Qt/Components/QActionButton.cxx
+  GUI/Qt/Components/QColorButtonWidget.cxx
+  GUI/Qt/Components/QDoubleSlider.cxx
+  GUI/Qt/Components/QDoubleSliderWithEditor.cxx
+  GUI/Qt/Components/QtIPCManager.cxx
+  GUI/Qt/Components/QtRendererPlatformSupport.cxx
+  GUI/Qt/Components/QtReporterDelegates.cxx
+  GUI/Qt/Components/QtWarningDialog.cxx
+  GUI/Qt/Components/QtWidgetActivator.cxx
+  GUI/Qt/Components/RecentHistoryItemsView.cxx
+  GUI/Qt/Components/SnakeToolROIPanel.cxx
+  GUI/Qt/Components/SnakeWizardPanel.cxx
+  GUI/Qt/Components/SNAPComponent.cxx
+  GUI/Qt/Components/SNAPQtCommon.cxx
+  GUI/Qt/Components/SliceViewPanel.cxx
+  GUI/Qt/Components/SynchronizationInspector.cxx
+  GUI/Qt/Components/ViewPanel3D.cxx
+  GUI/Qt/Components/VoxelIntensityQTableModel.cxx
+  GUI/Qt/Components/ZoomInspector.cxx
+  GUI/Qt/External/ColorWheel/ColorWheel.cxx
+  GUI/Qt/ModelView/GMMTableModel.cxx
+  GUI/Qt/View/ColorMapBox.cxx
+  GUI/Qt/View/CrosshairsInteractionMode.cxx
+  GUI/Qt/View/GenericSliceView.cxx
+  GUI/Qt/View/GenericView3D.cxx
+  GUI/Qt/View/InteractionModeClient.cxx
+  GUI/Qt/View/QtAbstractOpenGLBox.cxx
+  GUI/Qt/View/QtInteractionDelegateWidget.cxx
+  GUI/Qt/View/QtSimpleOpenGLBox.cxx
+  GUI/Qt/View/QtVTKInteractionDelegateWidget.cxx
+  GUI/Qt/View/QtVTKRenderWindowBox.cxx
+  GUI/Qt/View/PaintbrushInteractionMode.cxx
+  GUI/Qt/View/PolygonDrawingInteractionMode.cxx
+  GUI/Qt/View/SliceWindowInteractionDelegateWidget.cxx
+  GUI/Qt/View/SnakeROIInteractionMode.cxx
+  GUI/Qt/View/ThumbnailInteractionMode.cxx
+  GUI/Qt/Windows/AboutDialog.cxx
+  GUI/Qt/Windows/DropActionDialog.cxx
+  GUI/Qt/Windows/ImageIODialog.cxx
+  GUI/Qt/Windows/ImageIOWizard.cxx
+  GUI/Qt/Windows/LabelEditorDialog.cxx
+  GUI/Qt/Windows/LayerInspectorDialog.cxx
+  GUI/Qt/Windows/LabelSelectionPopup.cxx
+  GUI/Qt/Windows/MainControlPanel.cxx
+  GUI/Qt/Windows/MainImageWindow.cxx
+  GUI/Qt/Windows/PreferencesDialog.cxx
+  GUI/Qt/Windows/QtStyles.cxx
+  GUI/Qt/Windows/ReorientImageDialog.cxx
+  GUI/Qt/Windows/ResampleDialog.cxx
+  GUI/Qt/Windows/SaveModifiedLayersDialog.cxx
+  GUI/Qt/Windows/SimpleFileDialogWithHistory.cxx
+  GUI/Qt/Windows/SnakeParameterDialog.cxx
+  GUI/Qt/Windows/SpeedImageDialog.cxx
+  GUI/Qt/Windows/SplashPanel.cxx
+  GUI/Qt/Windows/StatisticsDialog.cxx
+  GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.cxx
+  GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.cxx
+  GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.cxx
+  Testing/GUI/Qt/SNAPTestQt.cxx
 )
 
 # The header files for the UI project
-SET(UI_HEADERS
-  UserInterface/BasicComponents/ColorMapBox.h
-  UserInterface/BasicComponents/ColorMapWidget.h
-  UserInterface/BasicComponents/FLTKCanvas.h
-  UserInterface/BasicComponents/FLTKEvent.h
-  UserInterface/BasicComponents/FLTKWidgetActivationManager.h
-  UserInterface/BasicComponents/FunctionPlot2D.h
-  UserInterface/BasicComponents/FunctionPlot2DBox.h
-  UserInterface/BasicComponents/IntensityCurveBox.h
-  UserInterface/BasicComponents/InteractionMode.h
-  UserInterface/BasicComponents/InteractionModeClient.h
-  UserInterface/BasicComponents/MetaDataTable.h  
-  UserInterface/BasicComponents/RecursiveInteractionMode.h
-  UserInterface/BasicComponents/SnakeParametersPreviewBox.h
-  UserInterface/BasicComponents/SnakeParametersPreviewPipeline.h
-  UserInterface/BasicComponents/StatisticsTable.h
-  UserInterface/Common/SNAPAppearanceSettings.h
-  UserInterface/Common/SNAPCommonUI.h
-  UserInterface/ImageIOWizard/ImageIOWizardBase.h
-  UserInterface/ImageIOWizard/ImageIOWizardLogic.h
-  UserInterface/ImageIOWizard/RestrictedImageIOWizardLogic.h
-  UserInterface/MainComponents/AppearanceDialogUIBase.h
-  UserInterface/MainComponents/AppearanceDialogUILogic.h
-  UserInterface/MainComponents/HelpViewerBase.h
-  UserInterface/MainComponents/HelpViewerLogic.h
-  UserInterface/MainComponents/LabelEditorUIBase.h
-  UserInterface/MainComponents/LabelEditorUILogic.h
-  UserInterface/MainComponents/LayerInspectorUIBase.h
-  UserInterface/MainComponents/LayerInspectorUILogic.h
-  UserInterface/MainComponents/PreprocessingUIBase.h
-  UserInterface/MainComponents/PreprocessingUILogic.h
-  UserInterface/MainComponents/ReorientImageUIBase.h
-  UserInterface/MainComponents/ReorientImageUILogic.h
-  UserInterface/MainComponents/ResizeRegionDialogBase.h
-  UserInterface/MainComponents/ResizeRegionDialogLogic.h
-  UserInterface/MainComponents/RestoreSettingsDialogBase.h
-  UserInterface/MainComponents/RestoreSettingsDialogLogic.h
-  UserInterface/MainComponents/SimpleFileDialogBase.h
-  UserInterface/MainComponents/SimpleFileDialogLogic.h
-  UserInterface/MainComponents/SnakeParametersUIBase.h
-  UserInterface/MainComponents/SnakeParametersUILogic.h
-  UserInterface/MainComponents/UserInterfaceBase.h
-  UserInterface/MainComponents/UserInterfaceLogic.h
-  UserInterface/MeshIOWizard/MeshExportSettings.h
-  UserInterface/MeshIOWizard/MeshIOWizardUIBase.h
-  UserInterface/MeshIOWizard/MeshIOWizardUILogic.h
-  UserInterface/SliceWindow/AnnotationInteractionMode.h
-  UserInterface/SliceWindow/BubblesInteractionMode.h
-  UserInterface/SliceWindow/CrosshairsInteractionMode.h
-  UserInterface/SliceWindow/GLToPNG.h
-  UserInterface/SliceWindow/GenericSliceWindow.h
-  UserInterface/SliceWindow/IRISSliceWindow.h
-  UserInterface/SliceWindow/OpenGLSliceTexture.h
-  UserInterface/SliceWindow/PaintbrushInteractionMode.h
-  UserInterface/SliceWindow/PolygonDrawing.h
-  UserInterface/SliceWindow/PolygonInteractionMode.h
-  UserInterface/SliceWindow/PolygonScanConvert.h
-  UserInterface/SliceWindow/PopupButtonInteractionMode.h
-  UserInterface/SliceWindow/RegionInteractionMode.h
-  UserInterface/SliceWindow/SNAPSliceWindow.h
-  UserInterface/SliceWindow/SliceWindowCoordinator.h
-  UserInterface/SliceWindow/ThumbnailInteractionMode.h
-  UserInterface/Window3D/Trackball.h
-  UserInterface/Window3D/Window3D.h
+SET(UI_MOC_HEADERS
+  GUI/Qt/Components/CollapsableGroupBox.h
+  GUI/Qt/Components/ColorLabelQuickListWidget.h
+  GUI/Qt/Components/ColorMapInspector.h
+  GUI/Qt/Components/ContrastInspector.h
+  GUI/Qt/Components/CursorInspector.h
+  GUI/Qt/Components/DisplayLayoutInspector.h
+  GUI/Qt/Components/FileChooserPanelWithHistory.h
+  GUI/Qt/Components/HistoryQListModel.h
+  GUI/Qt/Components/ImageInfoInspector.h
+  GUI/Qt/Components/LabelInspector.h
+  GUI/Qt/Components/LabelMiniInspector.h
+  GUI/Qt/Components/LabelSelectionButton.h
+  GUI/Qt/Components/LatentITKEventNotifier.h
+  GUI/Qt/Components/LayerInspectorRowDelegate.h
+  GUI/Qt/Components/MetadataInspector.h
+  GUI/Qt/Components/GeneralLayerInspector.h
+  GUI/Qt/Components/PaintbrushToolPanel.h
+  GUI/Qt/Components/QActionButton.h
+  GUI/Qt/Components/QColorButtonWidget.h
+  GUI/Qt/Components/QDoubleSlider.h
+  GUI/Qt/Components/QDoubleSliderWithEditor.h
+  GUI/Qt/Components/QtIPCManager.h
+  GUI/Qt/Components/QtWarningDialog.h
+  GUI/Qt/Components/QtWidgetActivator.h
+  GUI/Qt/Components/RecentHistoryItemsView.h
+  GUI/Qt/Components/SnakeToolROIPanel.h
+  GUI/Qt/Components/SnakeWizardPanel.h
+  GUI/Qt/Components/SNAPComponent.h
+  GUI/Qt/Components/SliceViewPanel.h
+  GUI/Qt/Components/SynchronizationInspector.h
+  GUI/Qt/Components/ViewPanel3D.h
+  GUI/Qt/Components/VoxelIntensityQTableModel.h
+  GUI/Qt/Components/ZoomInspector.h
+  GUI/Qt/Coupling/QtWidgetCoupling.h
+  GUI/Qt/External/ColorWheel/ColorWheel.h
+  GUI/Qt/ModelView/GMMTableModel.h
+  GUI/Qt/View/ColorMapBox.h
+  GUI/Qt/View/CrosshairsInteractionMode.h
+  GUI/Qt/View/GenericSliceView.h
+  GUI/Qt/View/GenericView3D.h
+  GUI/Qt/View/QtAbstractOpenGLBox.h
+  GUI/Qt/View/QtInteractionDelegateWidget.h
+  GUI/Qt/View/QtSimpleOpenGLBox.h
+  GUI/Qt/View/QtVTKInteractionDelegateWidget.h
+  GUI/Qt/View/QtVTKRenderWindowBox.h
+  GUI/Qt/View/PaintbrushInteractionMode.h
+  GUI/Qt/View/PolygonDrawingInteractionMode.h
+  GUI/Qt/View/SliceWindowInteractionDelegateWidget.h
+  GUI/Qt/View/SnakeROIInteractionMode.h
+  GUI/Qt/View/ThumbnailInteractionMode.h
+  GUI/Qt/Windows/AboutDialog.h
+  GUI/Qt/Windows/DropActionDialog.h
+  GUI/Qt/Windows/ImageIODialog.h
+  GUI/Qt/Windows/ImageIOWizard.h
+  GUI/Qt/Windows/LabelEditorDialog.h
+  GUI/Qt/Windows/LayerInspectorDialog.h
+  GUI/Qt/Windows/LabelSelectionPopup.h
+  GUI/Qt/Windows/MainControlPanel.h
+  GUI/Qt/Windows/MainImageWindow.h
+  GUI/Qt/Windows/PreferencesDialog.h
+  GUI/Qt/Windows/ReorientImageDialog.h
+  GUI/Qt/Windows/ResampleDialog.h
+  GUI/Qt/Windows/SaveModifiedLayersDialog.h
+  GUI/Qt/Windows/SimpleFileDialogWithHistory.h
+  GUI/Qt/Windows/SnakeParameterDialog.h
+  GUI/Qt/Windows/SpeedImageDialog.h
+  GUI/Qt/Windows/SplashPanel.h
+  GUI/Qt/Windows/StatisticsDialog.h
+  GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.h
+  GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.h
+  GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.h
+  Testing/GUI/Qt/SNAPTestQt.h
+)
+
+# These UI headers don't need to be MOC'd
+SET(UI_NONMOC_HEADERS
+  GUI/Qt/Components/SNAPQtCommon.h
+  GUI/Qt/Components/QtCursorOverride.h
+  GUI/Qt/Components/QtRendererPlatformSupport.h
+  GUI/Qt/Components/QtReporterDelegates.h
+  GUI/Qt/Coupling/QtAbstractButtonCoupling.h
+  GUI/Qt/Coupling/QtAbstractItemViewCoupling.h
+  GUI/Qt/Coupling/QtActionCoupling.h
+  GUI/Qt/Coupling/QtCheckBoxCoupling.h
+  GUI/Qt/Coupling/QtColorWheelCoupling.h
+  GUI/Qt/Coupling/QtComboBoxCoupling.h
+  GUI/Qt/Coupling/QtDoubleSliderWithEditorCoupling.h
+  GUI/Qt/Coupling/QtDoubleSpinBoxCoupling.h
+  GUI/Qt/Coupling/QtLabelCoupling.h
+  GUI/Qt/Coupling/QtLineEditCoupling.h
+  GUI/Qt/Coupling/QtListWidgetCoupling.h
+  GUI/Qt/Coupling/QtRadioButtonCoupling.h
+  GUI/Qt/Coupling/QtScrollbarCoupling.h
+  GUI/Qt/Coupling/QtSliderCoupling.h
+  GUI/Qt/Coupling/QtSpinBoxCoupling.h
+  GUI/Qt/Coupling/QtTableWidgetCoupling.h
+  GUI/Qt/Coupling/QtWidgetArrayCoupling.h
+  GUI/Qt/Coupling/QtWidgetCoupling.h
+)
+
+SET(UI_FORMS
+  GUI/Qt/Components/CollapsableGroupBox.ui
+  GUI/Qt/Components/ColorMapInspector.ui
+  GUI/Qt/Components/ContrastInspector.ui
+  GUI/Qt/Components/CursorInspector.ui
+  GUI/Qt/Components/DisplayLayoutInspector.ui
+  GUI/Qt/Components/FileChooserPanelWithHistory.ui
+  GUI/Qt/Components/ImageInfoInspector.ui
+  GUI/Qt/Components/LabelInspector.ui
+  GUI/Qt/Components/LabelMiniInspector.ui
+  GUI/Qt/Components/LayerInspectorRowDelegate.ui
+  GUI/Qt/Components/MetadataInspector.ui
+  GUI/Qt/Components/GeneralLayerInspector.ui
+  GUI/Qt/Components/PaintbrushToolPanel.ui
+  GUI/Qt/Components/QDoubleSliderWithEditor.ui
+  GUI/Qt/Components/QtWarningDialog.ui
+  GUI/Qt/Components/RecentHistoryItemsView.ui
+  GUI/Qt/Components/SliceViewPanel.ui
+  GUI/Qt/Components/SnakeToolROIPanel.ui
+  GUI/Qt/Components/SnakeWizardPanel.ui
+  GUI/Qt/Components/SynchronizationInspector.ui
+  GUI/Qt/Components/ViewPanel3D.ui
+  GUI/Qt/Components/ZoomInspector.ui
+  GUI/Qt/Windows/AboutDialog.ui
+  GUI/Qt/Windows/DropActionDialog.ui
+  GUI/Qt/Windows/ImageIODialog.ui
+  GUI/Qt/Windows/LabelEditorDialog.ui
+  GUI/Qt/Windows/LayerInspectorDialog.ui
+  GUI/Qt/Windows/LabelSelectionPopup.ui
+  GUI/Qt/Windows/MainControlPanel.ui
+  GUI/Qt/Windows/MainImageWindow.ui
+  GUI/Qt/Windows/PreferencesDialog.ui
+  GUI/Qt/Windows/ReorientImageDialog.ui
+  GUI/Qt/Windows/ResampleDialog.ui
+  GUI/Qt/Windows/SaveModifiedLayersDialog.ui
+  GUI/Qt/Windows/SimpleFileDialogWithHistory.ui
+  GUI/Qt/Windows/SnakeParameterDialog.ui
+  GUI/Qt/Windows/SpeedImageDialog.ui
+  GUI/Qt/Windows/SplashPanel.ui
+  GUI/Qt/Windows/StatisticsDialog.ui
+  GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.ui
+  GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.ui
+  GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.ui
+)
+
+SET(UI_RESOURCES
+  GUI/Qt/Resources/SNAPResources.qrc
+  Testing/GUI/Qt/TestingScripts.qrc
 )
 
 # The source code for SNAP testing project
 SET(TESTING_CXX
-  Testing/TestMain.cxx
-  Testing/SNAPTestDriver.cxx
+  Testing/Logic/TestMain.cxx
+  Testing/Logic/SNAPTestDriver.cxx
 )
 
 # The source code for the tutorial test
 SET(TESTING_TUTORIAL_CXX
-  Testing/TutorialTest.cxx
+  Testing/Logic/TutorialTest.cxx
 )
 
 # The headers for the testing code
 SET(TESTING_HEADERS
-  Testing/SNAPTestDriver.h
-  Testing/TestBase.h
-  Testing/TestCompareLevelSets.h
-  Testing/TestImageWrapper.h
-)
-
-# The FL files for SNAP
-SET(APPLICATION_FLUIDS
-  UserInterface/ImageIOWizard/ImageIOWizard.fl
-  UserInterface/MeshIOWizard/MeshIOWizardUI.fl
-  UserInterface/MainComponents/AppearanceDialogUI.fl
-  UserInterface/MainComponents/HelpViewer.fl
-  UserInterface/MainComponents/LabelEditorUI.fl
-  UserInterface/MainComponents/LayerInspectorUI.fl
-  UserInterface/MainComponents/PreprocessingUI.fl
-  UserInterface/MainComponents/ReorientImageUI.fl
-  UserInterface/MainComponents/ResizeRegionDialog.fl
-  UserInterface/MainComponents/RestoreSettingsDialog.fl
-  UserInterface/MainComponents/SimpleFileDialog.fl
-  UserInterface/MainComponents/SnakeParametersUI.fl
-  UserInterface/MainComponents/UserInterface.fl
+  Testing/Logic/SNAPTestDriver.h
+  Testing/Logic/TestBase.h
+  Testing/Logic/TestCompareLevelSets.h
+  Testing/Logic/TestImageWrapper.h
 )
 
-#############################################
-# LIBRARIES AND EXTERNAL CODE               #
-#############################################
+#--------------------------------------------------------------------------------
+# Specify include path
+#--------------------------------------------------------------------------------
 
 # Due to a limitation in Visual studio 6.0 on the length of include directories
 # that can be specified, (here we are including all the include directories from
@@ -382,27 +750,20 @@ IF( CMAKE_GENERATOR MATCHES "Visual Studio 6" )
   FILE( GLOB_RECURSE SNAP_GLOBBED_CXX "${SNAP_SOURCE_DIR}/*.cxx" )
   FILE( GLOB_RECURSE SNAP_GLOBBED_H "${SNAP_SOURCE_DIR}/*.h" )
   FILE( GLOB_RECURSE SNAP_GLOBBED_TXX "${SNAP_SOURCE_DIR}/*.txx" )
-  SET( SNAP_SOURCES
-            ${SNAP_GLOBBED_CXX}
-            ${SNAP_GLOBBED_H}
-            ${SNAP_GLOBBED_TXX}
-     )
+  SET(SNAP_SOURCES ${SNAP_GLOBBED_CXX} ${SNAP_GLOBBED_H} ${SNAP_GLOBBED_TXX})
   MAKE_DIRECTORY( "${SNAP_BINARY_DIR}/src" )
   SET( CONFIGURED_SOURCE_DIRECTORY "${SNAP_BINARY_DIR}/src" )
   FOREACH( SourceFile ${SNAP_SOURCES} )
     GET_FILENAME_COMPONENT( CONFIGURED_SOURCE_FILE ${SourceFile} NAME )
     SET( CONFIGURED_SOURCE_FILE "${CONFIGURED_SOURCE_DIRECTORY}/${CONFIGURED_SOURCE_FILE}" )
-    CONFIGURE_FILE( ${SourceFile} ${CONFIGURED_SOURCE_FILE}
-                     COPYONLY IMMEDIATE )
+    CONFIGURE_FILE( ${SourceFile} ${CONFIGURED_SOURCE_FILE} COPYONLY IMMEDIATE )
   ENDFOREACH( SourceFile )
   INCLUDE_DIRECTORIES(
     ${CONFIGURED_SOURCE_DIRECTORY}
     ${ITK_DIR}/Utilities/zlib
-    ${SNAP_BINARY_DIR}/UserInterface/ImageIOWizard
-    ${SNAP_BINARY_DIR}/UserInterface/MainComponents
-    ${FLTK_INCLUDE_PATH}
     ${OPENGL_INCLUDE_PATH}
-  )
+    ${QT_QTSCRIPT_INCLUDE_DIR}
+    ${QT_QTSCRIPTTOOLS_INCLUDE_DIR})
 
 ELSE( CMAKE_GENERATOR MATCHES "Visual Studio 6" )
 
@@ -418,58 +779,72 @@ ELSE( CMAKE_GENERATOR MATCHES "Visual Studio 6" )
     ${SNAP_SOURCE_DIR}/Logic/LevelSet
     ${SNAP_SOURCE_DIR}/Logic/Mesh
     ${SNAP_SOURCE_DIR}/Logic/Preprocessing
+    ${SNAP_SOURCE_DIR}/Logic/Preprocessing/GMM
+    ${SNAP_SOURCE_DIR}/Logic/Preprocessing/RandomForest
     ${SNAP_SOURCE_DIR}/Logic/Slicing
-    ${SNAP_SOURCE_DIR}/Testing
-    ${SNAP_SOURCE_DIR}/UserInterface/BasicComponents
-    ${SNAP_SOURCE_DIR}/UserInterface/Common
-    ${SNAP_SOURCE_DIR}/UserInterface/ImageIOWizard
-    ${SNAP_SOURCE_DIR}/UserInterface/MeshIOWizard
-    ${SNAP_SOURCE_DIR}/UserInterface/MainComponents
-    ${SNAP_SOURCE_DIR}/UserInterface/MainComponents/Artwork
-    ${SNAP_SOURCE_DIR}/UserInterface/SliceWindow
-    ${SNAP_SOURCE_DIR}/UserInterface/Window3D
-    ${SNAP_BINARY_DIR}/UserInterface/ImageIOWizard
-    ${SNAP_BINARY_DIR}/UserInterface/MainComponents
-    ${FLTK_INCLUDE_PATH}
+    ${SNAP_SOURCE_DIR}/GUI
+    ${SNAP_SOURCE_DIR}/GUI/Model
+    ${SNAP_SOURCE_DIR}/GUI/Renderer
+    ${SNAP_SOURCE_DIR}/GUI/Renderer/OrientationWidget/Reorient
+    ${SNAP_SOURCE_DIR}/GUI/Qt
+    ${SNAP_SOURCE_DIR}/GUI/Qt/Components
+    ${SNAP_SOURCE_DIR}/GUI/Qt/Coupling
+    ${SNAP_SOURCE_DIR}/GUI/Qt/External
+    ${SNAP_SOURCE_DIR}/GUI/Qt/External/ColorWheel
+    ${SNAP_SOURCE_DIR}/GUI/Qt/ModelView
+    ${SNAP_SOURCE_DIR}/GUI/Qt/Testing
+    ${SNAP_SOURCE_DIR}/GUI/Qt/View
+    ${SNAP_SOURCE_DIR}/GUI/Qt/Windows
+    ${SNAP_SOURCE_DIR}/GUI/Qt/Windows/MeshExportWizard
+    ${SNAP_SOURCE_DIR}/Testing/Logic
+    ${SNAP_SOURCE_DIR}/Testing/GUI/Qt
+    ${SNAP_BINARY_DIR}
     ${OPENGL_INCLUDE_PATH}
+    ${SNAP_QT5_INCLUDE_DIRS}
   )
 
 ENDIF( CMAKE_GENERATOR MATCHES "Visual Studio 6" )
 
+#--------------------------------------------------------------------------------
+# Compiler-specific warinings
+#--------------------------------------------------------------------------------
+
 # Get rid of this ridiculous warning in VS8
-IF( CMAKE_GENERATOR MATCHES "Visual Studio 8" OR CMAKE_GENERATOR MATCHES "Visual Studio 9")
+IF( CMAKE_GENERATOR MATCHES "Visual Studio 8" OR CMAKE_GENERATOR MATCHES "Visual Studio 9" OR CMAKE_GENERATOR MATCHES "Visual Studio 10" )
   ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
-ENDIF( CMAKE_GENERATOR MATCHES "Visual Studio 8" OR CMAKE_GENERATOR MATCHES "Visual Studio 9")
+ENDIF( CMAKE_GENERATOR MATCHES "Visual Studio 8" OR CMAKE_GENERATOR MATCHES "Visual Studio 9" OR CMAKE_GENERATOR MATCHES "Visual Studio 10" )
   
-# ----------------------------------------------------------------
+IF( CMAKE_GENERATOR MATCHES "^NMake" OR CMAKE_GENERATOR MATCHES "^Visual Studio" )
+  ADD_DEFINITIONS(-DNOMINMAX)
+ENDIF( CMAKE_GENERATOR MATCHES "^NMake" OR CMAKE_GENERATOR MATCHES "^Visual Studio" )
+
+#--------------------------------------------------------------------------------
 # Define External Libraries
-# ----------------------------------------------------------------
+#--------------------------------------------------------------------------------
 
 # ITK Libraries
-SET(SNAP_ITK_LIBS
-  ITKIO
-)
+SET(SNAP_ITK_LIBS ${ITK_LIBRARIES})
 
 # Core VTK libraries
-SET(SNAP_VTK_CORE_LIBS
-  vtkCommon
-  vtkRendering
-  vtkFiltering
-  vtkGraphics
-  vtkImaging
-  vtkIO
+SET(SNAP_VTK_LIBS
+  vtkChartsCore
+  vtkCommonCore
+  vtkRenderingCore
+  vtkRenderingFreeType
+  vtkRenderingFreeTypeOpenGL
+  vtkRenderingOpenGL
+  vtkRenderingVolume
+  vtkRenderingVolumeOpenGL
+  vtkFiltersCore
+  vtkImagingCore
+  vtkViewsCore
+  vtkViewsContext2D
+  vtkIOCore
+  vtkIOExport
+  vtkIOGeometry
+  vtkIOLegacy
 )
 
-# VTK Libraries with possible inclusion of patented code
-IF(VTK_USE_PATENTED)
-  SET(SNAP_VTK_LIBS vtkPatented ${SNAP_VTK_CORE_LIBS})
-ELSE(VTK_USE_PATENTED)
-  SET(SNAP_VTK_LIBS ${SNAP_VTK_CORE_LIBS})
-ENDIF(VTK_USE_PATENTED)
-
-# FLTK Related libraries
-SET(SNAP_FLTK_LIBS ${FLTK_LIBRARIES})
-
 # System libraries
 SET(SNAP_SYSTEM_LIBS
   ${OPENGL_LIBRARIES}
@@ -479,62 +854,166 @@ SET(SNAP_SYSTEM_LIBS
 
 # Designate the external libraries used by SNAP
 SET(SNAP_EXTERNAL_LIBS 
-  ${SNAP_FLTK_LIBS} 
   ${SNAP_ITK_LIBS} 
   ${SNAP_VTK_LIBS} 
-  ${SNAP_SYSTEM_LIBS})
+  ${SNAP_SYSTEM_LIBS}
+)
 
-# *****************************************************
-# SNAP Logic and UI Libraries
-# *****************************************************
+#--------------------------------------------------------------------------------
+# Define SNAP library targets (logic and UI)
+#--------------------------------------------------------------------------------
 
-# Wrap the .fl files
-FLTK_WRAP_UI(itksnapui ${APPLICATION_FLUIDS})
+# Wrap the QT input files
+QT5_WRAP_UI(UI_FORM_HEADERS ${UI_FORMS})
+QT5_WRAP_CPP(UI_WRAPPED_MOC_HEADERS ${UI_MOC_HEADERS})
+QT5_ADD_RESOURCES(UI_RESOURCES_RCC ${UI_RESOURCES})
 
 # The SNAP logic library
 ADD_LIBRARY(itksnaplogic ${LOGIC_CXX} ${LOGIC_HEADERS})
 
+# The UI model library
+ADD_LIBRARY(itksnapui_model ${UI_GENERIC_CXX} ${UI_GENERIC_HEADERS})
+
 # The user interface code library
-ADD_LIBRARY(itksnapui ${UI_CXX} ${UI_HEADERS} ${itksnapui_FLTK_UI_SRCS})
+ADD_LIBRARY(itksnapui_qt
+  ${UI_QT_CXX} ${UI_WRAPPED_MOC_HEADERS} ${UI_MOC_HEADERS} 
+  ${UI_NONMOC_HEADERS} ${UI_FORM_HEADERS} ${UI_RESOURCES_RCC})
 
 # This is experimental: it seems that shared libraries do not
 # build accurately (at least on MacOS) without the following
 # two lines
 TARGET_LINK_LIBRARIES(itksnaplogic ${SNAP_EXTERNAL_LIBS})
-TARGET_LINK_LIBRARIES(itksnapui itksnaplogic ${SNAP_EXTERNAL_LIBS})
+TARGET_LINK_LIBRARIES(itksnapui_model itksnaplogic ${SNAP_EXTERNAL_LIBS})
+TARGET_LINK_LIBRARIES(itksnapui_qt ${SNAP_QT5_LIBRARIES} ${SNAP_EXTERNAL_LIBS})
 
 # Designate the SNAP internal libraries
-SET(SNAP_INTERNAL_LIBS itksnapui itksnaplogic)
+SET(SNAP_INTERNAL_LIBS itksnapui_qt itksnapui_model itksnaplogic)
+
+#--------------------------------------------------------------------------------
+# Define main SNAP executable
+#--------------------------------------------------------------------------------
+
+# Code for the main application
+SET(SNAP_MAIN_SRC GUI/Qt/main.cxx)
+
+# On Apple, configure the application icon
+IF(APPLE)
+
+  # the icon file
+  SET(SNAP_OSX_ICON ${SNAP_SOURCE_DIR}/Utilities/MacOS/BundleResources/itksnap.icns)
 
-# *****************************************************
-# Define SNAP Executables
-# *****************************************************
-SET(SNAP_EXE InsightSNAP)
+  # set how it shows up in the Info.plist file
+  SET(MACOSX_BUNDLE_ICON_FILE itksnap.icns) 
+  
+  # set where in the bundle to put the icns file
+  SET_SOURCE_FILES_PROPERTIES(${SNAP_OSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
+
+  # include the icns file in the target
+  SET(SNAP_MAIN_SRC ${SNAP_MAIN_SRC} ${SNAP_OSX_ICON})
+
+ENDIF(APPLE)
+
+# On Windows, add the .RC file to the sources
+IF(WIN32)
+
+  # Add the .rc file
+  SET(SNAP_MAIN_SRC ${SNAP_MAIN_SRC} ${SNAP_SOURCE_DIR}/Utilities/Win32/itksnap.rc)
+
+ENDIF(WIN32)
 
-# Disable FLTK warnings
-#ITK_DISABLE_FLTK_GENERATED_WARNINGS("${APPLICATION_FLUIDS}")
 
 # Define the main SNAP executable
-ADD_EXECUTABLE(${SNAP_EXE} WIN32 UserInterface/SNAPMain.cxx)
-TARGET_LINK_LIBRARIES(${SNAP_EXE}
+SET(SNAP_BUNDLE_NAME ITK-SNAP)
+
+# Configure the executable's sources and libraries
+ADD_EXECUTABLE(${SNAP_BUNDLE_NAME} WIN32 MACOSX_BUNDLE ${SNAP_MAIN_SRC})
+TARGET_LINK_LIBRARIES(${SNAP_BUNDLE_NAME} ${SNAP_INTERNAL_LIBS} ${SNAP_EXTERNAL_LIBS})
+
+# On apple, we also need our custom plist.info file to be configured
+IF(APPLE)
+  SET_TARGET_PROPERTIES(${SNAP_BUNDLE_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST
+    ${SNAP_SOURCE_DIR}/Utilities/MacOS/BundleResources/Info.plist)
+ENDIF(APPLE)
+
+#--------------------------------------------------------------------------------
+# Testing-related executables
+#--------------------------------------------------------------------------------
+
+ENABLE_TESTING()
+
+include(BundleUtilities)
+
+# The list of Qt animated GUI tests
+SET(GUI_TESTS
+  Workspace
+  ProbeIntensity
+  RegionCompetition
+  RandomForest)
+
+SET(TESTDATA_DIR "${SNAP_SOURCE_DIR}/Testing/TestData")
+
+# Set up a test for each GUI test
+FOREACH(GUI_TEST ${GUI_TESTS})
+
+  # The path of the test - not obvious?
+  IF(APPLE)
+    GET_PROPERTY(GUI_TEST_EXE TARGET ${SNAP_BUNDLE_NAME} PROPERTY LOCATION)
+  ELSE(APPLE)
+    SET(GUI_TEST_EXE ${SNAP_BUNDLE_NAME})
+  ENDIF(APPLE)
+    
+  # Add the test
+  ADD_TEST(${GUI_TEST} ${GUI_TEST_EXE} --test ${GUI_TEST} --testdir "${TESTDATA_DIR}")
+
+  # Set the environment for the test to include Qt
+  FILE(TO_NATIVE_PATH ${QT_BINARY_DIR} QT_BINARY_DIR_NATIVE)
+
+  IF(WIN32)
+    SET_PROPERTY(TEST ${GUI_TEST} APPEND PROPERTY ENVIRONMENT PATH=${QT_BINARY_DIR_NATIVE})
+  ELSE(WIN32)
+    SET_PROPERTY(TEST ${GUI_TEST} APPEND PROPERTY ENVIRONMENT PATH="${QT_BINARY_DIR_NATIVE}:$ENV{PATH}")
+  ENDIF(WIN32)
+  SET_PROPERTY(TEST ${GUI_TEST} PROPERTY TIMEOUT 120)
+
+ENDFOREACH(GUI_TEST)
+
+# Orientation widget test
+SET(TEST_ORIENTATION_WIDGET_HEADERS
+  GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.h
+)
+
+SET(TEST_ORIENTATION_WIDGET_CXX
+  GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.cxx
+  GUI/Renderer/OrientationWidget/Test_OrientationWidget/main.cxx
+)
+
+QT5_WRAP_UI(UI_ORIENTATION_WIDGET_SRCS 
+  GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.ui)
+QT5_WRAP_CPP(MOC_ORIENTATION_WIDGET_SRCS 
+  GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.h)
+
+ADD_EXECUTABLE(Test_OrientationWidget
+  ${TEST_ORIENTATION_WIDGET_CXX} ${TEST_ORIENTATION_WIDGET_HEADERS}
+  ${UI_ORIENTATION_WIDGET_SRCS} ${MOC_ORIENTATION_WIDGET_SRCS}
+)
+
+TARGET_LINK_LIBRARIES(Test_OrientationWidget
   ${SNAP_INTERNAL_LIBS}
   ${SNAP_EXTERNAL_LIBS}
-  )
+)
 
-# Define the testing EXE
-ADD_EXECUTABLE(snaptest ${TESTING_CXX})
-TARGET_LINK_LIBRARIES(snaptest
-  ${SNAP_INTERNAL_LIBS}
-  ${SNAP_EXTERNAL_LIBS})
+INCLUDE(CTest)
+
+#--------------------------------------------------------------------------------
+# Copy and configure the program data directory
+#--------------------------------------------------------------------------------
 
-# ----------------------------------------------------------------
-# Miscelaneous tasks (not related to link and compilation)
-# ----------------------------------------------------------------
 # All program files - use recursive globbing
-FILE(GLOB_RECURSE PROGRAM_DATA_FILES ProgramData "*.txt" "*.html" "*.gif" "*.png" "*.img.gz" "*.hdr")
+FILE(GLOB_RECURSE SNAP_PROGRAM_DATA_FILES 
+  ProgramData "*.txt" "*.html" "*.gif" "*.png" "*.img.gz" "*.hdr")
 
 # Copy documentation from the source tree to the build tree
-FOREACH(DATAFILE ${PROGRAM_DATA_FILES})
+FOREACH(DATAFILE ${SNAP_PROGRAM_DATA_FILES})
   FILE(RELATIVE_PATH SHORTNAME ${SNAP_SOURCE_DIR} ${DATAFILE})
   CONFIGURE_FILE(
     ${SNAP_SOURCE_DIR}/${SHORTNAME}
@@ -542,125 +1021,171 @@ FOREACH(DATAFILE ${PROGRAM_DATA_FILES})
    COPYONLY)
 ENDFOREACH(DATAFILE)
 
-#########################################################
-# INSTALLATION AND PACKAGING with CPack                 #
-#########################################################
-INCLUDE(CMake/CustomBuildSettings.cmake)
+#--------------------------------------------------------------------------------
+# INSTALLATION AND PACKAGING SECTION
+#--------------------------------------------------------------------------------
 
-# Generate forward shared executable
-SUBDIRS(Utilities/Forwarding)
+MESSAGE(STATUS "=== Installation Section ===")
+MESSAGE(STATUS "   CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}")
+MESSAGE(STATUS "   CMAKE_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}")
+MESSAGE(STATUS "   PACKAGE_DIR ${CPACK_PACKAGE_DIRECTORY}")
+MESSAGE(STATUS "   INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}")
+MESSAGE(STATUS "   DESTDIR $ENV{DESTDIR}")
 
-# Install the SNAP executable in the appropriate place.
+#--------------------------------------------------------------------------------
+# Install the application
 
-# Windows (Microsoft Visual Studio)
-IF(WIN32 AND NOT UNIX)
-  INSTALL(TARGETS ${SNAP_EXE} RUNTIME DESTINATION bin)
-  SET(SNAP_DATA_INSTALL_DIR ".")
-ENDIF(WIN32 AND NOT UNIX)
-
-# Apple
 IF(APPLE)
-  # Copy executable into the bundle
-  SET(SNAP_MAIN_INSTALL_DIR ITK-SNAP.app/Contents/MacOS)
-  SET(SNAP_DATA_INSTALL_DIR ${SNAP_MAIN_INSTALL_DIR})
-  INSTALL(TARGETS ${SNAP_EXE} RUNTIME DESTINATION ${SNAP_MAIN_INSTALL_DIR})
 
-  # Configure the XML file
-  CONFIGURE_FILE(
-    ${SNAP_SOURCE_DIR}/Utilities/MacOS/BundleResources/Info.plist
-    ${SNAP_BINARY_DIR}/Utilities/MacOS/BundleResources/Info.plist)
-  INSTALL(FILES ${SNAP_BINARY_DIR}/Utilities/MacOS/BundleResources/Info.plist
-    DESTINATION ITK-SNAP.app/Contents) 
-  INSTALL(FILES ${SNAP_SOURCE_DIR}/Utilities/MacOS/BundleResources/itksnap.icns
-    DESTINATION ITK-SNAP.app/Contents/Resources)
-ENDIF(APPLE)
+  # on Apple, the bundle is at the root of the
+  # install tree, and on other platforms it'll go into the bin directory.
+  INSTALL(TARGETS ${SNAP_BUNDLE_NAME} 
+      BUNDLE DESTINATION . COMPONENT Runtime)
 
-# Other UNIX
-IF(UNIX AND NOT APPLE)
-  SET(SNAP_MAIN_INSTALL_DIR lib/snap-${SNAP_VERSION_FULL})
-  SET(SNAP_DATA_INSTALL_DIR ${SNAP_MAIN_INSTALL_DIR})
-  INSTALL(TARGETS ${SNAP_EXE} RUNTIME DESTINATION ${SNAP_MAIN_INSTALL_DIR})
-ENDIF(UNIX AND NOT APPLE)
-
-# Install the Program Data files
-INSTALL(DIRECTORY ${SNAP_BINARY_DIR}/ProgramData DESTINATION ${SNAP_DATA_INSTALL_DIR})
-
-# On Win32, we must include the redistributable
-IF(MSVC80 OR MSVC90)
-  FIND_PROGRAM(VCREDIST_EXE vcredist_x86.exe vcredist_x64.exe)
-  IF(VCREDIST_EXE)
-    GET_FILENAME_COMPONENT(VCREDIST_NAME ${VCREDIST_EXE} NAME)
-    INSTALL(FILES ${VCREDIST_EXE} DESTINATION bin)
-    SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS 
-      "ExecWait '\\\"$INSTDIR\\\\bin\\\\${VCREDIST_NAME}\\\" /q:a'")
-  ENDIF(VCREDIST_EXE)
-ENDIF(MSVC80 OR MSVC90)
-
-# Allow package generation
-SET(CPACK_PACKAGE_NAME "itksnap")
-SET(CPACK_PACKAGE_CONTACT "Paul A. Yushkevich")
-SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "ITK-SNAP 3D Image Segmentation Tool")
-SET(CPACK_PACKAGE_VENDOR "itksnap.org")
-SET(CPACK_PACKAGE_VERSION_MAJOR "${SNAP_VERSION_MAJOR}")
-SET(CPACK_PACKAGE_VERSION_MINOR "${SNAP_VERSION_MINOR}")
-SET(CPACK_PACKAGE_VERSION_PATCH "${SNAP_VERSION_PATCH}")
-SET(CPACK_PACKAGE_INSTALL_DIRECTORY "itksnap-${SNAP_VERSION_FULL}")
-
-# Show GPL license
-SET(CPACK_RESOURCE_FILE_LICENSE "${SNAP_SOURCE_DIR}/COPYING")
+  # On apple, we put a binary script along with a README file
+  INSTALL(FILES
+          ${SNAP_SOURCE_DIR}/Utilities/MacOS/BundleResources/itksnap
+          DESTINATION . COMPONENT Runtime
+          PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
+                      GROUP_EXECUTE GROUP_READ)
+
+  # Try adding a link to /usr/local/bin
+  INSTALL(CODE "EXECUTE_PROCESS(COMMAND ln -sf /usr/local/bin usr_local_bin WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX})")
+
+  INSTALL(FILES
+          ${SNAP_SOURCE_DIR}/Utilities/MacOS/BundleResources/README.txt
+          DESTINATION . COMPONENT Runtime)
+
+  #INSTALL(FILES
+  #        ${SNAP_BINARY_DIR}/usr_local_bin
+  #        DESTINATION . COMPONENT Runtime)
+
+  # Set the DS STORE
+  SET(CPACK_DMG_DS_STORE ${SNAP_SOURCE_DIR}/Utilities/MacOS/BundleResources/dsstore.bin)
+  SET(CPACK_DMG_BACKGROUND_IMAGE ${SNAP_SOURCE_DIR}/Utilities/MacOS/BundleResources/background.png)
 
-IF(WIN32 AND NOT UNIX)
+  # Include the qt4 dependent libraries
+  include(DeployQt5)
 
-  # There is a bug in NSI that does not handle full unix paths properly. Make
-  # sure there is at least one set of four (4) backlasshes.
-  SET(CPACK_GENERATOR "NSIS")
-  SET(CPACK_NSIS_INSTALLED_ICON_NAME "InsightSNAP.exe")
+  # Make sure the GIF plugin is included
+  get_property(QT_GIF_PLUGIN TARGET Qt5::QGifPlugin PROPERTY LOCATION_RELEASE)
+
+  # Install with the plugin
+  install_qt5_executable(${SNAP_BUNDLE_NAME}.app "${QT_GIF_PLUGIN}")
+
+ELSEIF(WIN32)
+
+  # Install to the bin directory
+  INSTALL(TARGETS ${SNAP_BUNDLE_NAME} RUNTIME DESTINATION bin)
+
+  # Include the qt4 dependent libraries
+  include(DeployQt5)
+
+  # Make sure the GIF plugin is included
+  get_property(QT_WIN_PLUGIN TARGET Qt5::QWindowsIntegrationPlugin PROPERTY LOCATION_RELEASE)
+  get_property(QT_GIF_PLUGIN TARGET Qt5::QGifPlugin PROPERTY LOCATION_RELEASE)
+
+  # Install with the plugin
+  install_qt5_executable(bin/${SNAP_BUNDLE_NAME}.exe "${QT_GIF_PLUGIN};${QT_WIN_PLUGIN}")
+
+  # On windows, we have to configure NSIS
+  SET(CPACK_NSIS_INSTALLED_ICON_NAME "ITK-SNAP.exe")
   SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} ITK-SNAP")
   SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.itksnap.org")
   SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.itksnap.org/credits.php")
   SET(CPACK_NSIS_MODIFY_PATH OFF)
-  
+
+  # CMake does not yet know to install into (x64) program files or not
+  IF(CMAKE_CL_64)
+    SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
+  ENDIF(CMAKE_CL_64)
+
   # Give it a windowsy directory name
   SET(CPACK_PACKAGE_INSTALL_DIRECTORY "ITK-SNAP ${SNAP_VERSION_MAJOR}.${SNAP_VERSION_MINOR}")
   
   # On Win32, the executable is the actual exe
-  SET(CPACK_PACKAGE_EXECUTABLES InsightSNAP "ITK-SNAP")
-  
-ELSE(WIN32 AND NOT UNIX)
+  SET(CPACK_PACKAGE_EXECUTABLES ITK-SNAP "ITK-SNAP")
+
+  # On Win32, we must include the redistributable
+  IF(MSVC_VERSION GREATER 1399)
+    FIND_PROGRAM(VCREDIST_EXE vcredist_x86.exe vcredist_x64.exe)
+    IF(VCREDIST_EXE)
+      GET_FILENAME_COMPONENT(VCREDIST_NAME ${VCREDIST_EXE} NAME)
+      INSTALL(FILES ${VCREDIST_EXE} DESTINATION bin)
+      SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS 
+        "ExecWait '\\\"$INSTDIR\\\\bin\\\\${VCREDIST_NAME}\\\" /passive'")
+    ENDIF(VCREDIST_EXE)
+  ENDIF(MSVC_VERSION GREATER 1399)
 
-  # Set the generator to either STGZ or Apple
-  IF(NOT APPLE)
-    SET(CPACK_GENERATOR "TGZ")
-  ELSE(NOT APPLE)
-    SET(CPACK_GENERATOR "ZIP")
-  ENDIF(NOT APPLE)
+ELSE()
 
-  # Executable is the forward sharing exe
+  # On Linux, we generate forward shared executable
+  SUBDIRS(Utilities/Forwarding)
+
+  SET(SNAP_EXE "ITK-SNAP")
+  SET(SNAP_MAIN_INSTALL_DIR lib/snap-${SNAP_VERSION_FULL})
+  SET(SNAP_DATA_INSTALL_DIR ${SNAP_MAIN_INSTALL_DIR})
   SET(CPACK_PACKAGE_EXECUTABLES "itksnap" "ITK-SNAP")
+  INSTALL(TARGETS ${SNAP_BUNDLE_NAME} RUNTIME DESTINATION ${SNAP_MAIN_INSTALL_DIR})
+
+  # Include the qt4 dependent libraries
+  include(DeployQt5)
 
-ENDIF(WIN32 AND NOT UNIX)
+  # Add an option to not package QT plugins. This is needed for some special builds,
+  # for example on Debian
+  OPTION(SNAP_PACKAGE_QT_PLUGINS "Try to package Qt5 plugins with the executable" ON)
+  MARK_AS_ADVANCED(SNAP_PACKAGE_QT_PLUGINS)
 
-# Figure out the extension of the binary
-MESSAGE(STATUS "Generator: ${CPACK_GENERATOR}")
-IF(CPACK_GENERATOR STREQUAL "NSIS")
+  # Get the necessary plugins
+  IF(SNAP_PACKAGE_QT_PLUGINS)
+
+    get_property(QT_XCB_PLUGIN TARGET Qt5::QXcbIntegrationPlugin PROPERTY LOCATION_RELEASE)
+    get_property(QT_GIF_PLUGIN TARGET Qt5::QGifPlugin PROPERTY LOCATION_RELEASE)
+
+    # Install the plugin
+    install_qt5_executable(${SNAP_MAIN_INSTALL_DIR}/${SNAP_EXE} "${QT_XCB_PLUGIN};${QT_GIF_PLUGIN}")
+
+  ELSE(SNAP_PACKAGE_QT_PLUGINS)
+
+    # Install the exe without plugins
+    install_qt5_executable(${SNAP_MAIN_INSTALL_DIR}/${SNAP_EXE})
+
+  ENDIF(SNAP_PACKAGE_QT_PLUGINS)
+
+ENDIF()
+
+
+#--------------------------------------------------------------------------------
+# Configure CPack
+
+# Which generator to use
+IF(APPLE)
+  SET(CPACK_GENERATOR DragNDrop)
+  SET(CPACK_EXTENSION "dmg")
+ELSEIF(WIN32)
+  SET(CPACK_GENERATOR NSIS)
   SET(CPACK_EXTENSION "exe")
-ELSEIF(CPACK_GENERATOR STREQUAL "ZIP")
-  SET(CPACK_EXTENSION "zip")
-ELSEIF(CPACK_GENERATOR STREQUAL "TGZ")
+ELSE(APPLE)
+  SET(CPACK_GENERATOR TGZ)
   SET(CPACK_EXTENSION "tar.gz")
-ENDIF(CPACK_GENERATOR STREQUAL "NSIS")
+ENDIF(APPLE)
 
-# The filename of the installable package
-SET(CPACK_TARGET_FILENAME ${CPACK_SOURCE_PACKAGE_FILE_NAME}-${CPACK_SYSTEM_NAME}.${CPACK_EXTENSION})
-SET(CPACK_TARGET ${SNAP_BINARY_DIR}/${CPACK_TARGET_FILENAME})
+#--------------------------------------------------------------------------------
+# Construct the name of the package
+SET(CPACK_PACKAGE_FILE_NAME_WEXT "${CPACK_PACKAGE_FILE_NAME}.${CPACK_EXTENSION}")
 
-# Call CPACK
-INCLUDE(CPack)
-INCLUDE(CTest)
 
-#########################################################
-# Automatic Uploading of Nightly Packages               #
-#########################################################
+#--------------------------------------------------------------------------------
+# Set up package target
+include(CPack)
+
+#--------------------------------------------------------------------------------
+# Uploading code to SourceForge
+#--------------------------------------------------------------------------------
+
+#--------------------------------------------------------------------------------
+# Configure SCP
+
 FIND_PROGRAM(SCP_PROGRAM NAMES scp DOC "Location of the scp program (optional)")
 MARK_AS_ADVANCED(SCP_PROGRAM)
 
@@ -670,19 +1195,25 @@ MARK_AS_ADVANCED(SCP_ARGUMENTS)
 SET(SCP_USERNAME "" CACHE STRING "SourceForge.net account id for uploads")
 MARK_AS_ADVANCED(SCP_USERNAME)
 
-SET(NIGHTLY_TARGET "itksnap-nightly-${CPACK_SYSTEM_NAME}.${CPACK_EXTENSION}")
+SET(NIGHTLY_TARGET "itksnap-3.2-dev-nightly-${CPACK_SYSTEM_NAME}.${CPACK_EXTENSION}")
 
 SET(SCP_ROOT "frs.sourceforge.net:/home/frs/project/i/it/itk-snap/itk-snap")
 
+#--------------------------------------------------------------------------------
+# Create targets
+
 ADD_CUSTOM_TARGET(upload_nightly 
-  VERBATIM COMMAND "${SCP_PROGRAM}" ${SCP_ARGUMENTS} ${CPACK_TARGET_FILENAME} ${SCP_USERNAME},itk-snap@${SCP_ROOT}/Nightly/${NIGHTLY_TARGET}
+  VERBATIM COMMAND "${SCP_PROGRAM}" ${SCP_ARGUMENTS}
+  ${CPACK_PACKAGE_FILE_NAME_WEXT} ${SCP_USERNAME},itk-snap@${SCP_ROOT}/Nightly/${NIGHTLY_TARGET}
   DEPENDS ${CPACK_TARGET}
   WORKING_DIRECTORY ${SNAP_BINARY_DIR}
-  COMMENT "Uploading package ${CPACK_TARGET} to SourceForge.net as ${NIGHTLY_TARGET}")
+  COMMENT "Uploading package ${CPACK_PACKAGE_FILE_NAME_WEXT} to SourceForge.net as ${NIGHTLY_TARGET}")
 
 ADD_CUSTOM_TARGET(upload_experimental 
-  VERBATIM COMMAND "${SCP_PROGRAM}" ${SCP_ARGUMENTS} ${CPACK_TARGET_FILENAME} ${SCP_USERNAME},itk-snap@${SCP_ROOT}/Experimental
+  VERBATIM COMMAND "${SCP_PROGRAM}" ${SCP_ARGUMENTS} 
+    ${CPACK_PACKAGE_FILE_NAME_WEXT} ${SCP_USERNAME},itk-snap@${SCP_ROOT}/Experimental/
   DEPENDS ${CPACK_TARGET}
   WORKING_DIRECTORY ${SNAP_BINARY_DIR}
-  COMMENT "Uploading package ${CPACK_TARGET} to SourceForge.net to Experimental directory")
+  COMMENT "Uploading package ${CPACK_PACKAGE_FILE_NAME_WEXT} to SourceForge.net to Experimental directory")
+
 
diff --git a/CTestConfig.cmake b/CTestConfig.cmake
index 08da9c0..e65ddc2 100644
--- a/CTestConfig.cmake
+++ b/CTestConfig.cmake
@@ -4,10 +4,10 @@
 ## # The following are required to uses Dart and the Cdash dashboard
 ##   ENABLE_TESTING()
 ##   INCLUDE(Dart)
-set(CTEST_PROJECT_NAME "ITK-SNAP")
-set(CTEST_NIGHTLY_START_TIME "01:00:00 EST")
+set(CTEST_PROJECT_NAME "ITK-SNAP 3.2")
+set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
 
 set(CTEST_DROP_METHOD "http")
 set(CTEST_DROP_SITE "itksnap.org")
-set(CTEST_DROP_LOCATION "/cdash/submit.php?project=ITK-SNAP")
+set(CTEST_DROP_LOCATION "/cdash/submit.php?project=ITK-SNAP+3.2")
 set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/Common/AbstractModel.cxx b/Common/AbstractModel.cxx
new file mode 100644
index 0000000..e9df180
--- /dev/null
+++ b/Common/AbstractModel.cxx
@@ -0,0 +1,130 @@
+#include "AbstractModel.h"
+#include "EventBucket.h"
+
+#include <IRISException.h>
+#include <vtkObject.h>
+#include <vtkCommand.h>
+
+#include "SNAPEventListenerCallbacks.h"
+
+
+AbstractModel::AbstractModel()
+  : itk::Object()
+{
+  m_EventBucket = new EventBucket();
+}
+
+AbstractModel::~AbstractModel()
+{
+  // Cleanup
+  delete m_EventBucket;
+  for(std::list<Rebroadcaster *>::iterator it = m_Rebroadcast.begin();
+      it != m_Rebroadcast.end(); ++it)
+    {
+    delete *it;
+    }
+}
+
+void AbstractModel::Update()
+{
+  if(!m_EventBucket->IsEmpty())
+    {
+#ifdef SNAP_DEBUG_EVENTS
+    if(flag_snap_debug_events)
+      {
+      std::cout << "UPDATE called in model " << this->GetNameOfClass()
+                << " [" << this << "] "
+                << " with " << *m_EventBucket << std::endl << std::flush;
+      }
+#endif
+    this->OnUpdate();
+    m_EventBucket->Clear();
+    }
+}
+
+
+AbstractModel::Rebroadcaster
+::Rebroadcaster(AbstractModel *model, const itk::EventObject &evt)
+{          
+  m_Model = model;
+  m_Event = evt.MakeObject();
+}
+
+AbstractModel::Rebroadcaster
+::~Rebroadcaster()
+{
+  delete m_Event;
+}
+
+void
+AbstractModel::Rebroadcaster
+::Broadcast(itk::Object *source, const itk::EventObject &evt)
+{
+  this->Broadcast((const itk::Object *) source, evt);
+}
+
+void
+AbstractModel::Rebroadcaster
+::Broadcast(const itk::Object *source, const itk::EventObject &evt)
+{
+#ifdef SNAP_DEBUG_EVENTS
+  if(flag_snap_debug_events)
+    {
+    std::cout << "REBROADCAST event " <<  evt.GetEventName()
+              << " from " << source->GetNameOfClass()
+              << " [" << source << "] "
+              << " as " << m_Event->GetEventName()
+              << " from " << m_Model->GetNameOfClass()
+              << " [" << m_Model << "] "
+              << std::endl << std::flush;
+    }
+#endif // SNAP_DEBUG_EVENTS
+  m_Model->m_EventBucket->PutEvent(evt, source);
+  m_Model->InvokeEvent(*m_Event);
+}
+
+void
+AbstractModel::Rebroadcaster
+::BroadcastVTK(vtkObject *source, unsigned long event, void *)
+{
+#ifdef SNAP_DEBUG_EVENTS
+  if(flag_snap_debug_events)
+    {
+    std::cout << "REBROADCAST VTK event "
+              <<  vtkCommand::GetStringFromEventId(event)
+              << " from " << source->GetClassName()
+              << " [" << source << "] "
+              << " as " << m_Event->GetEventName()
+              << " from " << m_Model->GetNameOfClass()
+              << " [" << m_Model << "] "
+              << std::endl << std::flush;
+    }
+#endif // SNAP_DEBUG_EVENTS
+
+  // TODO: how to package this up for the bucket?
+  m_Model->m_EventBucket->PutEvent(VTKEvent(), NULL);
+  m_Model->InvokeEvent(*m_Event);
+}
+
+#include "Rebroadcaster.h"
+
+unsigned long
+AbstractModel::Rebroadcast(
+    itk::Object *src, const itk::EventObject &srcEvent, const itk::EventObject &trgEvent)
+{
+  /*
+  Rebroadcaster *reb = new Rebroadcaster(this, trgEvent);
+  m_Rebroadcast.push_back(reb);
+  return AddListenerPair(src, srcEvent, reb, &Rebroadcaster::Broadcast, &Rebroadcaster::Broadcast);
+  */
+  return ::Rebroadcaster::Rebroadcast(src, srcEvent, this, trgEvent, m_EventBucket);
+}
+
+unsigned long
+AbstractModel::Rebroadcast(
+    vtkObject *src, unsigned long srcEvent, const itk::EventObject &trgEvent)
+{
+  Rebroadcaster *reb = new Rebroadcaster(this, trgEvent);
+  m_Rebroadcast.push_back(reb);
+  return AddListenerVTK(src, srcEvent, reb, &Rebroadcaster::BroadcastVTK);
+}
diff --git a/Common/AbstractModel.h b/Common/AbstractModel.h
new file mode 100644
index 0000000..b71b5fe
--- /dev/null
+++ b/Common/AbstractModel.h
@@ -0,0 +1,111 @@
+#ifndef ABSTRACTMODEL_H
+#define ABSTRACTMODEL_H
+
+#include "itkObject.h"
+#include "itkObjectFactory.h"
+#include "SNAPCommon.h"
+#include "SNAPEvents.h"
+#include "EventBucket.h"
+#include <set>
+#include <string>
+
+class vtkObject;
+
+
+/**
+  \class AbstractModel
+  \brief Parent class for all UI models
+
+  This class provides basic common functionality for all UI models. This
+  includes the event/update mechanism.
+  */
+class AbstractModel : public itk::Object
+{
+public:
+  /*
+  typedef AbstractModel                  Self;
+  typedef itk::Object                    Superclass;
+  typedef itk::SmartPointer<Self>        Pointer;
+  typedef itk::SmartPointer<const Self>  ConstPointer;
+
+  itkTypeMacro(AbstractModel, itk::Object)
+
+  itkNewMacro(Self)
+  */
+
+  irisITKObjectMacro(AbstractModel, itk::Object)
+
+
+  /**
+    Call this function to update the model based on events that have been
+    fired since the last time the model was updated. This function simply
+    checks if the event bucket is empty; if not, it calls the OnUpdate()
+    protected virtual method. Subclassers should reimplement OnUpdate(). The
+    event bucket is emptied at the end of this call.
+    */
+  void Update();
+
+
+  /**
+    Listen to events of type srcEvent on the object src, and rebroadcast
+    them as event trgEvent. In the process, record the srcEvent in the
+    event bucket. This is the main mechanism for model updates. The model
+    listens to events occurring upstream. When an event occurs, the model
+    only records the event and invokes its own event, to which the view
+    objects downstream are listening. It is then the view's responsibility
+    to call the Update() function on the model. This function checks what
+    events are in the event bucket, and processes them in an orderly fashion.
+    */
+  unsigned long Rebroadcast(
+      itk::Object *src, const itk::EventObject &srcEvent,
+      const itk::EventObject &trgEvent);
+
+  /**
+   We can also rebroadcast events from vtk objects. This is handled similar
+   to ITK but events are just unsigned long values. The event bucket will
+   include a VTKEvent() object with NULL caller if an event from VTK occurred.
+   (at the present, EventBucket does not support differentiating between different
+   kinds of VTK events and callers).
+   */
+  unsigned long Rebroadcast(vtkObject *src, unsigned long srcEvent,
+      const itk::EventObject &trgEvent);
+
+
+protected:
+
+  AbstractModel();
+  virtual ~AbstractModel();
+
+  /**
+    Helper class for AbstractModel used to rebroadcast events
+    */
+  class Rebroadcaster
+  {
+  public:
+    Rebroadcaster(AbstractModel *model, const itk::EventObject &evt);
+    virtual ~Rebroadcaster();
+
+    void Broadcast(itk::Object *source, const itk::EventObject &evt);
+    void Broadcast(const itk::Object *source, const itk::EventObject &evt);
+
+    void BroadcastVTK(vtkObject *source, unsigned long event, void *);
+
+  private:
+    AbstractModel *m_Model;
+    itk::EventObject *m_Event;
+  };
+
+  /**
+    This is the method called by Update() if there are events in the
+    event bucket
+    */
+  virtual void OnUpdate() {}
+
+  // List of rebroadcasters
+  std::list<Rebroadcaster *> m_Rebroadcast;
+
+  // Bucket that stores events fired since last call to Update()
+  EventBucket *m_EventBucket;
+};
+
+#endif // ABSTRACTMODEL_H
diff --git a/Common/AbstractPropertyContainerModel.cxx b/Common/AbstractPropertyContainerModel.cxx
new file mode 100644
index 0000000..d12879d
--- /dev/null
+++ b/Common/AbstractPropertyContainerModel.cxx
@@ -0,0 +1,86 @@
+#include "AbstractPropertyContainerModel.h"
+
+void
+AbstractPropertyContainerModel::DeepCopy(
+    const AbstractPropertyContainerModel *source)
+{
+  // This method will only work if both models have the same fields in the
+  // same order. The assertions below check that
+  assert(m_Properties.size() == source->m_Properties.size());
+
+  PropertyMapCIter itSrc = source->m_Properties.begin();
+  PropertyMapIter it = m_Properties.begin();
+  while(itSrc != source->m_Properties.end())
+    {
+    assert(it->first == itSrc->first);
+    ConcretePropertyHolderBase *ptr_src = itSrc->second;
+    ConcretePropertyHolderBase *ptr_trg = it->second;
+    ptr_trg->DeepCopy(ptr_src);
+    ++it; ++itSrc;
+    }
+}
+
+bool AbstractPropertyContainerModel::operator == (
+    const AbstractPropertyContainerModel &source)
+{
+  // This method will only work if both models have the same fields in the
+  // same order. The assertions below check that
+  assert(m_Properties.size() == source.m_Properties.size());
+
+  PropertyMapCIter itSrc = source.m_Properties.begin();
+  PropertyMapIter it = m_Properties.begin();
+  while(itSrc != source.m_Properties.end())
+    {
+    assert(it->first == itSrc->first);
+    ConcretePropertyHolderBase *ptr_src = itSrc->second;
+    ConcretePropertyHolderBase *ptr_trg = it->second;
+    if(!ptr_trg->Equals(ptr_src))
+      return false;
+    ++it; ++itSrc;
+    }
+
+  return true;
+}
+
+bool AbstractPropertyContainerModel::operator != (
+    const AbstractPropertyContainerModel &source)
+{
+  return !(*this == source);
+}
+
+unsigned long AbstractPropertyContainerModel::GetMTime() const
+{
+  return this->GetTimeStamp().GetMTime();
+}
+
+void AbstractPropertyContainerModel::WriteToRegistry(Registry &folder) const
+{
+  for(PropertyMapCIter it = m_Properties.begin(); it != m_Properties.end(); it++)
+    {
+    it->second->Serialize(folder);
+    }
+}
+
+void AbstractPropertyContainerModel::ReadFromRegistry(Registry &folder)
+{
+  for(PropertyMapIter it = m_Properties.begin(); it != m_Properties.end(); it++)
+    {
+    it->second->Deserialize(folder);
+    }
+
+  // Flag this object as modified
+  this->Modified();
+}
+
+
+const itk::TimeStamp &AbstractPropertyContainerModel::GetTimeStamp() const
+{
+  const itk::TimeStamp *ts = &AbstractModel::GetTimeStamp();
+  for(PropertyMapCIter it = m_Properties.begin(); it != m_Properties.end(); it++)
+    {
+    const itk::TimeStamp &tschild = it->second->GetPropertyTimeStamp();
+    if(tschild > (*ts))
+      ts = &tschild;
+    }
+  return *ts;
+}
diff --git a/Common/AbstractPropertyContainerModel.h b/Common/AbstractPropertyContainerModel.h
new file mode 100644
index 0000000..3cced22
--- /dev/null
+++ b/Common/AbstractPropertyContainerModel.h
@@ -0,0 +1,360 @@
+#ifndef ABSTRACTPROPERTYCONTAINERMODEL_H
+#define ABSTRACTPROPERTYCONTAINERMODEL_H
+
+#include "PropertyModel.h"
+#include "Registry.h"
+
+/**
+ * A helper class for AbstractPropertyContainerModel. This is a typeless parent
+ * for ConcretePropertyHolder.
+ */
+class ConcretePropertyHolderBase : public itk::Object
+{
+public:
+  irisITKAbstractObjectMacro(ConcretePropertyHolderBase, itk::Object)
+
+  virtual void DeepCopy(const ConcretePropertyHolderBase *source) = 0;
+  virtual bool Equals(const ConcretePropertyHolderBase *other) = 0;
+  virtual void Serialize(Registry &folder) const = 0;
+  virtual void Deserialize(Registry &folder) = 0;
+  virtual const itk::TimeStamp &GetPropertyTimeStamp() const = 0;
+};
+
+template <class TAtomic>
+class DefaultRegistrySerializationTraits
+{
+public:
+  void Serialize(RegistryValue &entry, const TAtomic &value) const
+  {
+    entry << value;
+  }
+  void Deserialize(RegistryValue &entry, TAtomic &value, const TAtomic &deflt) const
+  {
+    value = entry[deflt];
+  }
+};
+
+template <class TAtomic>
+class RegistryEnumSerializationTraits
+{
+public:
+  typedef RegistryEnumMap<TAtomic> EnumMap;
+  typedef RegistryEnumSerializationTraits<TAtomic> Self;
+
+  RegistryEnumSerializationTraits() {}
+
+  RegistryEnumSerializationTraits(const EnumMap &enummap)
+    : m_EnumMap(enummap) {}
+
+  RegistryEnumSerializationTraits(const Self &other)
+    : m_EnumMap(other.m_EnumMap) {}
+
+  void Serialize(RegistryValue &entry, const TAtomic &value) const
+  {
+    entry.PutEnum(m_EnumMap, value);
+  }
+  void Deserialize(RegistryValue &entry, TAtomic &value, const TAtomic &deflt) const
+  {
+    value = entry.GetEnum(m_EnumMap, deflt);
+  }
+
+private:
+  EnumMap m_EnumMap;
+};
+
+
+
+/**
+ * A helper class for AbstractPropertyContainerModel that holds a pointer to
+ * a ConcretePointerModel and supports copy and serialization operations.
+ */
+template <class TAtomic, class TDomain, class TRegistryTraits>
+class ConcretePropertyHolder : public ConcretePropertyHolderBase
+{
+public:
+  // ITK stuff
+  typedef ConcretePropertyHolder<TAtomic, TDomain, TRegistryTraits> Self;
+  typedef ConcretePropertyHolderBase Superclass;
+  typedef SmartPtr<Self> Pointer;
+  typedef SmartPtr<const Self> ConstPointer;
+
+  itkTypeMacro(ConcretePropertyHolder, ConcretePropertyHolderBase)
+  itkNewMacro(Self)
+
+  // Held property type
+  typedef ConcretePropertyModel<TAtomic, TDomain> PropertyType;
+
+  virtual void DeepCopy(const ConcretePropertyHolderBase *source)
+  {
+    const Self *source_cast = static_cast<const Self *>(source);
+    PropertyType *source_prop = source_cast->m_Property;
+    m_Property->DeepCopy(source_prop);
+  }
+
+  virtual bool Equals(const ConcretePropertyHolderBase *other)
+  {
+    const Self *source_cast = static_cast<const Self *>(other);
+    PropertyType *source_prop = source_cast->m_Property;
+    return m_Property->Equals(source_prop);
+  }
+
+  virtual void Serialize(Registry &folder) const
+  {
+    TAtomic value;
+    if(m_Property->GetValueAndDomain(value, NULL))
+      {
+      m_Traits.Serialize(folder.Entry(m_RegistryKey), value);
+      }
+  }
+
+  virtual void Deserialize(Registry &folder)
+  {
+    RegistryValue &rv = folder.Entry(m_RegistryKey);
+    if(!rv.IsNull())
+      {
+      TAtomic value;
+      m_Traits.Deserialize(rv, value, m_Property->GetValue());
+      m_Property->SetValue(value);
+      }
+  }
+
+  virtual const itk::TimeStamp &GetPropertyTimeStamp() const
+  {
+    return m_Property->GetTimeStamp();
+  }
+
+
+  irisGetSetMacro(Property, PropertyType *)
+  irisGetSetMacro(RegistryKey, const std::string &)
+  irisGetSetMacro(Traits, const TRegistryTraits &)
+
+protected:
+
+  // Pointer to the property
+  SmartPtr<PropertyType> m_Property;
+
+  // Registry key for serialization
+  std::string m_RegistryKey;
+
+  // A traits object for serialization
+  TRegistryTraits m_Traits;
+};
+
+
+/**
+ * This class is intended to serve as a parent class for models that hold
+ * a (large) number of individual ConcretePropertyModel objects. For example,
+ * we may want a FooSettings class that holds a bunch of properties that
+ * influence the behavior of Foo. Normally, one would write a struct with
+ * these different fields:
+ *
+ *   struct FooSettings {
+ *     int FooWidth;
+ *     double FooAspectRatio;
+ *     bool IsFooable;
+ *   }
+ *
+ * However, in the model/view paradigm in ITK-SNAP, we want each of the fields
+ * to be represented by a PropertyModel so that observers can listen to changes
+ * in the individual fields, and so that the fields can be hooked up to GUI
+ * widgets. So instead, FooSettings is represented like this:
+ *
+ *    class FooSettingsModel : public AbstractModel
+ *    {
+ *    public:
+ *      ...
+ *      irisRangedPropertyAccessMacro(FooWidth, int)
+ *      irisRangedPropertyAccessMacro(FooAspectRatio, double)
+ *      irisSimplePropertyAccessMacro(IsFooable, bool)
+ *    protected:
+ *      ...
+ *      SmartPtr<ConcreteRangedIntProperty> m_FooWidth;
+ *      SmartPtr<ConcreteRangedDoubleProperty> m_FooAspectRatio;
+ *      SmartPtr<ConcreteSimpleBooleanProperty> m_IsFooable;
+ *    }
+ *
+ * However, this class does not automatically offer comparison operators or
+ * means to copy the model (deep copy). Writing that code by hand is a pain,
+ * especially when there are lots of fields. So this is where the class
+ * AbstractPropertyContainerModel comes in. It allows the fields to be registered
+ * in the constructor, and provides default implementations of the comparison
+ * operators and DeepCopy function.
+ *
+ * The class AbstractPropertyContainerModel is a way to create a container of
+ * heterogeneous property models that supports comparison, serialization, and
+ * copy operations with little coding. The FooSettingsModel class will still have
+ * a similar structure to the one above.
+ *
+ *    class FooSettingsModel : public AbstractPropertyContainerModel
+ *    {
+ *    public:
+ *      ...
+ *      irisRangedPropertyAccessMacro(FooWidth, int)
+ *      irisRangedPropertyAccessMacro(FooAspectRatio, double)
+ *      irisSimplePropertyAccessMacro(IsFooable, bool)
+ *    protected:
+ *      ...
+ *      SmartPtr<ConcreteRangedIntProperty> m_FooWidth;
+ *      SmartPtr<ConcreteRangedDoubleProperty> m_FooAspectRatio;
+ *      SmartPtr<ConcreteSimpleBooleanProperty> m_IsFooable;
+ *    }
+ *
+ * The difference is that in the constructor, when the properties are created
+ * using the NewSimpleProperty/NewRangedProperty methods, they are automatically
+ * added to an internal list, allowing comparison, copy, and serialization.
+ *
+ *    FooSettingsModel::FooSettingsModel
+ *    {
+ *      m_FooWidth = NewRangedProperty("FooWidth", 2, 0, 4, 1);
+ *      m_FooAspectRatio = NewSimpleProperty("FooAspectRatio", 0.25, 0.0, 1.0, 0.01);
+ *      m_IsFooable = NewSimpleProperty("FooWidth", true);
+ *    }
+ */
+class AbstractPropertyContainerModel : public AbstractModel
+{
+public:
+  irisITKObjectMacro(AbstractPropertyContainerModel, AbstractModel)
+
+  FIRES(ChildPropertyChangedEvent)
+
+  void DeepCopy(const AbstractPropertyContainerModel *source);
+
+  virtual bool operator == (const AbstractPropertyContainerModel &source);
+
+  virtual bool operator != (const AbstractPropertyContainerModel &source);
+
+  /** Return this objects modified time. This will return the latest of our
+   * own modified time and the modified times of all the children */
+  virtual unsigned long GetMTime() const;
+
+  virtual const itk::TimeStamp &GetTimeStamp() const;
+
+  void WriteToRegistry(Registry &folder) const;
+
+  void ReadFromRegistry(Registry &folder);
+
+protected:
+
+  // Register a child model with this class. This should be called in the
+  // constructor when the model is created. The model should be a concrete
+  // property model. This method should only be called in the constructor
+  template <class TAtomic, class TDomain>
+  SmartPtr< ConcretePropertyModel<TAtomic, TDomain> >
+  RegisterProperty(const std::string &key,
+                   SmartPtr< ConcretePropertyModel<TAtomic, TDomain> > model)
+  {
+    typedef DefaultRegistrySerializationTraits<TAtomic> RegTraits;
+    typedef ConcretePropertyHolder<TAtomic, TDomain, RegTraits> HolderType;
+    SmartPtr<HolderType> holder = HolderType::New();
+    holder->SetProperty(model);
+    holder->SetRegistryKey(key);
+	m_Properties.insert(std::make_pair((std::string)key, (HolderPointer)holder));
+
+    // Propagate the modification events from the property
+    Rebroadcast(model, ValueChangedEvent(), ChildPropertyChangedEvent());
+    Rebroadcast(model, DomainChangedEvent(), ChildPropertyChangedEvent());
+
+    return model;
+  }
+
+  // Register a child model with an enum atomic type. The third parameter is
+  // the enum-to-string mapping used to serialize the enum.
+  template <class TAtomic, class TDomain>
+  SmartPtr< ConcretePropertyModel<TAtomic, TDomain> >
+  RegisterEnumProperty(const std::string &key,
+                       SmartPtr< ConcretePropertyModel<TAtomic, TDomain> > model,
+                       const RegistryEnumMap<TAtomic> &enummap)
+  {
+    typedef RegistryEnumSerializationTraits<TAtomic> RegTraits;
+    RegTraits traits(enummap);
+
+    typedef ConcretePropertyHolder<TAtomic, TDomain, RegTraits> HolderType;
+    SmartPtr<HolderType> holder = HolderType::New();
+    holder->SetProperty(model);
+    holder->SetRegistryKey(key);
+    holder->SetTraits(traits);
+
+	m_Properties.insert(std::make_pair((std::string)key, (HolderPointer)holder));
+
+    // Propagate the modification events from the property
+    Rebroadcast(model, ValueChangedEvent(), ChildPropertyChangedEvent());
+    Rebroadcast(model, DomainChangedEvent(), ChildPropertyChangedEvent());
+
+    return model;
+  }
+
+  // A convenience method that creates a new simple concrete property and
+  // then registers it using RegisterModel
+  template <class TAtomic>
+  SmartPtr< ConcretePropertyModel<TAtomic, TrivialDomain> >
+  NewSimpleProperty(const std::string &key, const TAtomic &value)
+  {
+    return RegisterProperty(key, NewSimpleConcreteProperty(value));
+  }
+
+  // A convenience method that creates a new simple concrete property and
+  // then registers it using RegisterModel
+  template <class TAtomic>
+  SmartPtr< ConcretePropertyModel<TAtomic, NumericValueRange<TAtomic> > >
+  NewRangedProperty(const std::string &key,
+                    const TAtomic &value,
+                    const TAtomic &minval,
+                    const TAtomic &maxval,
+                    const TAtomic &step)
+  {
+    return RegisterProperty(key, NewRangedConcreteProperty(value, minval, maxval, step));
+  }
+
+  // A convenience method that creates a new simple concrete property and
+  // then registers it using RegisterModel
+  template <class TAtomic>
+  SmartPtr< ConcretePropertyModel<TAtomic, TrivialDomain> >
+  NewSimpleEnumProperty(const std::string &key, const TAtomic &value,
+                        const RegistryEnumMap<TAtomic> &enummap)
+  {
+    return RegisterEnumProperty(key, NewSimpleConcreteProperty(value), enummap);
+  }
+
+private:
+
+  // The storage for the fields
+  typedef SmartPtr<ConcretePropertyHolderBase> HolderPointer;
+  typedef std::map<std::string, HolderPointer> PropertyMap;
+  typedef PropertyMap::iterator PropertyMapIter;
+  typedef PropertyMap::const_iterator PropertyMapCIter;
+
+  PropertyMap m_Properties;
+
+};
+
+/*
+ * These typedefs are commented out because I felt that they made the code too
+ * hard to read. They can reduce coding, but can sow confusion.
+ *
+#define apcmRangedPropertyAccessMacro(name,type) \
+  virtual AbstractPropertyModel<type, NumericValueRange<type> > * Get##name##Model () const \
+    { return GetProperty<type, NumericValueRange<type> >("##name##"); } \
+  virtual void Set##name (type _arg) \
+    { this->Get##name##Model()->SetValue(_arg); } \
+  virtual type Get##name () const \
+    { return this->Get##name##Model()->GetValue(); }
+
+#define apcmSimplePropertyAccessMacro(name,type) \
+  virtual AbstractPropertyModel<type, TrivialDomain > * Get##name##Model () const \
+    { return GetProperty<type, TrivialDomain >("##name##"); } \
+  virtual void Set##name (type _arg) \
+    { this->Get##name##Model()->SetValue(_arg); } \
+  virtual type Get##name () const \
+    { return this->Get##name##Model()->GetValue(); }
+
+#define apcmGenericPropertyAccessMacro(name,type,domaintype) \
+  virtual AbstractPropertyModel<type, domaintype > * Get##name##Model () const \
+    { return GetProperty<type, domaintype >("##name##"); } \
+  virtual void Set##name (type _arg) \
+    { this->Get##name##Model()->SetValue(_arg); } \
+  virtual type Get##name () const \
+    { return this->Get##name##Model()->GetValue(); }
+*/
+
+
+#endif // ABSTRACTPROPERTYCONTAINERMODEL_H
diff --git a/Common/CommandLineArgumentParser.cxx b/Common/CommandLineArgumentParser.cxx
index e75c6d0..b8488f8 100644
--- a/Common/CommandLineArgumentParser.cxx
+++ b/Common/CommandLineArgumentParser.cxx
@@ -108,7 +108,7 @@ CommandLineArgumentParser
 
     // Check if the number of parameters is correct
     int nParameters = m_OptionMap[arg].NumberOfParameters;
-    if(argc_out+nParameters >= argc) 
+    if(nParameters > 0 && argc_out+nParameters >= argc)
       {
       // Too few parameters
       cerr << "Too few parameters to command line option '" << arg 
@@ -116,13 +116,22 @@ CommandLineArgumentParser
       return false;
       }
 
+    // If the number of parameters is negative, read all parameters that are
+    // not recognized options
+    if(nParameters < 0)
+      {
+      nParameters = 0;
+      for(int j = argc_out+1; j < argc; j++, nParameters++)
+        if(m_OptionMap.find(argv[j]) != m_OptionMap.end())
+          break;
+      }
+
     // Tell the result that the option has been encountered
     outResult.AddOption(m_OptionMap[arg].CommonName,nParameters);
 
     // Pass in the parameters
     for(int j=0;j<nParameters;j++,argc_out++)
       outResult.AddParameter(m_OptionMap[arg].CommonName,string(argv[argc_out+1]));
-    
     }
 
   // Everything is good
@@ -148,6 +157,14 @@ CommandLineArgumentParseResult
   return m_OptionMap[string(option)][number].c_str();
 }
 
+int
+CommandLineArgumentParseResult
+::GetNumberOfOptionParameters(const char *option)
+{
+  assert(IsOptionPresent(option));
+  return m_OptionMap[string(option)].size();
+}
+
 void  
 CommandLineArgumentParseResult
 ::Clear()
diff --git a/Common/CommandLineArgumentParser.h b/Common/CommandLineArgumentParser.h
index 8b0ae4a..87575f6 100644
--- a/Common/CommandLineArgumentParser.h
+++ b/Common/CommandLineArgumentParser.h
@@ -59,11 +59,22 @@ public:
   /** Get one of the parameters to the option */
   const char *GetOptionParameter(const char *option, unsigned int number = 0);
 
+  /** Get the number of parameters for the option */
+  int GetNumberOfOptionParameters(const char *option);
+
 private:
   typedef std::vector< std::string > ParameterArrayType;
   typedef std::map< std::string, ParameterArrayType> OptionMapType;
 
   void Clear();
+
+  /**
+   * @brief Add an option with specified number of parameters. The number of
+   * parameters may be negative, in which case all non-options trailing the
+   * command are read as parameters.
+   * @param option
+   * @param nParms
+   */
   void AddOption(const std::string &option, int nParms);
   void AddParameter(const std::string &option, const std::string &parameter);
 
diff --git a/Common/EventBucket.cxx b/Common/EventBucket.cxx
new file mode 100644
index 0000000..7219f2c
--- /dev/null
+++ b/Common/EventBucket.cxx
@@ -0,0 +1,80 @@
+#include "EventBucket.h"
+
+unsigned long EventBucket::m_GlobalMTime = 1;
+
+EventBucket::EventBucket()
+{
+  m_MTime = m_GlobalMTime++;
+}
+
+EventBucket::~EventBucket()
+{
+  Clear();
+}
+
+void EventBucket::Clear()
+{
+  m_Lock.Lock();
+  // Remove all the event objects
+  for(BucketIt it = m_Bucket.begin(); it != m_Bucket.end(); ++it)
+    {
+    delete(it->first);
+    }
+  m_Bucket.clear();
+  m_Lock.Unlock();
+
+  m_MTime = m_GlobalMTime++;
+}
+
+bool EventBucket::HasEvent(const itk::EventObject &evt, const itk::Object *source) const
+{
+  m_Lock.Lock();
+  // Search for the event. Buckets are never too large so a linear search is fine
+  for(BucketIt it = m_Bucket.begin(); it != m_Bucket.end(); ++it)
+    {
+    const BucketEntry &entry = *it;
+    std::string echeck = evt.GetEventName();
+    std::string eentry = entry.first->GetEventName();
+    if(evt.CheckEvent(entry.first) && (source == NULL || source == entry.second))
+      {
+      m_Lock.Unlock();
+      return true;
+      }
+    }
+
+  m_Lock.Unlock();
+  return false;
+}
+
+bool EventBucket::IsEmpty() const
+{
+  return m_Bucket.size() == 0;
+}
+
+void EventBucket::PutEvent(const itk::EventObject &evt, const itk::Object *source)
+{
+  if(!this->HasEvent(evt, source))
+    {
+    BucketEntry entry;
+    entry.first = evt.MakeObject();
+    entry.second = source;
+    m_Lock.Lock();
+    m_Bucket.insert(entry);
+    m_Lock.Unlock();
+    m_MTime = m_GlobalMTime++;
+    }
+}
+
+std::ostream& operator<<(std::ostream& sink, const EventBucket& eb)
+{
+  sink << "EventBucket[";
+  for(EventBucket::BucketIt it = eb.m_Bucket.begin(); it != eb.m_Bucket.end();)
+    {
+    sink << it->first->GetEventName() << "(" << it->second << ")";
+    if(++it != eb.m_Bucket.end())
+      sink << ", ";
+    }
+  sink << "]";
+  return sink;
+}
+
diff --git a/Common/EventBucket.h b/Common/EventBucket.h
new file mode 100644
index 0000000..f6487eb
--- /dev/null
+++ b/Common/EventBucket.h
@@ -0,0 +1,75 @@
+#ifndef EVENTBUCKET_H
+#define EVENTBUCKET_H
+
+#include "SNAPEvents.h"
+#include "itkSimpleFastMutexLock.h"
+#include <set>
+#include <iostream>
+
+namespace itk
+{
+class Object;
+}
+
+/**
+  A simple 'bucket' that stores events. You can easily add events to
+  the bucket and check if events are present there.
+
+  TODO: the bucket should keep track of objects that fired the event,
+  not only the event types!
+  */
+class EventBucket
+{
+public:
+
+  EventBucket();
+
+  virtual ~EventBucket();
+
+  /**
+   * @brief Add an event to the bucket.
+   */
+  void PutEvent(const itk::EventObject &evt, const itk::Object *source);
+
+  /**
+   * @brief Check if the bucket has an event from a source (or from all
+   * sources if the second parameter has the default value of NULL). This
+   * method checks for child events, so if AEvent is a parent BEvent and the
+   * bucket holds a BEvent, then HasEvent(AEvent()) will return true.
+   */
+  bool HasEvent(const itk::EventObject &evt, const itk::Object *source = NULL) const;
+
+  bool IsEmpty() const;
+
+  void Clear();
+
+  unsigned long GetMTime() const { return m_MTime; }
+
+  friend std::ostream& operator<<(std::ostream& sink, const EventBucket& eb);
+
+protected:
+
+  /**
+   * The bucket entry consists of a pointer to the event, which the
+   * bucket owns and destroys when it is destroyed or cleared, and the
+   * pointer to the originator the event.
+   */
+  typedef std::pair<itk::EventObject *, const itk::Object *> BucketEntry;
+  typedef std::set<BucketEntry> BucketType;
+  typedef BucketType::iterator BucketIt;
+
+  BucketType m_Bucket;
+  itk::SimpleFastMutexLock m_Lock;
+
+  /** Each bucket has a unique id. This allows code to check whether or not
+   * it has already handled a bucket or not. This should not really be needed
+   * because event handlers should never get called twice with the same
+   * bucket, but it seems that in Qt this does happen sometimes */
+  unsigned long m_MTime;
+  static unsigned long m_GlobalMTime;
+};
+
+// IO operator
+std::ostream& operator<<(std::ostream& sink, const EventBucket& eb);
+
+#endif // EVENTBUCKET_H
diff --git a/Common/GPUSettings.h.in b/Common/GPUSettings.h.in
new file mode 100644
index 0000000..cca7436
--- /dev/null
+++ b/Common/GPUSettings.h.in
@@ -0,0 +1,2 @@
+#cmakedefine SNAP_USE_GPU
+
diff --git a/Common/HistoryManager.cxx b/Common/HistoryManager.cxx
new file mode 100644
index 0000000..f2b3182
--- /dev/null
+++ b/Common/HistoryManager.cxx
@@ -0,0 +1,133 @@
+#include "HistoryManager.h"
+#include "SystemInterface.h"
+#include "Registry.h"
+#include "itksys/SystemTools.hxx"
+#include <algorithm>
+
+const unsigned int HistoryManager::HISTORY_SIZE_LOCAL = 5;
+const unsigned int HistoryManager::HISTORY_SIZE_GLOBAL = 20;
+
+HistoryManager::HistoryManager()
+{
+}
+
+HistoryManager::ConcreteHistoryModel
+*HistoryManager::GetHistory(const std::string &category, HistoryMap &hmap)
+{
+  // Does the history exist?
+  HistoryMap::iterator it = hmap.find(category);
+  if(it == hmap.end())
+    {
+    ConcreteHistoryModelPtr model = ConcreteHistoryModel::New();
+    hmap.insert(std::make_pair(category, model));
+    return model;
+    }
+  else return it->second;
+}
+
+void HistoryManager
+::SaveHistory(Registry &folder, HistoryManager::HistoryMap &hmap)
+{
+  // Write all the histories to the registry
+  for(HistoryMap::iterator it = hmap.begin(); it != hmap.end(); it++)
+    {
+    ConcreteHistoryModel *model = it->second;
+    folder.Folder(it->first).PutArray(model->GetValue());
+    }
+}
+
+void HistoryManager
+::LoadHistory(Registry &folder, HistoryManager::HistoryMap &hmap)
+{
+  hmap.clear();
+
+  // Read all the relevant histories from the file. We do this dynamically
+  // although it would also have made sense to hard code here the list of
+  // all histories. I guess it does not really matter.
+  Registry::StringListType historyNames;
+  folder.GetFolderKeys(historyNames);
+  for(Registry::StringListType::iterator it = historyNames.begin();
+      it != historyNames.end(); it++)
+    {
+    // Histories are created on demand - so we must call the get model method,
+    // which will create and store the history model
+    ConcreteHistoryModel *model = GetHistory(*it, hmap);
+    model->SetValue(folder.Folder(*it).GetArray(std::string("")));
+    }
+}
+
+void HistoryManager
+::UpdateHistoryList(ConcreteHistoryModel *model, const std::string &file, unsigned int maxsize)
+{
+  // Get the list (passing by value here, but these lists are not huge)
+  HistoryListType array = model->GetValue();
+
+  // Remove all occurences of the file from the array
+  array.erase(std::remove(array.begin(), array.end(), file), array.end());
+
+  // Append the file to the end of the array
+  array.push_back(file);
+
+  // Trim the array to appropriate size
+  if(array.size() > maxsize)
+    array.erase(array.begin(), array.begin() + array.size() - maxsize);
+
+  // Put the new array back in the model
+  model->SetValue(array);
+}
+
+void HistoryManager::UpdateHistory(
+    const std::string &category,
+    const std::string &filename,
+    bool make_local)
+{
+  // Create a string for the new file
+  std::string fullpath = itksys::SystemTools::CollapseFullPath(filename.c_str());
+
+  // Get the current history registry
+  UpdateHistoryList(GetHistory(category, m_GlobalHistory), fullpath, HISTORY_SIZE_GLOBAL);
+  if(make_local)
+    UpdateHistoryList(GetHistory(category, m_LocalHistory), fullpath, HISTORY_SIZE_LOCAL);
+
+  // TODO: right now, no events are fired to notify changes to the HistoryManager as
+  // a whole. Also, there is no mechanism for sharing histories across sessions.
+}
+
+void HistoryManager::DeleteHistoryItem(
+    const std::string &category, const std::string &file)
+{
+  // Delete all occurences of file from the history
+  ConcreteHistoryModel *model = GetHistory(category, m_GlobalHistory);
+  HistoryListType hist = model->GetValue();
+  hist.erase(std::remove(hist.begin(), hist.end(), file), hist.end());
+  model->SetValue(hist);
+}
+
+void HistoryManager::ClearLocalHistory()
+{
+  m_LocalHistory.clear();
+}
+
+HistoryManager::AbstractHistoryModel *
+HistoryManager::GetLocalHistoryModel(const std::string &category)
+{
+  return GetHistory(category, m_LocalHistory);
+}
+
+HistoryManager::AbstractHistoryModel *
+HistoryManager::GetGlobalHistoryModel(const std::string &category)
+{
+  return GetHistory(category, m_GlobalHistory);
+}
+
+HistoryManager::HistoryListType
+HistoryManager::GetLocalHistory(const std::string &category)
+{
+  return GetHistory(category, m_LocalHistory)->GetValue();
+}
+
+HistoryManager::HistoryListType
+HistoryManager::GetGlobalHistory(const std::string &category)
+{
+  return GetHistory(category, m_GlobalHistory)->GetValue();
+}
diff --git a/Common/HistoryManager.h b/Common/HistoryManager.h
new file mode 100644
index 0000000..f0649fb
--- /dev/null
+++ b/Common/HistoryManager.h
@@ -0,0 +1,136 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: SystemInterface.h,v $
+  Language:  C++
+  Date:      $Date: 2010/04/14 10:06:23 $
+  Version:   $Revision: 1.11 $
+  Copyright (c) 2003-2013 Paul A. Yushkevich and Guido Gerig
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+
+#ifndef HISTORYMANAGER_H
+#define HISTORYMANAGER_H
+
+#include <vector>
+#include <map>
+#include <string>
+#include "PropertyModel.h"
+
+
+class SystemInterface;
+class Registry;
+
+/**
+ * @brief The HistoryManager class
+ * This class manages file IO history in the SNAP application. Starting with
+ * version 3.0, there is a global history for each kind of file (main image,
+ * segmentation, label descriptions, etc) and a history associated with each
+ * main image. This class maintains the history entries. Each history is a
+ * "PropertyModel", so other objects can register to observe changes to the
+ * history.
+ */
+class HistoryManager
+{
+public:
+
+  // Typedef for history lists
+  typedef std::vector<std::string> HistoryListType;
+
+  // Typedef for the history model
+  typedef AbstractPropertyModel<HistoryListType, TrivialDomain> AbstractHistoryModel;
+
+  /** Update the history in one of the named categories. The last parameter
+      is whether the history entry should be made local, i.e., associated
+      with the currently loaded main image. */
+  void UpdateHistory(const std::string &category,
+                     const std::string &file,
+                     bool make_local);
+
+  /** Delete an item from the global history  */
+  void DeleteHistoryItem(const std::string &category,
+                         const std::string &file);
+
+  /** Clear the local history - should be done when the main image is unloaded */
+  void ClearLocalHistory();
+
+  /** Get the model encapsulating local history */
+  AbstractHistoryModel *GetLocalHistoryModel(const std::string &category);
+
+  /** Get the model encapsulating local history */
+  AbstractHistoryModel *GetGlobalHistoryModel(const std::string &category);
+
+  /** Get the local history in a category (pass by value) */
+  HistoryListType GetLocalHistory(const std::string &category);
+
+  /** Get the global history in a category (pass by value)*/
+  HistoryListType GetGlobalHistory(const std::string &category);
+
+  /** Create a registry holding the local history */
+  void SaveLocalHistory(Registry &folder)
+    { SaveHistory(folder, m_LocalHistory); }
+
+  /** Read a registry holding the local history */
+  void LoadLocalHistory(Registry &folder)
+    { LoadHistory(folder, m_LocalHistory); }
+
+  /** Create a registry holding the local history */
+  void SaveGlobalHistory(Registry &folder)
+    { SaveHistory(folder, m_GlobalHistory); }
+
+  /** Read a registry holding the local history */
+  void LoadGlobalHistory(Registry &folder)
+    { LoadHistory(folder, m_GlobalHistory); }
+
+
+  HistoryManager();
+
+protected:
+
+  static const unsigned int HISTORY_SIZE_LOCAL, HISTORY_SIZE_GLOBAL;
+
+  // Typedef the concrete history model
+  typedef ConcretePropertyModel<HistoryListType, TrivialDomain> ConcreteHistoryModel;
+  typedef SmartPtr<ConcreteHistoryModel> ConcreteHistoryModelPtr;
+
+  // Array of histories for different types of files
+  typedef std::map<std::string, ConcreteHistoryModelPtr> HistoryMap;
+  HistoryMap m_LocalHistory, m_GlobalHistory;
+
+  ConcreteHistoryModel *GetHistory(const std::string &category, HistoryMap &hmap);
+  void SaveHistory(Registry &folder, HistoryMap &hmap);
+  void LoadHistory(Registry &folder, HistoryMap &hmap);
+
+  void UpdateHistoryList(
+      ConcreteHistoryModel *model, const std::string &file, unsigned int maxsize);
+
+  // The system interface class
+  SystemInterface *m_SystemInterface;
+
+};
+
+#endif // HISTORYMANAGER_H
diff --git a/Common/IPCHandler.cxx b/Common/IPCHandler.cxx
new file mode 100644
index 0000000..8b9a1aa
--- /dev/null
+++ b/Common/IPCHandler.cxx
@@ -0,0 +1,218 @@
+#include "IPCHandler.h"
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <cerrno>
+
+using namespace std;
+
+#ifdef WIN32
+  #ifdef _WIN32_WINNT
+  #undef _WIN32_WINNT
+  #endif //_WIN32_WINNT
+  #define _WIN32_WINNT	0x0600
+
+  #include <Shlobj.h>
+  #include <iostream>
+  #include <process.h>
+  #include <windows.h>
+  #include <cstdlib>
+#else
+  #include <sys/types.h>
+  #include <sys/ipc.h>
+  #include <sys/shm.h>
+  #include <unistd.h>
+  #include <sys/time.h>
+#endif
+
+void IPCHandler::Attach(const char *path, short version, size_t message_size)
+{
+  // Initialize the data pointer
+  m_SharedData = NULL;
+
+  // Store the size of the actual message
+  m_MessageSize = message_size;
+
+  // Save the protocol version
+  m_ProtocolVersion = version;
+
+  // Determine size of shared memory
+  size_t msize = message_size + sizeof(Header);
+
+#ifdef WIN32
+  // Create a shared memory block (key based on the preferences file)
+  m_Handle = CreateFileMapping(
+    INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, msize, path);
+
+  // If the return value is NULL, something failed
+  if(m_Handle)
+    {
+    // Attach to the shared memory block
+    m_SharedData = MapViewOfFile(m_Handle, FILE_MAP_ALL_ACCESS, 0, 0, msize);
+    }
+
+#else
+
+  // Create a unique key for this user
+  key_t keyid = ftok(path, version);
+
+  // Get a handle to shared memory
+  m_Handle = shmget(keyid, msize, IPC_CREAT | 0644);
+
+  // There may be an error!
+  if(m_Handle < 0)
+    {
+    cerr << "Shared memory (shmget) error: " << strerror(errno) << endl;
+    cerr << "This error may occur if a user is running two versions of ITK-SNAP" << endl;
+    cerr << "Multisession support is disabled" << endl;
+    m_SharedData = NULL;
+    }
+  else
+    {
+    // Get a pointer to shared data block
+    m_SharedData = shmat(m_Handle, (void *) 0, 0);
+
+    // Check errors again
+    if(!m_SharedData)
+      {
+      cerr << "Shared memory (shmat) error: " << strerror(errno) << endl;
+      cerr << "Multisession support is disabled" << endl;
+      m_SharedData = NULL;
+      }
+    }
+
+#endif
+
+  // Set the user data pointer
+  if(m_SharedData)
+    {
+    Header *hptr = static_cast<Header *>(m_SharedData);
+    m_UserData = static_cast<void *>(hptr + 1);
+    }
+  else
+    {
+    m_UserData = NULL;
+    }
+}
+
+bool IPCHandler::Read(void *target_ptr)
+{
+  // Must have some shared memory
+  if(!m_SharedData)
+    return false;
+
+  // Read the header, make sure it's the right version number
+  Header *header = static_cast<Header *>(m_SharedData);
+  if(header->version != m_ProtocolVersion)
+    return false;
+
+  // Store the last sender / id
+  m_LastSender = header->sender_pid;
+  m_LastReceivedMessageID = header->message_id;
+
+  // Copy the message to the target pointer
+  memcpy(target_ptr, m_UserData, m_MessageSize);
+
+  // Success!
+  return true;
+}
+
+bool IPCHandler::ReadIfNew(void *target_ptr)
+{
+  // Must have some shared memory
+  if(!m_SharedData)
+    return false;
+
+  // Read the header, make sure it's the right version number
+  Header *header = static_cast<Header *>(m_SharedData);
+  if(header->version != m_ProtocolVersion)
+    return false;
+
+  // Ignore our own messages
+  if(header->sender_pid == m_ProcessID)
+    return false;
+
+  // If we have already seen this message from this sender, also ignore it
+  if(m_LastSender == header->sender_pid && m_LastReceivedMessageID == header->message_id)
+    return false;
+
+  // Store the last sender / id
+  m_LastSender = header->sender_pid;
+  m_LastReceivedMessageID = header->message_id;
+
+  // Copy the message to the target pointer
+  memcpy(target_ptr, m_UserData, m_MessageSize);
+
+  // Success!
+  return true;
+}
+
+
+bool
+IPCHandler
+::Broadcast(const void *message_ptr)
+{
+  // Write to the shared memory
+  if(m_SharedData)
+    {
+    // Access the message header
+    Header *header = static_cast<Header *>(m_SharedData);
+
+    // Write version number
+    header->version = m_ProtocolVersion;
+
+    // Write the process ID
+    header->sender_pid = m_ProcessID;
+    header->message_id = ++m_MessageID;
+
+    // Copy the message contents into the shared memory
+    memcpy(m_UserData, message_ptr, m_MessageSize);
+
+    // Done
+    return true;
+    }
+
+  return false;
+}
+
+void IPCHandler::Close()
+{
+#ifdef WIN32
+  CloseHandle(m_Handle);
+#else
+  // Detach from the shared memory segment
+  shmdt(m_SharedData);
+
+  // If there is noone attached to the memory segment, destroy it
+  struct shmid_ds dsinfo;
+  shmctl(m_Handle, IPC_STAT, &dsinfo);
+  if(dsinfo.shm_nattch == 0)
+    shmctl(m_Handle, IPC_RMID, NULL);
+#endif
+
+  m_SharedData = NULL;
+}
+
+
+IPCHandler::IPCHandler()
+{
+  // Set the message ID and last sender/message id values
+  m_LastReceivedMessageID = -1;
+  m_LastSender = -1;
+  m_MessageID = 0;
+
+  // Reset the shared memory
+  m_SharedData = NULL;
+
+  // Get the process ID
+#ifdef WIN32
+  m_ProcessID = _getpid();
+#else
+  m_ProcessID = getpid();
+#endif
+}
+
+IPCHandler::~IPCHandler()
+{
+
+}
diff --git a/Common/IPCHandler.h b/Common/IPCHandler.h
new file mode 100644
index 0000000..fe64d67
--- /dev/null
+++ b/Common/IPCHandler.h
@@ -0,0 +1,83 @@
+#ifndef IPCHANDLER_H
+#define IPCHANDLER_H
+
+#include <cstddef>
+
+/**
+ * Base class for IPCHandler. This class contains the definitions of the
+ * core methods and is independent of the data structure being shared.
+ */
+class IPCHandler
+{
+public:
+
+  IPCHandler();
+  ~IPCHandler();
+
+  /**
+   * Attach to the shared memory. The caller should supply the path to the
+   * program executable (or a derived string), and a version number. The version
+   * number is used to prevent problems when the format of the shared data structure
+   * has changed between versions of the program. The version number should be
+   * incremented whenever the data structure being shared changes. The last parameter
+   * is the size of the message in bytes (obtained using size_of)
+   */
+  void Attach(const char *path, short version, size_t message_size);
+
+  /** Release shared memory */
+  void Close();
+
+  /** Whether the shared memory is attached */
+  bool IsAttached() { return m_SharedData != NULL; }
+
+  /** Read a 'message', i.e., the contents of shared memory */
+  bool Read(void *target_ptr);
+
+  /** Read a 'message' but only if it has not been seen before */
+  bool ReadIfNew(void *target_ptr);
+
+  /** Broadcast a 'message' (i.e. replace shared memory contents */
+  bool Broadcast(const void *message_ptr);
+
+protected:
+
+  struct Header
+  {
+    short version;
+    long sender_pid;
+    long message_id;
+  };
+
+
+  // Shared data pointer
+  void *m_SharedData, *m_UserData;
+
+  // Size of the shared data message
+  size_t m_MessageSize;
+
+  // Version of the protocol (to avoid problems with older code)
+  short m_ProtocolVersion;
+
+  // System-specific IPC related stuff
+#ifdef WIN32
+  void *m_Handle;
+#else
+  int m_Handle;
+#endif
+
+  // The version of the SNAP-IPC protocol. This way, when versions are different
+  // IPC will not work. This is to account for an off chance of a someone running
+  // two different versions of SNAP
+  static const short IPC_VERSION;
+
+  // Process ID and other values used by IPC
+  long m_ProcessID, m_MessageID, m_LastSender, m_LastReceivedMessageID;
+
+};
+
+
+
+
+
+
+#endif // IPCHANDLER_H
diff --git a/Common/IRISException.cxx b/Common/IRISException.cxx
index 95b1978..180edfb 100644
--- a/Common/IRISException.cxx
+++ b/Common/IRISException.cxx
@@ -36,20 +36,21 @@
 #include <cstdarg>
 #include <stdio.h>
 
-IRISException
-::operator const char *() 
+using namespace std;
+
+IRISException::operator const char *() 
 {
-  return m_SimpleMessage.c_str();
+  return this->what();
 }
 
-IRISException
-::IRISException() 
+IRISException::IRISException() 
+  : exception()
 {
   m_SimpleMessage = "Unspecified IRIS exception";
 }
 
-IRISException
-::IRISException(const char *message, ...)
+IRISException::IRISException(const char *message, ...)
+  : exception()
 {
   char buffer[1024];
   va_list args;
@@ -59,8 +60,20 @@ IRISException
   m_SimpleMessage = buffer;
 }
 
-IRISException
-::~IRISException() 
+
+IRISWarning::IRISWarning()
+  : IRISException()
 {
+
 }
 
+IRISWarning::IRISWarning(const char *message, ...)
+  : IRISException()
+{
+  char buffer[1024];
+  va_list args;
+  va_start(args, message);
+  vsprintf(buffer,message,args);
+  va_end (args);
+  m_SimpleMessage = buffer;
+}
diff --git a/Common/IRISException.h b/Common/IRISException.h
index ff78f3d..e3f7d98 100644
--- a/Common/IRISException.h
+++ b/Common/IRISException.h
@@ -36,14 +36,17 @@
 #define __IRIS_Exceptions_h_
 
 #include "SNAPCommon.h"
+#include <exception>
+#include <vector>
 
 using std::string;
+using std::exception;
 
 /** 
  * \class IRISException
  * \brief Sets up a family of SNAP/IRIS exceptions
  */
-class IRISException {
+class IRISException : public exception {
 protected:
   string m_SimpleMessage;
 
@@ -51,13 +54,34 @@ public:
   IRISException();
   IRISException(const char *message, ...);
 
-  virtual ~IRISException();
+  virtual ~IRISException() throw() {};
 
-  const char * what() { return m_SimpleMessage.c_str(); }
+  virtual const char * what() const throw() { return m_SimpleMessage.c_str(); }
 
   operator const char *();
 };
 
+
+/**
+  Actions can generate warnings. These warnings are simply instances of
+  IRISException that are not fired, but rather stored. Warnings do not
+  keep the action from executing, they are just messages that are sent to
+  the user. Optimally, there should be an option to react to the message.
+
+  Actions can also generate errors, but these are achieved by throwing an
+  exception.
+  */
+class IRISWarning : public IRISException
+{
+public:
+  IRISWarning(const char *fmt, ...);
+  IRISWarning();
+
+  virtual ~IRISWarning() throw() {}
+
+
+};
+
 /**
  * Set macro borrowed from VTK and modified.  Assumes m_ for private vars
  */
@@ -66,7 +90,7 @@ class name : public parent { \
 public: \
         name() : parent() {} \
           name(const char *message) : parent(message) {} \
-          virtual ~name() {} \
+          virtual ~name() throw() {}  \
 };
 
 irisExceptionMacro(IRISExceptionIO,IRISException)
diff --git a/Common/IRISVectorTypes.h b/Common/IRISVectorTypes.h
index 71c701c..ce1a85f 100644
--- a/Common/IRISVectorTypes.h
+++ b/Common/IRISVectorTypes.h
@@ -46,6 +46,8 @@
 // For the little vector operations
 #include <vnl/vnl_vector_fixed.h>
 #include <vnl/vnl_matrix_fixed.h>
+#include <itkSize.h>
+#include <itkIndex.h>
 
 /**
  * \class iris_vector_fixed
@@ -62,8 +64,15 @@ public:
   typedef iris_vector_fixed<float,VSize> FloatVectorType;
   typedef iris_vector_fixed<double,VSize> DoubleVectorType;
 
-  // Construct an uninitialized n-vector
-  iris_vector_fixed() : Parent() {}
+  typedef itk::Size<VSize> ITKSizeType;
+  typedef itk::Index<VSize> ITKIndexType;
+  typedef itk::FixedArray<T, VSize> ITKFixedArray;
+
+  // Initialize the n-vector to zeros
+  iris_vector_fixed() : Parent()
+  {
+    this->fill(0);
+  }
 
   // Copy constructor
   iris_vector_fixed(const Parent& rhs ) : Parent(rhs) {}
@@ -76,7 +85,7 @@ public:
 
   // Construct an fixed-n-vector initialized from \a datablck
   //  The data *must* have enough data. No checks performed.
-  explicit iris_vector_fixed(const T* data) : Parent(data) {}
+  // explicit iris_vector_fixed(const T* data) : Parent(data) {}
 
   // Convenience constructor for 2-D vectors
   iris_vector_fixed(const T& x0,const T& x1) : Parent(x0,x1) {}
@@ -84,6 +93,30 @@ public:
   // Convenience constructor for 3-D vectors
   iris_vector_fixed(const T& x0,const T& x1,const T& x2) : Parent(x0,x1,x2) {}
 
+  // Initialize with an itk::Size
+  iris_vector_fixed(const ITKSizeType &size)
+  {
+    for(int i = 0; i < VSize; i++)
+      (*this)[i] = static_cast<T>(size[i]);
+  }
+
+  // Initialize with an itk::Index
+  iris_vector_fixed(const ITKIndexType &idx)
+  {
+    for(int i = 0; i < VSize; i++)
+      (*this)[i] = static_cast<T>(idx[i]);
+  }
+
+  // Initialize with an itk::FixedArray
+  iris_vector_fixed(const ITKFixedArray &arr)
+  {
+    this->copy_in(arr.GetDataPointer());
+  }
+
+  // Assignment operator that takes an int
+  Self &operator = (int value)
+  { this->fill((T) value); return *this; }
+
   /**
    * Clamp the vector between a pair of vectors (the elements of this vector
    * that are smaller than the corresponding elements of lower are set to lower, 
@@ -109,6 +142,7 @@ typedef iris_vector_fixed<long,2> Vector2l;
 typedef iris_vector_fixed<unsigned long,2> Vector2ul;
 typedef iris_vector_fixed<float,2> Vector2f;
 typedef iris_vector_fixed<double,2> Vector2d;
+typedef iris_vector_fixed<bool,2> Vector2b;
 
 // Common 3D vector types
 typedef iris_vector_fixed<int,3> Vector3i;
@@ -117,9 +151,31 @@ typedef iris_vector_fixed<long,3> Vector3l;
 typedef iris_vector_fixed<unsigned long,3> Vector3ul;
 typedef iris_vector_fixed<float,3> Vector3f;
 typedef iris_vector_fixed<double,3> Vector3d;
+typedef iris_vector_fixed<bool,3> Vector3b;
 
 // A matrix definition
 typedef vnl_matrix_fixed<double,3,3> Matrix3d;
+typedef vnl_matrix_fixed<double,4,4> Matrix4d;
+
+// An equivalent to MATLAB's linspace command
+template<class T>
+inline vnl_vector<T> linspace(T x0, T x1, unsigned int n)
+{
+  vnl_vector<T> v(n);
+  double step = (x1 - x0) / (n - 1);
+  for(int i = 0; i < n; i++)
+    v[i] = (i == n-1) ? x1 : x0 + i * step;
+  return v;
+}
+
+template<class T>
+void
+linspace(T *v, T x0, T x1, unsigned int n)
+{
+  double step = (x1 - x0) / (n - 1);
+  for(int i = 0; i < n; i++)
+    v[i] = (i == n-1) ? x1 : x0 + i * step;
+}
 
 #ifndef ITK_MANUAL_INSTANTIATION
 #include "IRISVectorTypes.txx"
diff --git a/Common/ITKExtras/itkVoxBoCUBImageIO.cxx b/Common/ITKExtras/itkVoxBoCUBImageIO.cxx
index 6f191d3..bd4b6f6 100644
--- a/Common/ITKExtras/itkVoxBoCUBImageIO.cxx
+++ b/Common/ITKExtras/itkVoxBoCUBImageIO.cxx
@@ -48,6 +48,7 @@
 #ifdef SNAP_GZIP_SUPPORT
 #include <zlib.h>
 #endif
+#include "itkSpatialOrientationAdapter.h"
 
 namespace itk {
 
@@ -534,9 +535,23 @@ void VoxBoCUBImageIO::ReadImageInformation()
         OrientationMap::const_iterator it = m_OrientationMap.find(code);
         if(it != m_OrientationMap.end())
           {
-          itk::MetaDataDictionary &dic =this->GetMetaDataDictionary();
-          EncapsulateMetaData<OrientationFlags>(
-            dic, ITK_CoordinateOrientation, it->second);
+              //Octavian original begin
+          //itk::MetaDataDictionary &dic =this->GetMetaDataDictionary();
+          //EncapsulateMetaData<OrientationFlags>(
+            //dic, ITK_CoordinateOrientation, it->second);
+              //Octavian original end
+          //NOTE:  The itk::ImageIOBase direction is a std::vector<std::vector > >, and threeDDirection is a 3x3 matrix
+          itk::SpatialOrientationAdapter soAdaptor;
+          itk::SpatialOrientationAdapter::DirectionType threeDDirection=soAdaptor.ToDirectionCosines(it->second);
+          this->m_Direction[0][0]=threeDDirection[0][0];
+          this->m_Direction[0][1]=threeDDirection[0][1];
+          this->m_Direction[0][2]=threeDDirection[0][2];
+          this->m_Direction[1][0]=threeDDirection[1][0];
+          this->m_Direction[1][1]=threeDDirection[1][1];
+          this->m_Direction[1][2]=threeDDirection[1][2];
+          this->m_Direction[2][0]=threeDDirection[2][0];
+          this->m_Direction[2][1]=threeDDirection[2][1];
+          this->m_Direction[2][2]=threeDDirection[2][2];
           }
         }
 
@@ -637,9 +652,24 @@ VoxBoCUBImageIO
     }
 
   // Write the orientation code
-  MetaDataDictionary &dic = GetMetaDataDictionary();
-  OrientationFlags oflag = SpatialOrientation::ITK_COORDINATE_ORIENTATION_INVALID;
-  if(ExposeMetaData<OrientationFlags>(dic, ITK_CoordinateOrientation, oflag))
+    //Octavian original begin
+  //MetaDataDictionary &dic = GetMetaDataDictionary();
+  //OrientationFlags oflag = SpatialOrientation::ITK_COORDINATE_ORIENTATION_INVALID;
+  //if(ExposeMetaData<OrientationFlags>(dic, ITK_CoordinateOrientation, oflag))
+      //Octavian original end
+    //NOTE:  The itk::ImageIOBase direction is a std::vector<std::vector > >, and threeDDirection is a 3x3 matrix
+    itk::SpatialOrientationAdapter soAdaptor;
+    itk::SpatialOrientationAdapter::DirectionType threeDDirection;
+    threeDDirection[0][0]=this->m_Direction[0][0];
+    threeDDirection[0][1]=this->m_Direction[0][1];
+    threeDDirection[0][2]=this->m_Direction[0][2];
+    threeDDirection[1][0]=this->m_Direction[1][0];
+    threeDDirection[1][1]=this->m_Direction[1][1];
+    threeDDirection[1][2]=this->m_Direction[1][2];
+    threeDDirection[2][0]=this->m_Direction[2][0];
+    threeDDirection[2][1]=this->m_Direction[2][1];
+    threeDDirection[2][2]=this->m_Direction[2][2];
+    OrientationFlags     oflag = soAdaptor.FromDirectionCosines(threeDDirection);
     {
     InverseOrientationMap::const_iterator it = 
       m_InverseOrientationMap.find(oflag);
diff --git a/Common/PresetManager.h b/Common/PresetManager.h
new file mode 100644
index 0000000..6fe2ff4
--- /dev/null
+++ b/Common/PresetManager.h
@@ -0,0 +1,111 @@
+#ifndef PRESETMANAGER_H
+#define PRESETMANAGER_H
+
+#include "itkObject.h"
+#include "SNAPCommon.h"
+
+class SystemInterface;
+
+/**
+  A class that handles system and user presets for arbitrary data structures
+  in ITK-SNAP. An example structure is the color map. The data structure must
+  be described by a traits object. The traits object must define the following:
+
+  // The type (derived from itk::Object) that is being managed
+  typedef ManagedType;
+
+  // The iterator type for the system presets
+  typedef SystemPresetIterator;
+
+  // The list of system presets
+  static SystemPresetIterator SystemPresetBegin();
+  static SystemPresetIterator SystemPresetEnd();
+
+  // The unique name for this class of presets, used for storing in registry
+  static std::string GetPresetCategoryName();
+
+  // Apply system preset
+  static void SetToSystemPreset(ManagedType *instance, const SystemPresetIterator &preset);
+  static std::string GetSystemPresetName(const SystemPresetIterator &preset);
+
+  // Registry io for the managed type
+  static void ReadFromRegistry(ManagedType *instance, Registry &folder);
+  static void WriteToRegistry(ManagedType *instance, Registry &folder);
+
+  TODO: we need a good way for synchronizing presets across multiple sessions.
+  Currently, the list of presets is read at startup, and as the user saves and
+  deletes presets, these operations are carried out on disk, without checking
+  what another SNAP session might have done.
+
+  The object fires a itk::ModifiedEvent event when presets have been modified
+ */
+template<class TManagedObjectTraits>
+class PresetManager : public itk::Object
+{
+public:
+
+  irisITKObjectMacro(PresetManager, itk::Object)
+
+  typedef typename TManagedObjectTraits::ManagedType ManagedType;
+  typedef SmartPtr<ManagedType> ManagedTypePtr;
+  typedef typename TManagedObjectTraits::SystemPresetIterator SystemPresetIterator;
+
+  enum PresetType { PRESET_SYSTEM, PRESET_USER, PRESET_NONE };
+  typedef std::pair<PresetType, std::string> PresetMatch;
+
+  /** Load the presets from disk and initialize them */
+  void Initialize(SystemInterface *si);
+
+  /** Get the list of user and system presets */
+  const std::vector<std::string> &GetSystemPresets()
+    { return m_PresetSystem; }
+
+  const std::vector<std::string> &GetUserPresets()
+    { return m_PresetUser; }
+
+  /**
+   * Query if the passed in instance of the object matches one of the presets,
+   * and if so, which type of preset (system or user)
+   */
+  PresetMatch QueryPreset(ManagedType *instance);
+
+  /** Set the instance passed in to a preset */
+  void SetToPreset(ManagedType *instance, const std::string &preset);
+
+  /** Save an instance as a new preset or override an existing preset */
+  void SaveAsPreset(ManagedType *instance, const std::string &preset);
+
+  /** Delete a user preset */
+  void DeletePreset(const std::string &preset);
+
+  /** Access a preset */
+  ManagedType *GetPreset(const std::string &preset);
+
+  /** Whether a string is a valid preset */
+  bool IsValidPreset(const std::string &preset);
+
+
+protected:
+
+  PresetManager();
+  virtual ~PresetManager() {}
+
+  // Pointer to the system interface object used to manage user presets
+  SystemInterface *m_System;
+
+  // The name of the category
+  std::string m_Category;
+
+  // Map of presets to instances
+  typedef std::map<std::string, ManagedTypePtr> PresetMap;
+  PresetMap m_PresetMap;
+
+  // List of system and user presets
+  std::vector<std::string> m_PresetSystem, m_PresetUser;
+
+};
+
+
+
+
+#endif // PRESETMANAGER_H
diff --git a/Common/PresetManager.hxx b/Common/PresetManager.hxx
new file mode 100644
index 0000000..f2b0c74
--- /dev/null
+++ b/Common/PresetManager.hxx
@@ -0,0 +1,151 @@
+#include "PresetManager.h"
+#include "SystemInterface.h"
+#include "IRISException.h"
+#include <algorithm>
+
+template <class TManagedObjectTraits>
+PresetManager<TManagedObjectTraits>
+::PresetManager()
+{
+  m_System = NULL;
+}
+
+template <class TManagedObjectTraits>
+void
+PresetManager<TManagedObjectTraits>
+::Initialize(SystemInterface *si)
+{
+  // Store the system interface pointer
+  m_System = si;
+  m_Category = TManagedObjectTraits::GetPresetCategoryName().c_str();
+
+  // Create all the system presets
+  m_PresetMap.clear();
+  m_PresetSystem.clear();
+  for(SystemPresetIterator i = TManagedObjectTraits::SystemPresetBegin();
+      i != TManagedObjectTraits::SystemPresetEnd();
+      i++)
+    {
+    std::string name = TManagedObjectTraits::GetSystemPresetName(i);
+    ManagedTypePtr mtp = ManagedType::New();
+    TManagedObjectTraits::SetToSystemPreset(mtp, i);
+    m_PresetMap[name] = mtp;
+    m_PresetSystem.push_back(name);
+    }
+
+  // Load all the user preset names
+  m_PresetUser = m_System->GetSavedObjectNames(m_Category.c_str());
+
+  // Load each of the presets from the registry
+  for(int j = 0; j < m_PresetUser.size(); j++)
+    {
+    Registry reg = m_System->ReadSavedObject(m_Category.c_str(), m_PresetUser[j].c_str());
+    ManagedTypePtr mtp = ManagedType::New();
+    TManagedObjectTraits::ReadFromRegistry(mtp, reg);
+    m_PresetMap[m_PresetUser[j]] = mtp;
+    }
+
+  this->Modified();
+}
+
+template <class TManagedObjectTraits>
+typename PresetManager<TManagedObjectTraits>::PresetMatch
+PresetManager<TManagedObjectTraits>
+::QueryPreset(ManagedType *instance)
+{
+  // TODO: we currently employ brute force linear search. This is probably
+  // just fine, but could be done more cleanly using some sort of a hash key
+  std::vector<std::string>::const_iterator it;
+
+  for(it = m_PresetSystem.begin(); it != m_PresetSystem.end(); it++)
+    {
+    if(*m_PresetMap[*it] == *instance)
+      return std::make_pair(PRESET_SYSTEM, *it);
+    }
+
+  for(it = m_PresetUser.begin(); it != m_PresetUser.end(); it++)
+    {
+    if(*m_PresetMap[*it] == *instance)
+      return std::make_pair(PRESET_USER, *it);
+    }
+
+  return std::make_pair(PRESET_NONE, std::string());
+}
+
+template <class TManagedObjectTraits>
+void
+PresetManager<TManagedObjectTraits>
+::SetToPreset(ManagedType *instance, const std::string &preset)
+{
+  typename PresetMap::iterator it = m_PresetMap.find(preset);
+  if(it == m_PresetMap.end())
+    throw IRISException("Preset %s not found in category %s", preset.c_str(),
+                        m_Category.c_str());
+  instance->CopyInformation(it->second);
+}
+
+template <class TManagedObjectTraits>
+void
+PresetManager<TManagedObjectTraits>
+::SaveAsPreset(ManagedType *instance, const std::string &preset)
+{
+  // Check that the name is not used for a system preset
+  if(std::find(m_PresetSystem.begin(), m_PresetSystem.end(), preset) != m_PresetSystem.end())
+    throw IRISException(
+        "%s is not a valid user preset name. It conflicts with a system preset",
+        preset.c_str());
+
+  // Assign as a user preset
+  if(std::find(m_PresetUser.begin(), m_PresetUser.end(), preset)  == m_PresetUser.end())
+    m_PresetUser.push_back(preset);
+
+  // Store the preset in memory
+  ManagedTypePtr mtp = ManagedType::New();
+  mtp->CopyInformation(instance);
+  m_PresetMap[preset] = mtp;
+
+  // Write the preset to disk
+  Registry reg;
+  TManagedObjectTraits::WriteToRegistry(instance, reg);
+  m_System->UpdateSavedObject(m_Category.c_str(), preset.c_str(), reg);
+
+  this->Modified();
+}
+
+template <class TManagedObjectTraits>
+void
+PresetManager<TManagedObjectTraits>
+::DeletePreset(const std::string &preset)
+{
+  // Assign as a user preset
+  std::vector<std::string>::iterator it =
+      std::find(m_PresetUser.begin(), m_PresetUser.end(), preset);
+
+  if(it != m_PresetUser.end())
+    {
+    // Delete the preset from the file system
+    m_System->DeleteSavedObject(m_Category.c_str(), preset.c_str());
+
+    // Also delete it from the list of user presets
+    m_PresetUser.erase(it);
+    }
+
+  this->Modified();
+}
+
+
+template <class TManagedObjectTraits>
+typename PresetManager<TManagedObjectTraits>::ManagedType *
+PresetManager<TManagedObjectTraits>
+::GetPreset(const std::string &preset)
+{
+  return m_PresetMap[preset];
+}
+
+template <class TManagedObjectTraits>
+bool
+PresetManager<TManagedObjectTraits>
+::IsValidPreset(const std::string &preset)
+{
+  return m_PresetMap.find(preset) != m_PresetMap.end();
+}
diff --git a/Common/PropertyModel.h b/Common/PropertyModel.h
new file mode 100644
index 0000000..f05f6c8
--- /dev/null
+++ b/Common/PropertyModel.h
@@ -0,0 +1,1188 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef EDITABLENUMERICVALUEMODEL_H
+#define EDITABLENUMERICVALUEMODEL_H
+
+#include <SNAPCommon.h>
+#include <SNAPEvents.h>
+#include "AbstractModel.h"
+#include <map>
+
+/**
+  This class represents the range information associated with a numeric
+  value. This range information is used to set up the GUI controls with
+  which the user interacts.
+  */
+template<class TVal> struct NumericValueRange
+{
+  typedef NumericValueRange<TVal> Self;
+
+  // These values define a numeric value range
+  TVal Minimum, Maximum, StepSize;
+
+  NumericValueRange(TVal min, TVal max, TVal step) :
+    Minimum(min), Maximum(max), StepSize(step) {}
+
+  NumericValueRange(TVal min, TVal max) :
+    Minimum(min), Maximum(max)
+  {
+    StepSize = (TVal) 0;
+  }
+
+  NumericValueRange()
+  {
+    Minimum = static_cast<TVal>(0);
+    Maximum = (TVal) 0;
+    StepSize = (TVal) 0;
+  }
+
+  NumericValueRange(const NumericValueRange<TVal> &ref)
+  {
+    Minimum = ref.Minimum;
+    Maximum = ref.Maximum;
+    StepSize = ref.StepSize;
+  }
+
+  void Set(TVal min, TVal max, TVal step)
+    { Minimum = min; Maximum = max; StepSize = step; }
+
+  bool operator == (const Self &comp)
+  {
+    return (Minimum == comp.Minimum) && (Maximum == comp.Maximum) && (StepSize == comp.StepSize);
+  }
+
+  bool operator != (const Self &comp)
+  {
+    return (Minimum != comp.Minimum) || (Maximum != comp.Maximum) || (StepSize != comp.StepSize);
+  }
+
+  // An atomic domain holds its own state, so it is possible to compare two
+  // atomic domains to determine if they are the same or different. Domains
+  // that store references to external objects are not atomic.
+  virtual bool isAtomic() { return true; }
+
+
+};
+
+/**
+  This computes a step size that is a power of 10
+  */
+inline double CalculatePowerOfTenStepSize(double min, double max, size_t minNumSteps)
+{
+  double stepUB = (max - min) / minNumSteps;
+  return pow(10, floor(log10(stepUB)));
+}
+
+
+/**
+  An abstract parent type for models that allow random access to items of
+  some type. This abstract class is agnostic to the actual storage type of
+  the source container. For implementations, see RandomAccessCollectionModel
+
+  TODO: reconcile this with domains!
+
+  */
+template <class TItem>
+class AbstractRandomAccessCollectionModel : public AbstractModel
+{
+public:
+  typedef TItem ItemType;
+  virtual unsigned int GetSize() = 0;
+  virtual TItem operator[] (unsigned int n) = 0;
+};
+
+
+/**
+  This class represents a domain that allows all values in a data type. It
+  can be used with the class AbstractPropertyModel when there is no need to
+  communicate domain information to the widget
+  */
+class TrivialDomain
+{
+public:
+  bool operator == (const TrivialDomain &cmp) { return true; }
+  bool operator != (const TrivialDomain &cmp) { return false; }
+
+  // An atomic domain holds its own state, so it is possible to compare two
+  // atomic domains to determine if they are the same or different. Domains
+  // that store references to external objects are not atomic.
+  bool isAtomic() { return true; }
+};
+
+/**
+  Another type of a domain is a set of items/options from which the user is
+  able to choose. Examples can be lists of strings, lists of color labels, and
+  so on. The value is of type TVal, but this is not necessarily the information
+  that it presented to the user. For example, in a color label chooser, the
+  value held by a property is the ID of the label, but the user is shown the
+  color and the description of the label.
+
+  The signature for this type of domain consists of a const_iterator typedef,
+  begin() and end() methods that return a const_iterator(), the method
+  GetValue(it) which returns the numeric value associated with an iterator
+  and the method GetDescription(it), which returns the information used by
+  the GUI to present the choice to the user.
+
+  The actual implementations of this domain are normally wrappers around STL
+  structures.
+*/
+template <class TVal, class TDesc, class TIterator>
+class AbstractItemSetDomain
+{
+public:
+  typedef TIterator const_iterator;
+  typedef TVal ValueType;
+  typedef TDesc DescriptorType;
+
+  virtual const_iterator begin() const = 0;
+  virtual const_iterator end() const  = 0;
+  virtual const_iterator find(const TVal &value) const = 0;
+  virtual TVal GetValue(const const_iterator &it) const  = 0;
+  virtual TDesc GetDescription(const const_iterator &it) const  = 0;
+  virtual ~AbstractItemSetDomain() {}
+};
+
+/**
+  This is an implementation of the domain that wraps around an stl::map from
+  values to descriptors. The map is not stored in the domain, but referenced
+  from another object to avoid duplicating data.
+  */
+template <class TVal, class TDesc>
+class STLMapWrapperItemSetDomain :
+    public AbstractItemSetDomain<TVal, TDesc,
+                                 typename std::map<TVal,TDesc>::const_iterator>
+{
+public:
+  typedef STLMapWrapperItemSetDomain<TVal, TDesc> Self;
+  typedef typename std::map<TVal, TDesc> MapType;
+  typedef typename MapType::const_iterator const_iterator;
+
+  STLMapWrapperItemSetDomain() { m_SourceMap = NULL; }
+  STLMapWrapperItemSetDomain(const MapType *refmap) { m_SourceMap = refmap; }
+  virtual ~STLMapWrapperItemSetDomain() {}
+
+  const_iterator begin() const
+    { assert(m_SourceMap); return m_SourceMap->begin(); }
+
+  const_iterator end() const
+    { assert(m_SourceMap); return m_SourceMap->end(); }
+
+  const_iterator find(const TVal &value) const
+    { assert(m_SourceMap); return m_SourceMap->find(value); }
+
+  TVal GetValue(const const_iterator &it) const
+    { return it->first; }
+
+  TDesc GetDescription(const const_iterator &it) const
+    { return it->second; }
+
+  void SetWrappedMap(const MapType *refmap) { m_SourceMap = refmap; }
+
+  virtual bool operator == (const Self &cmp) const
+    { return m_SourceMap == cmp.m_SourceMap; }
+
+  virtual bool operator != (const Self &cmp) const
+    { return m_SourceMap != cmp.m_SourceMap; }
+
+  // An atomic domain holds its own state, so it is possible to compare two
+  // atomic domains to determine if they are the same or different. Domains
+  // that store references to external objects are not atomic.
+  virtual bool isAtomic() { return false; }
+
+protected:
+  const MapType *m_SourceMap;
+};
+
+
+/**
+  This is an implementation of the domain that wraps around an stl::vector
+  of descriptors. TVal should be an integer type that can be used as an index
+  (int, unsigned int, enum, etc)
+  */
+template <class TVal, class TDesc>
+class STLVectorWrapperItemSetDomain :
+    public AbstractItemSetDomain<TVal, TDesc,
+                                 typename std::vector<TDesc>::const_iterator>
+{
+public:
+  typedef STLVectorWrapperItemSetDomain<TVal, TDesc> Self;
+  typedef typename std::vector<TDesc> VectorType;
+  typedef typename VectorType::const_iterator const_iterator;
+
+  STLVectorWrapperItemSetDomain() { m_SourceVector = NULL; }
+  STLVectorWrapperItemSetDomain(const VectorType *refvec) { m_SourceVector = refvec; }
+  virtual ~STLVectorWrapperItemSetDomain() {}
+
+  const_iterator begin() const
+    { assert(m_SourceVector); return m_SourceVector->begin(); }
+
+  const_iterator end() const
+    { assert(m_SourceVector); return m_SourceVector->end(); }
+
+  const_iterator find(const TVal &value) const
+    { assert(m_SourceVector); return m_SourceVector->begin() + value; }
+
+  TVal GetValue(const const_iterator &it) const
+    { assert(m_SourceVector); return it - m_SourceVector->begin(); }
+
+  TDesc GetDescription(const const_iterator &it) const
+    { assert(m_SourceVector); return *it; }
+
+  virtual bool operator == (const Self &cmp) const
+    { return m_SourceVector == cmp.m_SourceVector; }
+
+  virtual bool operator != (const Self &cmp) const
+    { return m_SourceVector != cmp.m_SourceVector; }
+
+  // An atomic domain holds its own state, so it is possible to compare two
+  // atomic domains to determine if they are the same or different. Domains
+  // that store references to external objects are not atomic.
+  virtual bool isAtomic() { return false; }
+
+protected:
+  const VectorType *m_SourceVector;
+};
+
+/**
+  This is an item domain implementation that is just an stl::map, i.e., it
+  owns the data, as opposed to STLMapWrapperItemSetDomain, which references
+  the data from another map. This implementation is useful for small domains
+  where there is no cost in passing the domain by value.
+  */
+template<class TVal, class TDesc>
+class SimpleItemSetDomain : public
+    AbstractItemSetDomain<TVal, TDesc, typename std::map<TVal,TDesc>::const_iterator>
+{
+public:
+  typedef std::map<TVal, TDesc> MapType;
+  typedef typename MapType::const_iterator const_iterator;
+  typedef SimpleItemSetDomain<TVal, TDesc> Self;
+  typedef AbstractItemSetDomain<TVal, TDesc, const_iterator> Superclass;
+
+  SimpleItemSetDomain() : Superclass() { }
+
+  const_iterator begin() const
+    { return m_Map.begin(); }
+
+  const_iterator end() const
+    { return m_Map.end(); }
+
+  const_iterator find(const TVal &value) const
+    { return m_Map.find(value); }
+
+  void clear()
+    { m_Map.clear(); }
+
+  TVal GetValue(const const_iterator &it) const
+    { return it->first; }
+
+  TDesc GetDescription(const const_iterator &it) const
+    { return it->second; }
+
+  unsigned int size() const
+    { return m_Map.size(); }
+
+  // Standard stl::map operator
+  TDesc & operator [] (const TVal &key) { return m_Map[key]; }
+
+  const TDesc & operator [] (const TVal &key) const { return m_Map[key]; }
+
+  virtual bool operator == (const Self &cmp) const
+    { return m_Map == cmp.m_Map; }
+
+  virtual bool operator != (const Self &cmp) const
+    { return m_Map != cmp.m_Map; }
+
+  // An atomic domain holds its own state, so it is possible to compare two
+  // atomic domains to determine if they are the same or different. Domains
+  // that store references to external objects are not atomic.
+  virtual bool isAtomic() { return true; }
+
+protected:
+  MapType m_Map;
+};
+
+/**
+ * States that can be checked for property models. We place this enum outside
+ * of the class AbstractPropertyModel because this class is templated. This
+ * enum is meant to be used with the SNAPUIFlag framework.
+ */
+enum PropertyModelUIState
+{
+  // Indicates that the
+  UIF_PROPERTY_IS_VALID = 0
+};
+
+/**
+  A parent class for a family of models that encapsulate a single value of
+  a particular type. These models use events to communicate changes in state
+  and can be coupled to GUI widgets to allow seamless connections between the
+  GUI and the model layer. The model is parameterized by the data type of the
+  value (TVal), which would normally be a number, a string, a vector, etc. It
+  is also parameterized by the domain type, which describes the set of values
+  from which the value is drawn. The domain is used to configure GUI widgets
+  to that the user is restricted to choosing a value in a valid range. For
+  example, for TVal=double, the natural domain is the NumericValueRange class,
+  consisting of a min, max and a step size. For TVal=string, the natural
+  domain is a set of strings.
+
+  In addition to supplying a value for the encapsulated property, the model
+  can return a boolean flag as to whether the model/property is in a valid
+  state. For example, a model describing the minumum intensity of an image
+  would be in an invalid state if there is no image currently loaded. The
+  corresponding GUI widget can then be set to indicate that the value is
+  invalid or null.
+
+  This type of model is meant to be matched to a widget in the GUI. Since the
+  number of widgets is small (10s or 100s), it is acceptable for these models
+  to be somewhat heavyweight. They inherit from AbstractModel, which in turn
+  inherits from itk::Object.
+  */
+template <class TVal, class TDomain = TrivialDomain>
+class AbstractPropertyModel : public AbstractModel
+{
+public:
+
+  irisITKAbstractObjectMacro(AbstractPropertyModel, AbstractModel)
+
+  /** The atomic type encompassed by the model */
+  typedef TVal ValueType;
+
+  /** The type of the domain */
+  typedef TDomain DomainType;
+
+  /** The model fires two types of events: ValueChangedEvent and
+    DomainChangedEvent, in response to either the value or the domain
+    having changed. */
+  FIRES(ValueChangedEvent)
+  FIRES(DomainChangedEvent)
+  FIRES(StateMachineChangeEvent)
+
+  /** A setter method */
+  virtual void SetValue(TVal value) = 0;
+
+  /**
+    A compound getter method exposed by the model. Return false if the
+    value is not valid, and the corresponding control should show a blank
+    string instead of a value. If the domain is not needed, a NULL pointer
+    will be passed in. If domain is needed, the current values stored in
+    the GUI widget will be passed in.
+
+    If the domain is not handled by the model (i.e., a fixed range set in
+    the GUI designer once and for all), the callback can just ignore the
+    domain parameter.
+  */
+  virtual bool GetValueAndDomain(TVal &value, TDomain *domain) = 0;
+
+  /**
+    A getter with a simple signature. Not meant to be overridden by the
+    child class.
+    */
+  TVal GetValue()
+  {
+    TVal value;
+    GetValueAndDomain(value, NULL);
+    return value;
+  }
+
+  /**
+   * The model can participate in the state management mechanism with SNAPUIFlag.
+   * At the moment, the only flag available is the Validity flag.
+   */
+  bool CheckState(PropertyModelUIState flag)
+  {
+    if(flag == UIF_PROPERTY_IS_VALID)
+      {
+      TVal value;
+      return GetValueAndDomain(value, NULL);
+      }
+    else return false;
+  }
+
+  /**
+    Sometimes it is useful to have the model rebroadcast value and domain
+    change events from another model. An example may be a model that wraps
+    around another model, e.g., if model A is of a compound type T and
+    model B is used to access an attribute T.x in T, then we want the value
+    change events in A to be rebroadcast as value change events in B. This
+    function simplifies making this connection
+    */
+  void RebroadcastFromSourceProperty(AbstractModel *source)
+  {
+    Rebroadcast(source, ValueChangedEvent(), ValueChangedEvent());
+    Rebroadcast(source, DomainChangedEvent(), DomainChangedEvent());
+  }
+
+protected:
+
+  AbstractPropertyModel()
+  {
+    Rebroadcast(this, ValueChangedEvent(), StateMachineChangeEvent());
+  }
+};
+
+
+/**
+  A concrete implementation of AbstractPropertyModel that holds the value,
+  the validity flag, and the domain as private variables. The validity flag
+  is initialized to true. The parent model is responsible for setting the
+  value, domain, and validity flag inside of this concrete model.
+  */
+template <class TVal, class TDomain = TrivialDomain>
+class ConcretePropertyModel : public AbstractPropertyModel<TVal, TDomain>
+{
+public:
+  // Standard ITK stuff
+  typedef ConcretePropertyModel<TVal, TDomain> Self;
+  typedef AbstractPropertyModel<TVal, TDomain> Superclass;
+  typedef SmartPtr<Self> Pointer;
+  typedef SmartPtr<const Self> ConstPointer;
+  itkTypeMacro(ConcretePropertyModel, AbstractPropertyModel)
+  itkNewMacro(Self)
+
+  virtual bool GetValueAndDomain(TVal &value, TDomain *domain)
+  {
+    value = m_Value;
+    if(domain)
+      *domain = m_Domain;
+    return m_IsValid;
+  }
+
+  irisSetWithEventMacro(Value, TVal, ValueChangedEvent)
+  irisSetWithEventMacro(Domain, TDomain, DomainChangedEvent)
+  irisSetWithEventMacro(IsValid, bool, ValueChangedEvent)
+
+  // Simple implementation of the deep copy function
+  void DeepCopy(const Self *source)
+  {
+    // Copy the relevant stuff
+    this->SetValue(source->m_Value);
+    this->SetDomain(source->m_Domain);
+    this->SetIsValid(source->m_IsValid);
+  }
+
+  /** Compare with another model (by value only, not domain) */
+  bool Equals(const Self *source) const
+  {
+    // Cast to the right type
+    return(source->m_Value == m_Value &&
+           source->m_IsValid == m_IsValid);
+  }
+
+
+protected:
+
+  ConcretePropertyModel()
+    : m_Value(TVal()), m_Domain(TDomain()), m_IsValid(true) {}
+
+  virtual ~ConcretePropertyModel() {}
+
+  TVal m_Value;
+  TDomain m_Domain;
+  bool m_IsValid;
+};
+
+// A macro to generate functions GetXXX(), SetXXX() and GetXXXModel() in a class
+// that contains a ConcretePropertyModel of a certain type named m_XXXModel
+#define irisRangedPropertyAccessMacro(name,type) \
+  virtual void Set##name (type _arg) \
+    { this->m_##name##Model->SetValue(_arg); } \
+  virtual type Get##name () const \
+    { return this->m_##name##Model->GetValue(); } \
+  virtual AbstractPropertyModel<type, NumericValueRange<type> > * Get##name##Model () const \
+    { return this->m_##name##Model; }
+
+#define irisSimplePropertyAccessMacro(name,type) \
+  virtual void Set##name (type _arg) \
+    { this->m_##name##Model->SetValue(_arg); } \
+  virtual type Get##name () const \
+    { return this->m_##name##Model->GetValue(); } \
+  virtual AbstractPropertyModel<type, TrivialDomain > * Get##name##Model () const \
+    { return this->m_##name##Model; }
+
+#define irisGenericPropertyAccessMacro(name,type,domaintype) \
+  virtual void Set##name (type _arg) \
+    { this->m_##name##Model->SetValue(_arg); } \
+  virtual type Get##name () const \
+    { return this->m_##name##Model->GetValue(); } \
+  virtual AbstractPropertyModel<type, domaintype> * Get##name##Model () const \
+    { return this->m_##name##Model; }
+
+// A factory function to initialize properties - again, for shorter code
+template <class TVal>
+SmartPtr< ConcretePropertyModel<TVal, NumericValueRange<TVal> > >
+NewRangedConcreteProperty(TVal val, TVal rmin, TVal rmax, TVal rstep)
+{
+  typedef ConcretePropertyModel<TVal, NumericValueRange<TVal> > Prop;
+  SmartPtr<Prop> p = Prop::New();
+  p->SetValue(val);
+  p->SetDomain(NumericValueRange<TVal>(rmin, rmax, rstep));
+  return p;
+}
+
+template <class TVal>
+SmartPtr< ConcretePropertyModel<TVal, TrivialDomain > >
+NewSimpleConcreteProperty(TVal val)
+{
+  typedef ConcretePropertyModel<TVal, TrivialDomain > Prop;
+  SmartPtr<Prop> p = Prop::New();
+  p->SetValue(val);
+  return p;
+}
+
+
+
+/**
+  This class is only used to define some typedefs. It allows us to write
+
+      AbstractRangedPropertyModel<double>::Type
+
+  as shorthand for
+
+      AbstractPropertyModel<double, NumericValueRange<double> >
+  */
+template <class TVal>
+class AbstractRangedPropertyModel
+{
+public:
+  typedef NumericValueRange<TVal> DomainType;
+  typedef AbstractPropertyModel<TVal, DomainType> Type;
+};
+
+template <class TVal>
+class ConcreteRangedPropertyModel
+{
+public:
+  typedef NumericValueRange<TVal> DomainType;
+  typedef ConcretePropertyModel<TVal, DomainType> Type;
+};
+
+/*
+Make some typedefs. The macros below define types
+
+  AbstractSimpleXXXProperty
+  AbstractRangedXXXProperty
+  ConcreteSimpleXXXProperty
+  ConcreteRangedXXXProperty
+*/
+
+#define MAKE_TYPEDEF_PM_RANGED(type,name) \
+  typedef AbstractPropertyModel< type > AbstractSimple##name##Property; \
+  typedef AbstractRangedPropertyModel< type >::Type AbstractRanged##name##Property; \
+  typedef ConcretePropertyModel< type > ConcreteSimple##name##Property; \
+  typedef ConcreteRangedPropertyModel< type >::Type ConcreteRanged##name##Property;
+
+#define MAKE_TYPEDEF_PM_NONRNG(type,name) \
+  typedef AbstractPropertyModel< type > AbstractSimple##name##Property; \
+  typedef ConcretePropertyModel< type > ConcreteSimple##name##Property;
+
+// Macros for standard types that support ranges
+MAKE_TYPEDEF_PM_RANGED(double,          Double)
+MAKE_TYPEDEF_PM_RANGED(float,           Float)
+MAKE_TYPEDEF_PM_RANGED(int,             Int)
+MAKE_TYPEDEF_PM_RANGED(unsigned int,    UInt)
+MAKE_TYPEDEF_PM_RANGED(short,           Short)
+MAKE_TYPEDEF_PM_RANGED(unsigned short,  UShort)
+MAKE_TYPEDEF_PM_RANGED(char,            Char)
+MAKE_TYPEDEF_PM_RANGED(unsigned char,   UChar)
+MAKE_TYPEDEF_PM_RANGED(bool,            Boolean)
+
+// Common SNAP typedefs
+MAKE_TYPEDEF_PM_RANGED(LabelType,       LabelType)
+
+// Common vector types
+MAKE_TYPEDEF_PM_RANGED(Vector2d,        DoubleVec2)
+MAKE_TYPEDEF_PM_RANGED(Vector3d,        DoubleVec3)
+MAKE_TYPEDEF_PM_RANGED(Vector2i,        IntVec2)
+MAKE_TYPEDEF_PM_RANGED(Vector3i,        IntVec3)
+MAKE_TYPEDEF_PM_RANGED(Vector2ui,       UIntVec2)
+MAKE_TYPEDEF_PM_RANGED(Vector3ui,       UIntVec3)
+MAKE_TYPEDEF_PM_RANGED(Vector2b,        BooleanVec2)
+MAKE_TYPEDEF_PM_RANGED(Vector3b,        BooleanVec3)
+
+// Macros for non-ranged types
+MAKE_TYPEDEF_PM_NONRNG(std::string,     String)
+
+
+
+
+/**
+  An implementation of the AbstractPropertyModel that serves as a wrapper
+  around a getter function and a setter function, both members of a parent
+  model class. The primary use for this class is to make it easy to create
+  AbstractPropertyModels that describe a derived property.
+
+  The parent model must include a getter with one of the following three
+  signatures.
+
+      bool GetValueAndDomain(TVal &value, TDomain *domain)
+
+      bool GetValue(TVal &value)
+
+      TVal GetValue()
+
+  It may also optionally include a setter method with the signature
+
+      void SetValue(TVal value)
+
+  In addition to value and domain, this class is templated over the parent
+  model type (TModel) and the traits object describing the signature of the
+  getter. This is because we want to support all three of the getter signatures
+  without having to check which one the user supplied dynamically.
+
+  Note that this class is not meant to be used directly in the GUI model code.
+  Instead, one should make use of the function wrapGetterSetterPairAsProperty, which
+  serves as a factory for creating models of this type.
+*/
+template<class TVal, class TDomain, class TModel, class GetterTraits, class SetterTraits>
+class FunctionWrapperPropertyModel
+    : public AbstractPropertyModel<TVal, TDomain>
+{
+public:
+
+  // Standard ITK stuff (can't use irisITKObjectMacro because of two template
+  // parameters, comma breaks the macro).
+  typedef FunctionWrapperPropertyModel<TVal, TDomain, TModel, GetterTraits, SetterTraits> Self;
+  typedef AbstractPropertyModel<TVal, TDomain> Superclass;
+  typedef SmartPtr<Self> Pointer;
+  typedef SmartPtr<const Self> ConstPointer;
+
+  itkTypeMacro(FunctionWrapperPropertyModel, AbstractPropertyModel)
+  itkNewMacro(Self)
+
+  // Function pointers to a setter method
+  typedef typename SetterTraits::Setter Setter;
+
+  // The function pointer to the getter is provided by the traits
+  typedef typename GetterTraits::Getter Getter;
+
+  /** Initializes a model with a parent model and function pointers */
+  void Initialize(TModel *model, Getter getter, Setter setter = NULL)
+  {
+    m_Model = model;
+    m_Getter = getter;
+    m_Setter = setter;
+  }
+
+  /** Get a reference to the getter traits */
+  GetterTraits &GetGetterTraits() { return m_GetterTraits; }
+
+  /** Get a reference to the setter traits */
+  SetterTraits &GetSetterTraits() { return m_SetterTraits; }
+
+  /**
+    Set up the events fired by the parent model that this model should
+    listen to and rebroadcast as ValueChangedEvent and DomainChangedEvent.
+    */
+  void SetEvents(const itk::EventObject &valueEvent,
+                 const itk::EventObject &rangeEvent)
+  {
+    this->Rebroadcast(m_Model, valueEvent, ValueChangedEvent());
+    this->Rebroadcast(m_Model, rangeEvent, DomainChangedEvent());
+  }
+
+
+  bool GetValueAndDomain(TVal &value, TDomain *domain)
+  {
+    // This is important! Before calling the getter function, we should allow
+    // the model to respond to whatever events it may have received that led
+    // to this data request. Otherwise, we would have to make an Update()
+    // call in each of the Getter functions we write.
+    m_Model->Update();
+
+    // Call the getter function with the help of the traits object
+    return m_GetterTraits.GetValueAndDomain(m_Model, m_Getter, value, domain);
+  }
+
+  void SetValue(TVal value)
+  {
+    if(m_Setter)
+      {
+      static_cast<AbstractModel *>(m_Model)->Update();
+      m_SetterTraits.SetValue(m_Model, m_Setter, value);
+      }
+  }
+
+  /**
+    A factory method used to create new models of this type. The user should
+    not need to call this directly, instead use the wrapGetterSetterPairAsProperty
+    methods below. The last two paremeters are the events fired by the parent
+    model that should be rebroadcast as the value and domain change events by
+    the property model.
+    */
+  static SmartPtr<Superclass> CreatePropertyModel(
+      TModel *parentModel,
+      Getter getter, Setter setter,
+      const itk::EventObject &valueEvent,
+      const itk::EventObject &rangeEvent,
+      GetterTraits getterTraits = GetterTraits(),
+      SetterTraits setterTraits = SetterTraits())
+  {
+    SmartPtr<Self> p = Self::New();
+    p->Initialize(parentModel, getter, setter);
+    p->SetEvents(valueEvent, rangeEvent);
+    p->m_SetterTraits = setterTraits;
+    p->m_GetterTraits = getterTraits;
+
+    // p->UnRegister();
+
+    SmartPtr<Superclass> pout(p);
+    return pout;
+  }
+
+protected:
+
+  TModel *m_Model;
+  Getter m_Getter;
+  Setter m_Setter;
+  GetterTraits m_GetterTraits;
+  SetterTraits m_SetterTraits;
+
+  FunctionWrapperPropertyModel()
+    : m_Model(NULL), m_Getter(NULL), m_Setter(NULL)  {}
+
+  ~FunctionWrapperPropertyModel() {}
+
+};
+
+/**
+  Getter traits for the FunctionWrapperPropertyModel that use the compound
+  getter signature,
+
+    bool GetValueAndDomain(TVal &value, TDomain &domain);
+*/
+template <class TVal, class TDomain, class TModel>
+class FunctionWrapperPropertyModelCompoundGetterTraits
+{
+public:
+  // Signature of the getter
+  typedef bool (TModel::*Getter)(TVal &t, TDomain *domain);
+
+  // Implementation of the get method, just calls the getter directly
+  bool GetValueAndDomain(
+      TModel *model, Getter getter, TVal &value, TDomain *domain)
+  {
+    return ((*model).*(getter))(value, domain);
+  }
+};
+
+/**
+  Getter traits for the FunctionWrapperPropertyModel that use the rangeless
+  getter signature,
+
+    bool GetValue(TVal &value);
+*/
+template <class TVal, class TDomain, class TModel>
+class FunctionWrapperPropertyModelRangelessGetterTraits
+{
+public:
+  // Signature of the getter
+  typedef bool (TModel::*Getter)(TVal &t);
+
+  // Implementation of the get method, just calls the getter directly
+  bool GetValueAndDomain(
+      TModel *model, Getter getter, TVal &value, TDomain *domain)
+  {
+    return ((*model).*(getter))(value);
+  }
+};
+
+/**
+  Getter traits for the FunctionWrapperPropertyModel that use the simple
+  getter signature,
+
+    TVal GetValue();
+*/
+template <class TVal, class TDomain, class TModel>
+class FunctionWrapperPropertyModelSimpleGetterTraits
+{
+public:
+  // Signature of the getter
+  typedef TVal (TModel::*Getter)();
+
+  // Implementation of the get method, just calls the getter directly
+  bool GetValueAndDomain(
+      TModel *model, Getter getter, TVal &value, TDomain *domain)
+  {
+    value = ((*model).*(getter))();
+    return true;
+  }
+};
+
+/**
+  Basic setter traits
+  */
+template <class TVal, class TModel>
+class FunctionWrapperPropertyModelSimpleSetterTraits
+{
+public:
+  // Signature of the getter
+  typedef void (TModel::*Setter)(TVal value);
+
+  // Implementation of the get method, just calls the getter directly
+  void SetValue(
+      TModel *model, Setter getter, TVal &value)
+  {
+    ((*model).*(getter))(value);
+  }
+};
+
+class FunctionWrapperPropertyModelIndexedTraits
+{
+public:
+
+  void SetIndex(int index) { m_Index = index; }
+  int GetIndex() const { return m_Index; }
+
+protected:
+  int m_Index;
+};
+
+/**
+  Getter traits for the FunctionWrapperPropertyModel that use the compound
+  getter signature, with a parameter variable i. This is useful when we need
+  to create an array of models that wrap around function of the form
+
+    bool GetValueAndDomain(int i, TVal &value, TDomain &domain);
+*/
+template <class TVal, class TDomain, class TModel>
+class FunctionWrapperPropertyModelIndexedCompoundGetterTraits :
+    public FunctionWrapperPropertyModelIndexedTraits
+{
+public:
+  // Signature of the getter
+  typedef bool (TModel::*Getter)(int i, TVal &t, TDomain *domain);
+
+  // Implementation of the get method, just calls the getter directly
+  bool GetValueAndDomain(
+      TModel *model, Getter getter, TVal &value, TDomain *domain)
+  {
+    return ((*model).*(getter))(GetIndex(), value, domain);
+  }
+};
+
+
+template <class TVal, class TDomain, class TModel>
+class FunctionWrapperPropertyModelIndexedRangelessGetterTraits :
+    public FunctionWrapperPropertyModelIndexedTraits
+{
+public:
+  // Signature of the getter
+  typedef bool (TModel::*Getter)(int index, TVal &t);
+
+  // Implementation of the get method, just calls the getter directly
+  bool GetValueAndDomain(
+      TModel *model, Getter getter, TVal &value, TDomain *domain)
+  {
+    return ((*model).*(getter))(GetIndex(), value);
+  }
+};
+
+
+/**
+  Indexed setter traits
+  */
+template <class TVal, class TModel>
+class FunctionWrapperPropertyModelIndexedSimpleSetterTraits :
+    public FunctionWrapperPropertyModelIndexedTraits
+{
+public:
+  // Signature of the getter
+  typedef void (TModel::*Setter)(int index, TVal value);
+
+  // Implementation of the get method, just calls the getter directly
+  void SetValue(
+      TModel *model, Setter getter, TVal &value)
+  {
+    ((*model).*(getter))(GetIndex(), value);
+  }
+};
+
+
+
+/**
+  This code creates an AbstractPropertyModel that wraps around a pair of
+  functions (a getter and a setter) in the parent model object. There are
+  three versions of this function, corresponding to different signatures
+  of the getter function.
+  */
+template<class TModel, class TVal, class TDomain>
+SmartPtr< AbstractPropertyModel<TVal, TDomain> >
+wrapGetterSetterPairAsProperty(
+    TModel *model,
+    bool (TModel::*getter)(TVal &, TDomain *),
+    void (TModel::*setter)(TVal) = NULL,
+    const itk::EventObject &valueEvent = ModelUpdateEvent(),
+    const itk::EventObject &rangeEvent = ModelUpdateEvent())
+{
+  typedef FunctionWrapperPropertyModelCompoundGetterTraits<
+      TVal, TDomain, TModel> GetterTraitsType;
+
+  typedef FunctionWrapperPropertyModelSimpleSetterTraits<
+      TVal, TModel> SetterTraitsType;
+
+  typedef FunctionWrapperPropertyModel<
+      TVal, TDomain, TModel, GetterTraitsType, SetterTraitsType> ModelType;
+
+  return ModelType::CreatePropertyModel(model, getter, setter,
+                                        valueEvent, rangeEvent);
+}
+
+template<class TModel, class TVal>
+SmartPtr< AbstractPropertyModel<TVal> >
+wrapGetterSetterPairAsProperty(
+    TModel *model,
+    bool (TModel::*getter)(TVal &),
+    void (TModel::*setter)(TVal) = NULL,
+    const itk::EventObject &valueEvent = ModelUpdateEvent(),
+    const itk::EventObject &rangeEvent = ModelUpdateEvent())
+{
+  typedef FunctionWrapperPropertyModelRangelessGetterTraits<
+      TVal, TrivialDomain, TModel> GetterTraitsType;
+
+  typedef FunctionWrapperPropertyModelSimpleSetterTraits<
+      TVal, TModel> SetterTraitsType;
+
+  typedef FunctionWrapperPropertyModel<
+      TVal, TrivialDomain, TModel, GetterTraitsType, SetterTraitsType> ModelType;
+
+  return ModelType::CreatePropertyModel(model, getter, setter,
+                                        valueEvent, rangeEvent);
+}
+
+template<class TModel, class TVal>
+SmartPtr< AbstractPropertyModel<TVal> >
+wrapGetterSetterPairAsProperty(
+    TModel *model,
+    TVal (TModel::*getter)(),
+    void (TModel::*setter)(TVal) = NULL,
+    const itk::EventObject &valueEvent = ModelUpdateEvent(),
+    const itk::EventObject &rangeEvent = ModelUpdateEvent())
+{
+  typedef FunctionWrapperPropertyModelSimpleGetterTraits<
+      TVal, TrivialDomain, TModel> GetterTraitsType;
+
+  typedef FunctionWrapperPropertyModelSimpleSetterTraits<
+      TVal, TModel> SetterTraitsType;
+
+  typedef FunctionWrapperPropertyModel<
+      TVal, TrivialDomain, TModel, GetterTraitsType, SetterTraitsType> ModelType;
+
+  return ModelType::CreatePropertyModel(model, getter, setter,
+                                        valueEvent, rangeEvent);
+}
+
+/**
+  A version of wrapGetterSetterPairAsProperty that creates a model that wraps around
+  a function GetXXXValueAndDomain(int i, TVal &value, TDomain *). This is
+  useful when we want to create multiple models that wrap around the same
+  getter/setter function.
+  */
+template<class TModel, class TVal, class TDomain>
+SmartPtr< AbstractPropertyModel<TVal, TDomain> >
+wrapIndexedGetterSetterPairAsProperty(
+    TModel *model,
+    int index,
+    bool (TModel::*getter)(int, TVal &, TDomain *),
+    void (TModel::*setter)(int, TVal) = NULL,
+    const itk::EventObject &valueEvent = ModelUpdateEvent(),
+    const itk::EventObject &rangeEvent = ModelUpdateEvent())
+{
+  typedef FunctionWrapperPropertyModelIndexedCompoundGetterTraits<
+      TVal, TDomain, TModel> GetterTraitsType;
+
+  typedef FunctionWrapperPropertyModelIndexedSimpleSetterTraits<
+      TVal, TModel> SetterTraitsType;
+
+  typedef FunctionWrapperPropertyModel<
+      TVal, TDomain, TModel, GetterTraitsType, SetterTraitsType> ModelType;
+
+  // Assign the index to the traits
+  GetterTraitsType getterTraits;
+  getterTraits.SetIndex(index);
+
+  SetterTraitsType setterTraits;
+  setterTraits.SetIndex(index);
+
+  // Create the property model
+  return ModelType::CreatePropertyModel(model, getter, setter,
+                                        valueEvent, rangeEvent,
+                                        getterTraits, setterTraits);
+}
+
+template<class TModel, class TVal>
+SmartPtr< AbstractPropertyModel<TVal> >
+wrapIndexedGetterSetterPairAsProperty(
+    TModel *model, int index,
+    bool (TModel::*getter)(int, TVal &),
+    void (TModel::*setter)(int, TVal) = NULL,
+    const itk::EventObject &valueEvent = ModelUpdateEvent(),
+    const itk::EventObject &rangeEvent = ModelUpdateEvent())
+{
+  typedef FunctionWrapperPropertyModelIndexedRangelessGetterTraits<
+      TVal, TrivialDomain, TModel> GetterTraitsType;
+
+  typedef FunctionWrapperPropertyModelIndexedSimpleSetterTraits<
+      TVal, TModel> SetterTraitsType;
+
+  typedef FunctionWrapperPropertyModel<
+      TVal, TrivialDomain, TModel, GetterTraitsType, SetterTraitsType> ModelType;
+
+  // Assign the index to the traits
+  GetterTraitsType getterTraits;
+  getterTraits.SetIndex(index);
+
+  SetterTraitsType setterTraits;
+  setterTraits.SetIndex(index);
+
+  return ModelType::CreatePropertyModel(model, getter, setter,
+                                        valueEvent, rangeEvent,
+                                        getterTraits, setterTraits);
+}
+
+
+
+/**
+ * This model is used to decorate a member in a C++ struct as a property. This
+ * is useful when we have a property of type X, and we want to be able to access
+ * X.a as a property.
+ */
+template <class TStruct, class TMember, class TDomain>
+class StructMemberWrapperPropertyModel
+    : public AbstractPropertyModel<TMember, TDomain>
+{
+public:
+
+  // Standard ITK stuff (can't use irisITKObjectMacro because of two template
+  // parameters, comma breaks the macro).
+  typedef StructMemberWrapperPropertyModel<TStruct, TMember, TDomain> Self;
+  typedef AbstractPropertyModel<TMember, TDomain> Superclass;
+  typedef SmartPtr<Self> Pointer;
+  typedef SmartPtr<const Self> ConstPointer;
+
+  itkTypeMacro(StructMemberWrapperPropertyModel, AbstractPropertyModel)
+  itkNewMacro(Self)
+
+  // Set the source model (the one that manages the TStruct)
+  typedef AbstractPropertyModel<TStruct> ParentModel;
+  void Initialize(ParentModel *model, size_t offset, const TDomain &domain)
+  {
+    m_ParentModel = model;
+    m_MemberOffset = offset;
+    m_Domain = domain;
+
+    // Respond to value change events
+    AbstractModel::Rebroadcast(m_ParentModel, ValueChangedEvent(), ValueChangedEvent());
+  }
+
+  bool GetValueAndDomain(TMember &value, TDomain *domain)
+  {
+    TStruct parentValue;
+    if(m_ParentModel && m_ParentModel->GetValueAndDomain(parentValue,  NULL))
+      {
+      // Get the value of the member based on the offset
+      TMember *valuePtr =
+          reinterpret_cast<TMember *>(
+            reinterpret_cast<char *>(&parentValue) + m_MemberOffset);
+
+      value = *valuePtr;
+      if(domain)
+        *domain = m_Domain;
+
+      return true;
+      }
+    return false;
+  }
+
+  void SetValue(TMember value)
+  {
+    TStruct parentValue;
+    if(m_ParentModel && m_ParentModel->GetValueAndDomain(parentValue,  NULL))
+      {
+      // Get the value of the member based on the offset
+      TMember *valuePtr =
+          reinterpret_cast<TMember *>(
+            reinterpret_cast<char *>(&parentValue) + m_MemberOffset);
+
+      // Set the value
+      if(*valuePtr != value)
+        {
+        *valuePtr = value;
+        m_ParentModel->SetValue(parentValue);
+        }
+      }
+  }
+
+  static SmartPtr<Superclass> CreatePropertyModel(
+      ParentModel *parentModel,
+      size_t offset,
+      TDomain domain)
+  {
+    SmartPtr<Self> p = Self::New();
+    p->Initialize(parentModel, offset, domain);
+
+    // p->UnRegister();
+
+    SmartPtr<Superclass> pout(p);
+    return pout;
+  }
+
+protected:
+  StructMemberWrapperPropertyModel()
+    : m_ParentModel(NULL), m_MemberOffset(0) {}
+
+
+  ParentModel *m_ParentModel;
+  size_t m_MemberOffset;
+  TDomain m_Domain;
+};
+
+template <class TStruct, class TField>
+SmartPtr< AbstractPropertyModel<TField> >
+wrapStructMemberAsSimpleProperty(
+    AbstractPropertyModel<TStruct> *parentModel,
+    size_t offset)
+{
+  typedef StructMemberWrapperPropertyModel<TStruct, TField, TrivialDomain> ModelType;
+  TrivialDomain td;
+  return ModelType::CreatePropertyModel(parentModel, offset, td);
+}
+
+template <class TStruct, class TField>
+SmartPtr< AbstractPropertyModel<TField, NumericValueRange<TField> > >
+wrapStructMemberAsRangedProperty(
+    AbstractPropertyModel<TStruct> *parentModel,
+    size_t offset,
+    const NumericValueRange<TField> &domain)
+{
+  typedef StructMemberWrapperPropertyModel<TStruct, TField, NumericValueRange<TField> > ModelType;
+  return ModelType::CreatePropertyModel(parentModel, offset, domain);
+}
+
+
+
+#endif // EDITABLENUMERICVALUEMODEL_H
diff --git a/Common/Rebroadcaster.cxx b/Common/Rebroadcaster.cxx
new file mode 100644
index 0000000..7a7bdd3
--- /dev/null
+++ b/Common/Rebroadcaster.cxx
@@ -0,0 +1,231 @@
+#include "Rebroadcaster.h"
+#include "SNAPEventListenerCallbacks.h"
+#include "SNAPCommon.h"
+#include "EventBucket.h"
+
+Rebroadcaster::DispatchMap Rebroadcaster::m_SourceMap;
+Rebroadcaster::DispatchMap Rebroadcaster::m_TargetMap;
+
+unsigned long Rebroadcaster
+::Rebroadcast(itk::Object *source, const itk::EventObject &sourceEvent,
+              itk::Object *target, const itk::EventObject &targetEvent,
+              EventBucket *bucket)
+{
+  // TODO: for now, we allow the user to call this method twice with the same
+  // input without checking if the rebroadcast has already been set up. This
+  // might cause some issues if users are not careful.
+  Association *assoc = new Association(source, target, targetEvent);
+
+  // Add listeners to the source object, unless the source event is a delete
+  // event, in which case, we already are going to register for it in order
+  // to delete the associate when the source is deleted.
+  assoc->m_IsForDeleteEvent = itk::DeleteEvent().CheckEvent(&sourceEvent);
+  if(!assoc->m_IsForDeleteEvent)
+    {
+    assoc->m_SourceTag = AddListenerPair(
+          source, sourceEvent, assoc, &Association::Callback, &Association::ConstCallback);
+    }
+
+  // Pass the bucket pointer
+  assoc->m_Bucket = bucket;
+
+#ifdef SNAP_DEBUG_EVENTS
+  if(flag_snap_debug_events)
+    {
+    std::cout << "ESTABLISHED REBROADCAST event " <<  sourceEvent.GetEventName()
+              << " from " << source->GetNameOfClass()
+              << " [" << source << "] "
+              << " as " << targetEvent.GetEventName()
+              << " from " << target->GetNameOfClass()
+              << " [" << target << "] "
+              << std::endl << std::flush;
+    }
+#endif // SNAP_DEBUG_EVENTS
+
+
+
+  // This can explode if the target object is deleted and the source object
+  // fires an event. One solution would be to require the target object to
+  // stop broadcasting before being deleted. However, itk sends us delete
+  // callbacks for all objects, so we can use these callbacks to uncouple
+  // everything when the source or target are deleted.
+
+  // Is this a known target object?
+  if(m_TargetMap.find(target) == m_TargetMap.end())
+    {
+    // Target object is new. Register to receive delete events from it
+    SmartPtr<itk::CStyleCommand> cmd_target_delete = itk::CStyleCommand::New();
+    cmd_target_delete->SetCallback(&Rebroadcaster::DeleteTargetCallback);
+    cmd_target_delete->SetConstCallback(&Rebroadcaster::DeleteTargetConstCallback);
+    target->AddObserver(itk::DeleteEvent(), cmd_target_delete);
+    }
+
+  // Add the association to the target's list
+  m_TargetMap[target].push_back(assoc);
+
+  // Is this a known source object?
+  if(m_SourceMap.find(source) == m_SourceMap.end())
+    {
+    // Target object is new. Register to receive delete events from it
+    SmartPtr<itk::CStyleCommand> cmd_source_delete = itk::CStyleCommand::New();
+    cmd_source_delete->SetCallback(&Rebroadcaster::DeleteSourceCallback);
+    cmd_source_delete->SetConstCallback(&Rebroadcaster::DeleteSourceConstCallback);
+    source->AddObserver(itk::DeleteEvent(), cmd_source_delete);
+    }
+
+  // Add the association to the source's list
+  m_SourceMap[source].push_back(assoc);
+
+  // Return the tag
+  return assoc->m_SourceTag;
+}
+
+unsigned long Rebroadcaster
+::RebroadcastAsSourceEvent(
+    itk::Object *source, const itk::EventObject &sourceEvent,
+    itk::Object *target, EventBucket *bucket)
+{
+  // We just call the main rebroadcast method with RefireEvent() to indicate
+  // that the source event should be refired
+  return Rebroadcast(source, sourceEvent, target, RefireEvent(), bucket);
+}
+
+void Rebroadcaster::DeleteTargetCallback(
+    itk::Object *target, const itk::EventObject &evt, void *cd)
+{
+  DeleteTargetConstCallback(target, evt, cd);
+}
+
+void Rebroadcaster::DeleteTargetConstCallback(
+    const itk::Object *target, const itk::EventObject &evt, void *cd)
+{
+  // The target object is being deleted. This means that the corresponding
+  // associations should be detatched from their source objects.
+
+  // Find the list of associations for the target object.
+  DispatchMap::iterator itmap = m_TargetMap.find(target);
+  if(itmap == m_TargetMap.end())
+    return;
+
+  // Destroy all the associations
+  AssociationList &l = m_TargetMap[target];
+  for(AssociationIterator it = l.begin(); it != l.end(); ++it)
+    {
+    Association *assoc = *it;
+
+    // Remove the observer from the source. If the source is the same object
+    // as the target (being deleted), we can skip this
+    if(target != assoc->m_Source)
+      assoc->m_Source->RemoveObserver(assoc->m_SourceTag);
+
+    // Remove the association from the source's list
+    m_SourceMap[assoc->m_Source].remove(assoc);
+
+    // Delete the association
+    delete assoc;
+    }
+
+  // Remove the target from m_TargetMap
+  m_TargetMap.erase(itmap);
+}
+
+void Rebroadcaster::DeleteSourceCallback(
+    itk::Object *source, const itk::EventObject &evt, void *cd)
+{
+  DeleteSourceConstCallback(source, evt, cd);
+}
+
+void Rebroadcaster::DeleteSourceConstCallback(
+    const itk::Object *source, const itk::EventObject &evt, void *cd)
+{
+  // The source object is being deleted. We need to destroy all of its
+  // associations. We don't need to remove any observers though.
+
+  // Find the list of associations for the source object.
+  DispatchMap::iterator itmap = m_SourceMap.find(source);
+  if(itmap == m_SourceMap.end())
+    return;
+
+  // Destroy all the associations
+  AssociationList &l = m_SourceMap[source];
+  for(AssociationIterator it = l.begin(); it != l.end(); ++it)
+    {
+    Association *assoc = *it;
+
+    // Remove the association from the target's list
+    m_TargetMap[assoc->m_Target].remove(assoc);
+
+    // If the association is for a delete event, then it must be triggered,
+    // because these associations are not hooked up to the source objects using
+    // AddListener as non-delete associations
+    if(assoc->m_IsForDeleteEvent)
+      {
+      // This call will propagate the event downstream, even though the
+      // association itself will be deleted
+      assoc->ConstCallback(source, evt);
+      }
+
+    // Delete the association
+    delete assoc;
+    }
+
+  // Remove the source from the source map
+  m_SourceMap.erase(itmap);
+}
+
+
+Rebroadcaster::Association::Association(
+    itk::Object *source, itk::Object *target, const itk::EventObject &targetEvent)
+{
+  m_Source = source;
+  m_Target = target;
+  m_TargetEvent = targetEvent.MakeObject();
+  m_Bucket = NULL;
+  m_SourceTag = 0;
+
+  m_SourceObjectName = source->GetNameOfClass();
+  m_TargetObjectName = target->GetNameOfClass();
+
+  // Are we refiring the source event or firing the target event?
+  m_RefireSource = Rebroadcaster::RefireEvent().CheckEvent(m_TargetEvent);
+
+
+}
+
+Rebroadcaster::Association::~Association()
+{
+  delete m_TargetEvent;
+}
+
+void Rebroadcaster::Association::Callback(itk::Object *source, const itk::EventObject &evt)
+{
+  this->ConstCallback((const itk::Object *) source, evt);
+}
+
+void Rebroadcaster::Association::ConstCallback(const itk::Object *source, const itk::EventObject &evt)
+{
+  // Decide what to do
+  const itk::EventObject *firedEvent = m_RefireSource ? &evt : m_TargetEvent;
+
+#ifdef SNAP_DEBUG_EVENTS
+  if(flag_snap_debug_events)
+    {
+    std::cout << "REBROADCAST event " <<  evt.GetEventName()
+              << " from " << m_SourceObjectName
+              << " [" << source << "] "
+              << " as " << firedEvent->GetEventName()
+              << " from " << m_TargetObjectName
+              << " [" << m_Target << "] "
+              << std::endl << std::flush;
+    }
+#endif // SNAP_DEBUG_EVENTS
+
+  // Rebroadcast the target event
+  m_Target->InvokeEvent(*firedEvent);
+
+  // If there is a bucket, record in it
+  if(m_Bucket)
+    m_Bucket->PutEvent(evt, source);
+}
+
+
diff --git a/Common/Rebroadcaster.h b/Common/Rebroadcaster.h
new file mode 100644
index 0000000..6f0bdbc
--- /dev/null
+++ b/Common/Rebroadcaster.h
@@ -0,0 +1,116 @@
+#ifndef REBROADCASTER_H
+#define REBROADCASTER_H
+
+#include <map>
+#include <set>
+#include <list>
+#include <itkObject.h>
+#include <itkEventObject.h>
+
+class EventBucket;
+
+/**
+ * @brief The Rebroadcaster class
+ * This class allows classes that inherit from itk::Object to rebroadcast
+ * events from other itk::Objects as their own events. For example, if I
+ * have a class A, which has an instance variable A::worker of class B, and
+ * B invokes the event 'FinishedEvent()', I might want A to invoke the event
+ * 'WorkerFinishedEvent()'. This is cumbersome to implement in ITK, but using
+ * the Rebroadcaster class, it's quite easy:
+ *
+ * A a1;
+ * unsigned long tag = Rebroadcaster::Rebroadcast(
+ *                        a1.worker, FinishedEvent(), a1, WorkerFinishedEvent());
+ *
+ * Later on, if we want to stop rebroadcasting, we can use the tag to stop:
+ *
+ * Rebroadcaster::StopRebroadcasting(tag);
+ *
+ * The class handles object destruction gracefully. As soon as one of the classes
+ * fires a itk::DeleteEvent(), the rebroadcasting stops.
+ *
+ * The class also has optional support for event buckets. If, the caller passes
+ * in an EventBucket pointer to Rebroadcast(), then any events passed to the
+ * target object from the source object will be added to the EventBucket. This
+ * way, the target object (or another interested party) can keep track of what
+ * events, and from whom, were rebroadcast.
+ */
+class Rebroadcaster
+{
+public:
+
+  /**
+   * Rebroadcast event sourceEvent from object source as the event
+   * targetEvent from object target. Note that if the source event is of
+   * a type derived from sourceEvent, then the broadcast will still occur.
+   * See docs for the class (above) for notes about the EventBucket param.
+   */
+  static unsigned long Rebroadcast(
+      itk::Object *source, const itk::EventObject &sourceEvent,
+      itk::Object *target, const itk::EventObject &targetEvent,
+      EventBucket *bucket = NULL);
+
+  /**
+   * Rebroadcast event sourceEvent from object source as the same event from
+   * object target. An important property of this method is that if we call
+   * this method with source event of type baseEvent, and the source object
+   * fires event derivedEvent(), which derives from baseEvent(), then the
+   * event rebroadcast by the target object will be of type derivedEvent().
+   * This is a convenient mechanism for rebroadcasting whole groups of events.
+   * For example, if we want every event fired by source to be rebroadcast by
+   * target, we can just call this method with itk::AnyEvent() as sourceEvent.
+   */
+  static unsigned long RebroadcastAsSourceEvent(
+      itk::Object *source, const itk::EventObject &sourceEvent,
+      itk::Object *target, EventBucket *bucket = NULL);
+
+protected:
+
+  // We define our own event type RefireEvent which is used to indicate that
+  // the event fired by the target object should be the same as the event
+  // fired by the source object
+  itkEventMacro(RefireEvent, itk::EventObject)
+
+  // One of these workers is associated with every rebroadcast request
+  class Association
+  {
+  public:
+    Association(itk::Object *source, itk::Object *target, const itk::EventObject &targetEvent);
+    ~Association();
+
+    void Callback(itk::Object *source, const itk::EventObject &evt);
+    void ConstCallback(const itk::Object *source, const itk::EventObject &evt);
+
+    itk::Object *m_Source, *m_Target;
+    itk::EventObject *m_TargetEvent;
+    EventBucket *m_Bucket;
+    unsigned long m_SourceTag;
+
+    // Whether this association is in response to a delete event.
+    bool m_IsForDeleteEvent;
+
+    // For debug purposes, it helps to keep the names of the source and target
+    // objects in memory, in case these objects are deleted
+    const char *m_SourceObjectName, *m_TargetObjectName;
+
+    bool m_RefireSource;
+  };
+
+  static void DeleteSourceCallback(
+      itk::Object *source, const itk::EventObject &evt, void *cd);
+  static void DeleteSourceConstCallback(
+      const itk::Object *source, const itk::EventObject &evt, void *cd);
+  static void DeleteTargetCallback(
+      itk::Object *target, const itk::EventObject &evt, void *cd);
+  static void DeleteTargetConstCallback(
+      const itk::Object *target, const itk::EventObject &evt, void *cd);
+
+  // typedef std::pair<itk::Object *, itk::EventObject> ObjectEventPair;
+  typedef std::list<Association *> AssociationList;
+  typedef AssociationList::iterator AssociationIterator;
+  typedef std::map<const itk::Object *, AssociationList> DispatchMap;
+
+  static DispatchMap m_SourceMap, m_TargetMap;
+};
+
+#endif // REBROADCASTER_H
diff --git a/Common/Registry.cxx b/Common/Registry.cxx
index cde0cf1..de1a2d6 100644
--- a/Common/Registry.cxx
+++ b/Common/Registry.cxx
@@ -34,12 +34,15 @@
 =========================================================================*/
 #include "Registry.h"
 #include "IRISVectorTypes.h"
+#include "itkXMLFile.h"
 
 #include <stdio.h>
 #include <cstdlib>
 #include <cstdarg>
 #include <fstream>
 #include <iomanip>
+#include "itksys/SystemTools.hxx"
+#include "IRISException.h"
 
 #if defined(_MSC_VER)
 #pragma warning ( disable : 4786 )
@@ -47,6 +50,116 @@
 
 using namespace std;
 
+
+
+/** Reader for XML files */
+class RegistryXMLFileReader : public itk::XMLReader<Registry>
+{
+public:
+
+  irisITKObjectMacro(RegistryXMLFileReader, itk::XMLReader<Registry>)
+
+protected:
+
+  RegistryXMLFileReader() {}
+
+  virtual int CanReadFile(const char *name);
+  virtual void StartElement(const char *name, const char **atts);
+  virtual void EndElement(const char *name);
+  virtual void CharacterDataHandler(const char *inData, int inLength);
+
+  static int strcmpi(const char *str1, const char *str2)
+  {
+    return itksys::SystemTools::Strucmp(str1, str2);
+  }
+
+  // The folder stack
+  std::list<Registry *> m_FolderStack;
+};
+
+int RegistryXMLFileReader::CanReadFile(const char *name)
+{
+  if ( !itksys::SystemTools::FileExists(name)
+       || itksys::SystemTools::FileIsDirectory(name)
+       || itksys::SystemTools::FileLength(name) == 0 )
+    {
+    return 0;
+    }
+
+  return 1;
+}
+
+void RegistryXMLFileReader::StartElement(const char *name, const char **atts)
+{
+  // If this is the root-level element <registry>, it can be ignored
+  if(strcmpi(name, "registry") == 0)
+    {
+    // Put the target registry on the stack
+    assert(this->GetOutputObject());
+    m_FolderStack.push_back(this->GetOutputObject());
+    return;
+    }
+
+  // If the stack is empty throw up
+  if(m_FolderStack.size() == 0)
+    throw IRISException("Problem parsing Registry XML file. The file might not be valid.");
+
+  // Read the attributes into a map
+  typedef std::map<std::string, std::string> AttributeMap;
+  typedef AttributeMap::const_iterator AttrIter;
+  AttributeMap attrmap;
+
+  for(int i = 0; atts[i] != NULL && atts[i+1] != NULL; i+=2)
+    attrmap[itksys::SystemTools::LowerCase(atts[i])] = atts[i+1];
+
+  // Process tags
+  if(strcmpi(name, "folder") == 0)
+    {
+    AttrIter itKey = attrmap.find("key");
+    if(itKey == attrmap.end())
+      throw IRISException("Missing 'key' attribute to <folder> element");
+
+    // Create a new folder and place it on the stack
+    Registry &newFolder = m_FolderStack.back()->Folder(itKey->second);
+    m_FolderStack.push_back(&newFolder);
+    }
+  else if(strcmpi(name, "entry") == 0)
+    {
+    AttrIter itKey = attrmap.find("key");
+    if(itKey == attrmap.end())
+      throw IRISException("Missing 'key' attribute to <entry> element");
+
+    AttrIter itValue = attrmap.find("value");
+    if(itValue == attrmap.end())
+      throw IRISException("Missing 'value' attribute to <entry> element");
+
+    // Create a new entry (TODO: decode!)
+    m_FolderStack.back()->Entry(itKey->second) = RegistryValue(itValue->second);
+    }
+  else
+    throw IRISException("Unknown XML element <%s>", name);
+}
+
+
+void RegistryXMLFileReader::EndElement(const char *name)
+{
+  if(strcmpi(name, "registry") == 0)
+    {
+    m_FolderStack.clear();
+    }
+
+  else if(strcmpi(name, "folder") == 0)
+    {
+    m_FolderStack.pop_back();
+    }
+}
+
+void RegistryXMLFileReader::CharacterDataHandler(const char *inData, int inLength)
+{
+  return;
+}
+
+
 RegistryValue
 ::RegistryValue()
 {
@@ -131,7 +244,43 @@ Registry
   return targetArray.size();
 }
 
-void 
+bool Registry::HasEntry(const Registry::StringType &key)
+{
+  // Get the containing folder
+  StringType::size_type iDot = key.find_first_of('.');
+
+  // There is a subfolder
+  if(iDot != key.npos)
+    {
+    StringType child = key.substr(0,iDot);
+    StringType childKey = key.substr(iDot+1);
+    return Folder(child).HasEntry(childKey);
+    }
+
+  // Search for the key and return it if found
+  EntryIterator it = m_EntryMap.find(key);
+  return it != m_EntryMap.end();
+}
+
+bool Registry::HasFolder(const Registry::StringType &key)
+{
+  // Get the containing folder
+  StringType::size_type iDot = key.find_first_of('.');
+
+  // There is a subfolder
+  if(iDot != key.npos)
+    {
+    StringType child = key.substr(0,iDot);
+    StringType childKey = key.substr(iDot+1);
+    return Folder(child).HasFolder(childKey);
+    }
+
+  // Search for the key and return it if found
+  FolderIterator it = m_FolderMap.find(key);
+  return it != m_FolderMap.end();
+}
+
+void
 Registry
 ::Write(ostream &sout,const StringType &prefix)
 {
@@ -157,6 +306,38 @@ Registry
     }  
 }
 
+void
+Registry
+::WriteXML(ostream &sout, const StringType &prefix)
+{
+  // Write the entries in this folder
+  for(EntryIterator ite = m_EntryMap.begin();ite != m_EntryMap.end(); ++ite)
+    {
+    // Only write the non-null entries
+    if(!ite->second.IsNull())
+      {
+      // Write the key
+      sout << prefix << "<entry key=\"" << EncodeXML(ite->first) << "\"";
+
+      // Write the encoded value
+      sout << " value=\"" << EncodeXML(ite->second.GetInternalString()) << "\" />" << endl;
+      }
+    }
+
+  // Write the folders
+  for(FolderIterator itf = m_FolderMap.begin(); itf != m_FolderMap.end(); ++itf)
+    {
+    // Write the folder tag
+    sout << prefix << "<folder key=\"" << EncodeXML(itf->first) << "\" >" << endl;
+
+    // Write the folder contents (recursive, contents prefixed with full path name)
+    itf->second->WriteXML(sout, prefix + "  ");
+
+    // Close the folder
+    sout << prefix << "</folder>" << endl;
+    }
+}
+
 void 
 Registry
 ::SetFlagAddIfNotFound(bool yesno) 
@@ -253,6 +434,42 @@ Registry
   m_FolderMap.clear();
 }
 
+Registry::StringType
+Registry
+::EncodeXML(const StringType &input)
+{
+  IRISOStringStream oss;
+  for(unsigned int i=0; i < input.length() ; i++)
+    {
+    // Map the character to positive integer (0..255)
+    char c = input[i];
+
+    // There are special characters not allowed in XML
+    switch(c)
+      {
+      case '<' :
+        oss << "<"; break;
+      case '>' :
+        oss << ">"; break;
+      case '&' :
+        oss << "&"; break;
+      case '\'' :
+        oss << "'"; break;
+      case '\"' :
+        oss << """; break;
+      default:
+        oss << c; break;
+      }
+   }
+
+  // Return the resulting string
+  return oss.str();
+}
+
+Registry::StringType Registry::DecodeXML(const Registry::StringType &input)
+{
+  return input;
+}
 
 Registry::StringType
 Registry
@@ -261,16 +478,21 @@ Registry
   IRISOStringStream oss;
   for(unsigned int i=0; i < input.length() ; i++)
     {
-    if(!isprint(input[i]) || input[i]=='%' || isspace(input[i]))
+    // Map the character to positive integer (0..255)
+    char c = input[i];
+    int v = static_cast<int>(static_cast<unsigned char>(c));
+
+    // We only print ASCII codes
+    if(v <= 0x20 || v >= 0x7f || c == '%')
       {
       // Replace character by a escape string
       oss << '%';
-      oss << setw(2) << setfill('0') << hex << (int)input[i];
+      oss << setw(2) << setfill('0') << hex << v;
       }
     else
       {
       // Just copy the character
-      oss << input[i];
+      oss << c;
       }
     }
 
@@ -431,6 +653,49 @@ Registry::
   //  delete itf->second;
 }
 
+bool Registry::operator == (const Registry &other) const
+{
+  // Compare the folders
+  if(m_FolderMap.size() != other.m_FolderMap.size())
+    return false;
+
+  for(FolderIterator it1 = m_FolderMap.begin(), it2 = other.m_FolderMap.begin();
+      it1 != m_FolderMap.end(); ++it1, ++it2)
+    {
+    // Compare keys
+    if(it1->first != it2->first)
+      return false;
+
+    // Compare subfolder contents (recursively)
+    if(*(it1->second) != *(it2->second))
+      return false;
+    }
+
+  // Compare the entries
+  if(m_EntryMap.size() != other.m_EntryMap.size())
+    return false;
+
+  for(EntryConstIterator it1 = m_EntryMap.begin(), it2 = other.m_EntryMap.begin();
+      it1 != m_EntryMap.end(); ++it1, ++it2)
+    {
+    // Compare keys
+    if(it1->first != it2->first)
+      return false;
+
+    // Compare subfolder contents (recursively)
+    if(it1->second != it2->second)
+      return false;
+    }
+
+  return true;
+}
+
+bool Registry::operator != (const Registry &other) const
+{
+  return ! (*this == other);
+}
+
+
 /**
 * Write the folder to a disk
 */
@@ -452,6 +717,40 @@ Registry
   Write(sout,"");
 }
 
+void Registry::WriteToXMLFile(const char *pathname, const char *header)
+{
+  // Open the file
+  ofstream sout(pathname,std::ios::out);
+
+  // Set the stream to be picky
+  sout.exceptions(std::ios::failbit);
+
+  // Write the XML string
+  sout << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << endl;
+
+  // Write the header
+  if(header)
+    sout << "<!--" << header << "-->" << endl;
+
+  // Write the DOCTYPE content
+  sout << "<!DOCTYPE registry [" << endl
+       << "<!ELEMENT registry (entry*,folder*)>" << endl
+       << "<!ELEMENT folder (entry*,folder*)>" << endl
+       << "<!ELEMENT entry EMPTY>" << endl
+       << "<!ATTLIST folder key CDATA #REQUIRED>" << endl
+       << "<!ATTLIST entry key CDATA #REQUIRED>" << endl
+       << "<!ATTLIST entry value CDATA #REQUIRED>" << endl
+       << "]>" << endl;
+
+  // Write to the stream
+  sout << "<registry>" << endl;
+  WriteXML(sout, "  ");
+  sout << "</registry>" << endl;
+}
+
+
+
+
 /**
 * Read folder from file
 */
@@ -459,15 +758,22 @@ void
 Registry
 ::ReadFromFile(const char *pathname) 
 {
-  // Create an error stream
-  IRISOStringStream serr;
-      
   // Create output stream
   ifstream sin(pathname,std::ios::in);
   if(!sin.good())
     throw IOException("Unable to open the Registry file");
 
-  try 
+  ReadFromStream(sin);
+
+}
+
+void Registry
+::ReadFromStream(istream &sin)
+{
+  // Create an error stream
+  IRISOStringStream serr;
+
+  try
     {
     // Try reading
     Read(sin,serr);
@@ -482,5 +788,12 @@ Registry
     throw SyntaxException(serr.str().c_str());
 }
 
+void Registry::ReadFromXMLFile(const char *pathname)
+{
+  SmartPtr<RegistryXMLFileReader> reader = RegistryXMLFileReader::New();
+  reader->SetOutputObject(this);
+  reader->SetFilename(pathname);
+  reader->GenerateOutputInformation();
+}
 
 
diff --git a/Common/Registry.h b/Common/Registry.h
index 5273a24..950151a 100644
--- a/Common/Registry.h
+++ b/Common/Registry.h
@@ -48,6 +48,7 @@
 #include <vector>
 
 #include "SNAPCommon.h"
+#include "itkXMLFile.h"
 
 inline Vector2d GetValueWithDefault(const std::string &source, bool isNull, Vector2d defaultValue)
 {
@@ -157,6 +158,29 @@ public:
     m_EnumToStringMap[value] = std::string(description);
     m_StringToEnumMap[description] = value;
   }
+
+  bool GetEnumValue(const StringType &key, TEnum &outValue) const
+  {
+    typename std::map<StringType, TEnum>::const_iterator it = m_StringToEnumMap.find(key);
+    if(it == m_StringToEnumMap.end())
+      return false;
+
+    outValue = it->second;
+    return true;
+  }
+
+  bool GetString(TEnum value, StringType &outString) const
+  {
+    typename std::map<TEnum, StringType>::const_iterator it = m_EnumToStringMap.find(value);
+    if(it == m_EnumToStringMap.end())
+      return false;
+
+    outString = it->second;
+    return true;
+  }
+
+  unsigned int Size() const { return m_EnumToStringMap.size(); }
+  StringType operator [] (TEnum value) { return m_EnumToStringMap[value]; }
 private:
   std::map<TEnum, StringType> m_EnumToStringMap;
   std::map<StringType, TEnum> m_StringToEnumMap;
@@ -173,6 +197,17 @@ public:
   /** Initializing constructor: sets the object to a value */
   RegistryValue(const std::string &value);
 
+  /** Comparison */
+  bool operator == (const RegistryValue &other) const
+  {
+    return m_Null == other.m_Null && m_String == other.m_String;
+  }
+
+  bool operator != (const RegistryValue &other) const
+  {
+    return ! (*this == other);
+  }
+
   /** Is the value present in the Registry? */
   bool IsNull() const { return m_Null; }
 
@@ -255,20 +290,22 @@ public:
     m_Null = false;
   }
 
-  /** Put an enum into this entry */
-  template <class TEnum> void PutEnum(
-    RegistryEnumMap<TEnum> &rem,TEnum value)
+  /**
+   * Put an enum into this entry. If the enum map does not have the value,
+   * nothing will be written to the entry (entry will be null)
+   */
+  template <class TEnum> void PutEnum(const RegistryEnumMap<TEnum> &rem, TEnum value)
   {
-    (*this) << rem.m_EnumToStringMap[value];;
+    m_Null = !rem.GetString(value, m_String);
   }
 
   /** Get an enum from this entry */
-  template <class TEnum> TEnum GetEnum(
-    RegistryEnumMap<TEnum> &rem,TEnum defaultValue)
+  template <class TEnum> TEnum GetEnum(const RegistryEnumMap<TEnum> &rem, TEnum defaultValue)
   {
-    if(rem.m_StringToEnumMap.find(m_String) == rem.m_StringToEnumMap.end())
-      return defaultValue;
-    else return rem.m_StringToEnumMap[m_String];
+    TEnum value;
+    if(rem.GetEnumValue(m_String, value))
+      return value;
+    else return defaultValue;
   }
 
 private:
@@ -301,6 +338,11 @@ public:
   /** Destructor */
   virtual ~Registry();
 
+  /** Comparison */
+  bool operator == (const Registry &other) const;
+
+  bool operator != (const Registry &other) const;
+
   /** Get a reference to a value in this registry, which can then be queried */
   RegistryValue &operator[](const StringType &key) { return Entry(key); }
 
@@ -319,6 +361,12 @@ public:
   /** Get a list of all subfolder keys, append it to keyList */
   int GetFolderKeys(StringListType &keyList);
 
+  /** Check if an entry with the given key exists */
+  bool HasEntry(const StringType &key);
+
+  /** Check if a subfolder with the given key exists */
+  bool HasFolder(const StringType &key);
+
   /** Find a value in a folder or return "" */
   StringType FindValue(const StringType& value);
 
@@ -337,6 +385,9 @@ public:
    * header, each line of which must start with the '#" character  */
   void WriteToFile(const char *pathname, const char *header = NULL);
 
+  /** Write the Registry to an XML file */
+  void WriteToXMLFile(const char *pathname, const char *header = NULL);
+
   /**
    * Update the registry with keys from another registry
    */
@@ -345,6 +396,13 @@ public:
   /** Read this Registry from a file */
   void ReadFromFile(const char *pathname);
 
+  /** Read from an std::ifstream */
+  void ReadFromStream(std::istream &sin);
+
+  /** Read from XML file */
+  void ReadFromXMLFile(const char *pathname);
+
+
   /** Experimental */
   void SetFlagAddIfNotFound(bool yesno);
 
@@ -426,6 +484,9 @@ private:
   /** Write this folder recursively to a stream */
   void Write(std::ostream &sout,const StringType &keyPrefix);
 
+  /** Write this folder recursively to a stream in XML format */
+  void WriteXML(std::ostream &sout,const StringType &keyPrefix);
+
   /** Read this folder recursively from a stream, recording syntax errors */
   void Read(std::istream &sin, std::ostream &serr);
 
@@ -434,6 +495,16 @@ private:
 
   /** Decode a string for writing to file */
   static StringType Decode(const StringType &input);
+
+  /** Encode a string for writing to file */
+  static StringType EncodeXML(const StringType &input);
+
+  /** Decode a string for writing to file */
+  static StringType DecodeXML(const StringType &input);
 };
 
+
+#include <itkXMLFile.h>
+
+
 #endif
diff --git a/Common/SNAPCommon.cxx.in b/Common/SNAPCommon.cxx.in
index cb43325..65dd03b 100644
--- a/Common/SNAPCommon.cxx.in
+++ b/Common/SNAPCommon.cxx.in
@@ -33,7 +33,26 @@ const char SNAPUISoftVersion[] =
 // Release date of the current version
 const char SNAPCurrentVersionReleaseDate[] = "@SNAP_VERSION_RELEASE_DATE@";
 
+// String describing the current build environment
+const char SNAPBuildInfo[] =
+    "Build date        @SNAP_VERSION_COMPILE_DATE@\n"
+    "Git commit hash   @SNAP_VERSION_GIT_SHA1@\n"
+    "Build site name   @SITE@\n"
+    "Build OS          @CMAKE_HOST_SYSTEM@ @CMAKE_HOST_SYSTEM_PROCESSOR@\n"
+    "Build type        @CMAKE_BUILD_TYPE@\n"
+    "ITK version       @ITK_VERSION_MAJOR at .@ITK_VERSION_MINOR at .@ITK_VERSION_PATCH@\n"
+    "VTK version       @VTK_VERSION_MAJOR at .@VTK_VERSION_MINOR at .@VTK_VERSION_PATCH@\n"
+    "Qt version        @QTVERSION@\n"
+    "CMake version     @CMAKE_VERSION@\n"
+    "C compiler        @CMAKE_C_COMPILER_ID@ @CMAKE_C_COMPILER_VERSION@\n"
+    "C++ compiler      @CMAKE_CXX_COMPILER_ID@ @CMAKE_CXX_COMPILER_VERSION@\n";
+
 // Release date of the latest version whose user preference files are
 // incompatible with the current version and will be erased
 const char SNAPLastIncompatibleReleaseDate[] = "@SNAP_VERSION_LAST_COMPATIBLE_RELEASE_DATE@";
 
+// Build date - shown to help debugging nightly builds
+const char SNAPBuildDate[] = "@SNAP_VERSION_COMPILE_DATE@";
+
+// GIT signature
+const char SNAPGitSignature[] = "@SNAP_VERSION_GIT_SHA1@";
diff --git a/Common/SNAPCommon.h b/Common/SNAPCommon.h
index 95e5d2e..216684d 100644
--- a/Common/SNAPCommon.h
+++ b/Common/SNAPCommon.h
@@ -59,7 +59,7 @@ extern std::ostream &snaperr;
 #include <itkRGBPixel.h>
 
 /** Definitions for the string streams, for compatibility */
-typedef itk::OStringStream IRISOStringStream;
+typedef std::ostringstream IRISOStringStream;
 typedef std::istringstream IRISIStringStream;
 
 // Non-cvs version
@@ -84,6 +84,9 @@ extern const char SNAPCurrentVersionReleaseDate[];
 // incompatible with the current version and will be erased
 extern const char SNAPLastIncompatibleReleaseDate[];
 
+// Build date - shown to help debugging nightly builds
+extern const char SNAPBuildInfo[];
+
 // Voxel types 
 // CAREFUL: do not redefine this to INT without disabling the usage of
 // UnaryFunctorCache in the GreyImageWrapper type.  Greyscale instensities
@@ -94,35 +97,104 @@ extern const GreyType MAXGREYVAL;
 extern const GreyType MINGREYVAL;
 typedef itk::RGBPixel<unsigned char> RGBType;
 
-#define MAX_COLOR_LABELS 0xffff
+/************************************************************************/
+/* Enums that are common enough to declare them outside of a class      */
+/************************************************************************/
 
-/** 
- A structure used to map intensity from gray to 'native' intensity for
- images that are not of short datatype
- */
-struct GreyTypeToNativeFunctor
+// Coverage mode for draw-over operations
+enum CoverageModeType
 {
-  double scale;
-  double shift;
-  double operator() (GreyType g) const
-    { return g * scale + shift; }
-  GreyTypeToNativeFunctor() : scale(1.0), shift(0.0) {}
-  GreyTypeToNativeFunctor(double a, double b) : scale(a), shift(b) {}
+  PAINT_OVER_ALL = 0,
+  PAINT_OVER_VISIBLE,
+  PAINT_OVER_ONE
 };
 
-/** 
- A structure used to map 'native' intensity to gray intensity for
- images that are not of short datatype
- */
-struct NativeToGreyTypeFunctor
+// Role played by an image layer.
+enum LayerRole
+{
+  MAIN_ROLE = 0x0001,
+  OVERLAY_ROLE = 0x0002,
+  SNAP_ROLE = 0x0004,
+  LABEL_ROLE = 0x0008,
+  NO_ROLE = 0x0010,
+  ALL_ROLES = 0xffffffff
+};
+
+// Cardinal directions in the anatomical space
+enum AnatomicalDirection
+{
+  ANATOMY_AXIAL = 0,
+  ANATOMY_SAGITTAL,
+  ANATOMY_CORONAL,
+  ANATOMY_NONSENSE
+};
+
+
+
+// An atomic data type to represent draw-over state
+struct DrawOverFilter
 {
-  double scale;
-  double shift;
-  GreyType operator() (double g) const
-    { return GreyType(g * scale + shift); }
-  NativeToGreyTypeFunctor() : scale(1.0), shift(0.0) {}
-  NativeToGreyTypeFunctor(double a, double b) : scale(a), shift(b) {}
-  NativeToGreyTypeFunctor(GreyTypeToNativeFunctor g2n) : scale(1.0/g2n.scale), shift(-g2n.shift/g2n.scale) {}
+  CoverageModeType CoverageMode;
+  LabelType DrawOverLabel;
+
+  bool operator == (const DrawOverFilter &cmp) const
+  {
+    return CoverageMode == cmp.CoverageMode
+        && DrawOverLabel == cmp.DrawOverLabel;
+  }
+
+  bool operator != (const DrawOverFilter &cmp) const
+  {
+    return CoverageMode != cmp.CoverageMode
+        || DrawOverLabel != cmp.DrawOverLabel;
+  }
+
+  DrawOverFilter()
+    : CoverageMode(PAINT_OVER_ALL), DrawOverLabel(0) {}
+  DrawOverFilter(CoverageModeType cm, LabelType label)
+    : CoverageMode(cm), DrawOverLabel(label) {}
+  DrawOverFilter(const DrawOverFilter &ref)
+    : CoverageMode(ref.CoverageMode), DrawOverLabel(ref.DrawOverLabel) {}
+};
+
+#define MAX_COLOR_LABELS 0xffff
+#define NUM_INITIAL_COLOR_LABELS 6
+
+
+#define DEFAULT_HISTOGRAM_BINS 40
+
+/**
+  A debugging function to get the system time in ms. Actual definition is
+  in SystemInterface.cxx
+  */
+long get_system_time_ms();
+
+
+/**
+  A child class around itk::SmartPointer. It's main purpose is to allow Qt
+  Creator's intellisense to work with smart pointers. The current version
+  (Qt 4.7.x) does not complete smart pointers because of typedefs used by
+  the -> operator. In the future when this goes away (or does not matter)
+  we can simply replace this class by "typedef itk::SmartPointer SmartPtr"
+  */
+template <class TObject> class SmartPtr : public itk::SmartPointer<TObject>
+{
+public:
+  typedef SmartPtr<TObject> Self;
+  typedef itk::SmartPointer<TObject> Superclass;
+
+  TObject* operator -> () const
+    { return Superclass::GetPointer(); }
+
+  SmartPtr(const Superclass &p) : Superclass(p) {}
+  SmartPtr(TObject *p) : Superclass(p) {}
+  SmartPtr() : Superclass() {}
+
+  Self &operator =(const Self &p)
+  {
+    Superclass::operator =(p);
+    return *this;
+  }
 };
 
 /************************************************************************/
@@ -144,13 +216,42 @@ struct NativeToGreyTypeFunctor
 #define irisGetMacro(name,type) \
     virtual type Get##name () const { \
     return this->m_##name; \
-} 
+}
+
+/**
+ * Get macro borrowed from VTK and modified.  Assumes m_ for private vars
+ */
+#define irisStaticGetMacro(name,type) \
+    static type Get##name () const { \
+    return this->m_##name; \
+}
+
+/**
+ * Set macro borrowed from VTK and modified.  Assumes m_ for private vars
+ */
+#define irisVirtualSetMacro(name,type) \
+    virtual void Set##name (type _arg) = 0;
+
+/**
+ * Get macro borrowed from VTK and modified.  Assumes m_ for private vars
+ */
+#define irisVirtualGetMacro(name,type) \
+    virtual type Get##name () const = 0;
+
+/**
+ * Combo get/set macro
+ */
+#define irisGetSetMacro(name,type) \
+  virtual void Set##name (type _arg) \
+    { this->m_##name = _arg; } \
+  virtual type Get##name () const \
+    { return this->m_##name; }
 
 /**
  * Set macro for strings
  */
 #define irisSetStringMacro(name) \
-    virtual void Set##name (const char *_arg) \
+    virtual void Set##name (const std::string &_arg) \
 { \
     this->m_##name = _arg; \
 } 
@@ -164,6 +265,19 @@ struct NativeToGreyTypeFunctor
 } 
 
 /**
+ * Set macro for strings
+ */
+#define irisVirtualSetStringMacro(name) \
+    virtual void Set##name (const std::string &_arg)  = 0;
+
+/**
+ * Get macro borrowed from VTK and modified.  Assumes m_ for private vars
+ */
+#define irisVirtualGetStringMacro(name) \
+    virtual const char *Get##name () const = 0;
+
+
+/**
  * A get macro for boolean variables, IsXXX instead of GetXXX
  */
 #define irisIsMacro(name) \
@@ -171,6 +285,34 @@ struct NativeToGreyTypeFunctor
     return this->m_##name; \
 } 
 
+/**
+ * A get macro for boolean variables, IsXXX instead of GetXXX
+ */
+#define irisVirtualIsMacro(name) \
+    virtual bool Is##name () const  = 0;
+
+/**
+  A macro combining the standard macros at the head of itk::Object classes
+  */
+#define irisITKObjectMacro(self,super) \
+  typedef self Self; \
+  typedef super Superclass; \
+  typedef SmartPtr<Self> Pointer; \
+  typedef SmartPtr<const Self> ConstPointer; \
+  itkTypeMacro(self, super) \
+  itkNewMacro(Self)
+
+/**
+  A macro combining the standard macros at the head of itk::Object classes,
+  excluding the New construct
+  */
+#define irisITKAbstractObjectMacro(self,super) \
+  typedef self Self; \
+  typedef super Superclass; \
+  typedef SmartPtr<Self> Pointer; \
+  typedef SmartPtr<const Self> ConstPointer; \
+  itkTypeMacro(self, super)
+
 /** 
  * A rip off from the ITK not used macro to eliminate 'parameter not used'
  * warnings 
diff --git a/Common/SNAPEventListenerCallbacks.h b/Common/SNAPEventListenerCallbacks.h
new file mode 100644
index 0000000..14ad777
--- /dev/null
+++ b/Common/SNAPEventListenerCallbacks.h
@@ -0,0 +1,77 @@
+#ifndef SNAPEVENTLISTENERCALLBACKS_H
+#define SNAPEVENTLISTENERCALLBACKS_H
+
+#include "itkObject.h"
+#include "itkCommand.h"
+
+#include "vtkObject.h"
+#include "vtkCallbackCommand.h"
+#include "vtkSmartPointer.h"
+
+
+template <class TObserver>
+unsigned long AddListener(itk::Object *sender,
+                 const itk::EventObject &event,
+                 TObserver *observer,
+                 void (TObserver::*memberFunction)())
+{
+  typedef itk::SimpleMemberCommand<TObserver> Cmd;
+  typename Cmd::Pointer cmd = Cmd::New();
+  cmd->SetCallbackFunction(observer, memberFunction);
+  return sender->AddObserver(event, cmd);
+}
+
+template <class TObserver>
+unsigned long AddListener(itk::Object *sender,
+                 const itk::EventObject &event,
+                 TObserver *observer,
+                 void (TObserver::*memberFunction)(itk::Object*, const itk::EventObject &))
+{
+  typedef itk::MemberCommand<TObserver> Cmd;
+  typename Cmd::Pointer cmd = Cmd::New();
+  cmd->SetCallbackFunction(observer, memberFunction);
+
+  return sender->AddObserver(event, cmd);
+}
+
+template <class TObserver>
+unsigned long AddListenerConst(itk::Object *sender,
+                 const itk::EventObject &event,
+                 TObserver *observer,
+                 void (TObserver::*memberFunction)(const itk::Object*, const itk::EventObject &))
+{
+  typedef itk::MemberCommand<TObserver> Cmd;
+  typename Cmd::Pointer cmd = Cmd::New();
+  cmd->SetCallbackFunction(observer, memberFunction);
+  return sender->AddObserver(event, cmd);
+}
+
+template <class TObserver>
+unsigned long AddListenerPair(
+    itk::Object *sender,
+    const itk::EventObject &event,
+    TObserver *observer,
+    void (TObserver::*memberFunction)(itk::Object*, const itk::EventObject &),
+    void (TObserver::*constMemberFunction)(const itk::Object*, const itk::EventObject &))
+{
+  typedef itk::MemberCommand<TObserver> Cmd;
+  typename Cmd::Pointer cmd = Cmd::New();
+  cmd->SetCallbackFunction(observer, memberFunction);
+  cmd->SetCallbackFunction(observer, constMemberFunction);
+  return sender->AddObserver(event, cmd);
+}
+
+
+template <class TObserver>
+unsigned long AddListenerVTK(
+    vtkObject *sender,
+    unsigned long event,
+    TObserver *observer,
+    void (TObserver::*memberFunction)(vtkObject*, unsigned long, void *))
+{
+  return sender->AddObserver(event, observer, memberFunction);
+}
+
+
+
+#endif // SNAPEVENTLISTENERCALLBACKS_H
diff --git a/Common/SNAPEvents.h b/Common/SNAPEvents.h
new file mode 100644
index 0000000..ce02d7c
--- /dev/null
+++ b/Common/SNAPEvents.h
@@ -0,0 +1,180 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef SNAPEVENTS_H
+#define SNAPEVENTS_H
+
+#include "itkEventObject.h"
+#include <ostream>
+
+
+/**
+  To enable event debugging, ITK-SNAP must be compiled with the
+  flag SNAP_DEBUG_EVENTS set. Also, the SNAP executable must be
+  launched with the --debug-events option
+  */
+#define SNAP_DEBUG_EVENTS 1
+
+// This defines the stream for event debugging
+#ifdef SNAP_DEBUG_EVENTS
+extern bool flag_snap_debug_events;
+#endif
+
+// Common events for the whole application
+itkEventMacro(IRISEvent, itk::AnyEvent)
+
+// Any event originating in VTK
+itkEventMacro(VTKEvent, IRISEvent)
+
+// Events fired by IRISApplication
+
+/** Event that never gets invoked */
+itkEventMacro(NullEvent, IRISEvent)
+
+/** 3D cursor update event */
+itkEventMacro(CursorUpdateEvent, IRISEvent)
+
+/** The set of layers loaded into SNAP has changed */
+itkEventMacro(LayerChangeEvent, IRISEvent)
+
+/** The size of the main image has changed. */
+itkEventMacro(MainImageDimensionsChangeEvent, LayerChangeEvent)
+
+/** The pose (orientation, spacing, origin) of the main image has changed */
+itkEventMacro(MainImagePoseChangeEvent, LayerChangeEvent)
+
+/** The segmentation has changed */
+itkEventMacro(SegmentationChangeEvent, IRISEvent)
+
+/** The level set image has changed (due to iteration) */
+itkEventMacro(LevelSetImageChangeEvent, IRISEvent)
+
+/** Change to the speed image */
+itkEventMacro(SpeedImageChangedEvent, LayerChangeEvent)
+
+/** Generic event representing that a model has changed */
+itkEventMacro(ModelUpdateEvent, IRISEvent)
+
+/** Change in the linked zoom state */
+itkEventMacro(LinkedZoomUpdateEvent, IRISEvent)
+
+/** A change to the UI state (see UIFlags.h)  */
+itkEventMacro(StateMachineChangeEvent, IRISEvent)
+
+/** The value of the common zoom has changed */
+itkEventMacro(ZoomLevelUpdateEvent, IRISEvent)
+
+/** Toolbar mode change */
+itkEventMacro(ToolbarModeChangeEvent, IRISEvent)
+
+/** Events used by numeric value models */
+
+// The value of the numeric model changed
+itkEventMacro(ValueChangedEvent, IRISEvent)
+
+// The domain of the numeric model changed
+itkEventMacro(DomainChangedEvent, IRISEvent)
+
+// A special event where the domain description has changed, rather than
+// the whole domain. This never occurs for NumericRange domains, but does
+// occur for domains that are lists/sets of items. In that case, this event
+// represents the situation where the set of items remains the same, but the
+// description of some of the items has changed. The GUI needs to update how
+// the items are displayed, but does not need to rebuild the list of items.
+itkEventMacro(DomainDescriptionChangedEvent, IRISEvent)
+
+// An event used by property containers that indicates that one of the child
+// properties has been modified. For the time being, there does not seem to
+// be a need to distinguish between child property value changes and domain
+// changes, so there is just a single event.
+itkEventMacro(ChildPropertyChangedEvent, IRISEvent)
+
+/** A change to appearance of a renderer, etc */
+itkEventMacro(AppearanceUpdateEvent, IRISEvent)
+
+/** Parent event for events fired by the image wrapper */
+itkEventMacro(WrapperChangeEvent, IRISEvent)
+
+/** A change to a image wrapper property (e.g., nickname) */
+itkEventMacro(WrapperMetadataChangeEvent, WrapperChangeEvent)
+
+/** A change to the visibility of a layer (stickiness, visibility) */
+itkEventMacro(WrapperVisibilityChangeEvent, WrapperMetadataChangeEvent)
+
+/** A change to the display mapping of an image wrapper (e.g. color map) */
+itkEventMacro(WrapperDisplayMappingChangeEvent, WrapperChangeEvent)
+
+/** A change to wrapper-associated user data */
+itkEventMacro(WrapperUserDataChangeEvent, WrapperChangeEvent)
+
+/** A change to wrapper-associated image processing settings */
+itkEventMacro(WrapperProcessingSettingsChangeEvent, WrapperUserDataChangeEvent)
+
+/** A change to the intensity curve */
+itkEventMacro(IntensityCurveChangeEvent, WrapperDisplayMappingChangeEvent)
+
+/** A change to the color map */
+itkEventMacro(ColorMapChangeEvent, WrapperDisplayMappingChangeEvent)
+
+/** Changes to the color label table */
+itkEventMacro(SegmentationLabelChangeEvent, IRISEvent)
+itkEventMacro(SegmentationLabelConfigurationChangeEvent, SegmentationLabelChangeEvent)
+itkEventMacro(SegmentationLabelPropertyChangeEvent, SegmentationLabelChangeEvent)
+
+/** Label under cursor changed */
+itkEventMacro(LabelUnderCursorChangedEvent, IRISEvent)
+
+/** Segmentation ROI changed */
+itkEventMacro(SegmentationROIChangedEvent, IRISEvent)
+
+/** The mapping between display coordinates and anatomical coordinates changed */
+itkEventMacro(DisplayToAnatomyCoordinateMappingChangeEvent, IRISEvent)
+
+// A setter method that fires events
+#define irisSetWithEventMacro(name,type,event) \
+    virtual void Set##name (type _arg) \
+{ \
+    if(this->m_##name != _arg) \
+      { \
+      this->m_##name = _arg; \
+      this->Modified(); \
+      this->InvokeEvent(event()); \
+      } \
+}
+
+// A macro to add observers to specific events to objects. This is here just
+// to make the code more readable, because otherwise you never know what class
+// fires what events without looking in the code.
+#define irisDeclareEventObserver(event) \
+    virtual void AddObserver_##event (itk::Command *cmd) \
+        { this->AddObserver( event() , cmd ); }
+
+#define FIRES(event) virtual bool Fires##event() const { return true; }
+
+
+
+
+#endif // SNAPEVENTS_H
diff --git a/Common/SNAPOpenGL.cxx b/Common/SNAPOpenGL.cxx
new file mode 100644
index 0000000..306ac22
--- /dev/null
+++ b/Common/SNAPOpenGL.cxx
@@ -0,0 +1,39 @@
+#include "SNAPOpenGL.h"
+#include <vnl/vnl_math.h>
+#include <vector>
+
+void
+gl_draw_circle_with_border(double x, double y, double r,
+                           int vp_width, int vp_height,
+                           Vector3ui color)
+{
+  static std::vector<double> cx, cy;
+  if(cx.size() == 0)
+    {
+    for(double a = 0; a < 2 * vnl_math::pi - 1.0e-6; a += vnl_math::pi / 20)
+      {
+      cx.push_back(cos(a));
+      cy.push_back(sin(a));
+      }
+    }
+
+  glPushMatrix();
+  glTranslated(x, y, 0.0);
+  glScaled(1.2 / vp_width, 1.2 / vp_height, 1.0);
+
+  glBegin(GL_TRIANGLE_FAN);
+  glVertex2d(0, 0);
+  for(size_t i = 0; i < cx.size(); i++)
+    glVertex2d(r * cx[i], r * cy[i]);
+  glVertex2d(r, 0);
+  glEnd();
+
+  glColor3ub(color(0), color(1), color(2));
+
+  glBegin(GL_LINE_LOOP);
+  for(size_t i = 0; i < cx.size(); i++)
+    glVertex2d(r * cx[i], r * cy[i]);
+  glEnd();
+
+  glPopMatrix();
+}
diff --git a/Common/SNAPOpenGL.h b/Common/SNAPOpenGL.h
index 49bc53c..0c9514d 100644
--- a/Common/SNAPOpenGL.h
+++ b/Common/SNAPOpenGL.h
@@ -39,18 +39,17 @@
 #include "IRISVectorTypes.h"
 
 // Include OpenGL headers according to the platform
-#ifdef __APPLE__
-  #include <OpenGL/glu.h>
-  #include <FL/gl.h>
-#else
-  #include <FL/gl.h>
-  #include <GL/glu.h>
+// #include <QtOpenGL/QtOpenGL>
+
+#if defined(WIN32)
+#include <windows.h>
 #endif
 
-#ifndef _WIN32
-  #ifndef GLU_VERSION_1_2
-    #define GLU_VERSION_1_2
-  #endif
+// Include GLU, for some reason taken out of Qt 4.8
+#if defined (__APPLE__)
+  #include <OpenGL/glu.h> 
+#else
+ #include <GL/glu.h>
 #endif
 
 // Inline functions for use with vector classes
@@ -89,5 +88,11 @@ inline void glTranslate( const Vector3d &x ) { glTranslated(x[0],x[1],x[2]); }
 inline void glScale( const Vector3f &x ) { glScalef(x[0],x[1],x[2]); }
 inline void glScale( const Vector3d &x ) { glScaled(x[0],x[1],x[2]); }
 
+void
+gl_draw_circle_with_border(double x, double y, double r,
+                           int vp_width, int vp_height,
+                           Vector3ui color);
+
+Vector3d adjust_color_luminance(const Vector3d &color, double factor);
 
 #endif // __SNAPOpenGL_h_
diff --git a/Common/SystemInterface.cxx b/Common/SystemInterface.cxx
index 2c4acea..61701ad 100644
--- a/Common/SystemInterface.cxx
+++ b/Common/SystemInterface.cxx
@@ -32,13 +32,29 @@
   PURPOSE.  See the above copyright notices for more information. 
 
 =========================================================================*/
+
+#ifdef WIN32
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif //_WIN32_WINNT
+#define _WIN32_WINNT	0x0600
+
+#include <Shlobj.h>
+#endif //WIN32
+
+
+//#define WINVER 0x0600
+//#define WINVER _WIN32_WINNT
+//#define _WIN32_IE 0x0500 
+
 #include "SystemInterface.h"
+#include "IRISException.h"
 #include "IRISApplication.h"
 #include "IRISException.h"
 #include "GlobalState.h"
 #include "SNAPRegistryIO.h"
-#include "FL/Fl_Preferences.H"
-#include "FL/filename.H"
+#include "HistoryManager.h"
+#include "UIReporterDelegates.h"
 #include <itksys/Directory.hxx>
 #include <itksys/SystemTools.hxx>
 #include "itkVoxBoCUBImageIOFactory.h"
@@ -51,59 +67,127 @@
 #ifdef WIN32
   #include <iostream>
   #include <process.h>
+  #include <windows.h>
+  #include <cstdlib>
 #else
   #include <sys/types.h> 
   #include <sys/ipc.h> 
   #include <sys/shm.h> 
   #include <unistd.h>
+  #include <sys/time.h>
 #endif
 
 using namespace std;
 using namespace itksys;
 
+// Initialize the info delegate to NULL
+SystemInfoDelegate *SystemInterface::m_SystemInfoDelegate = NULL;
+
+#if defined(WIN32)
+
+std::string
+SystemInterface::GetApplicationDataDirectory()
+{
+  // TODO: when the username is not ASCII, this crashes!
+  wchar_t path_w[4096];
+  DWORD bufferSize = GetEnvironmentVariableW(L"APPDATA", path_w, 4096);
+  if (!bufferSize)
+    throw IRISException("Can not access APPDATA path on WIN32.");
+
+  // Convert to multi-byte
+  int size_needed = WideCharToMultiByte(CP_UTF8, 0, &path_w[0], wcslen(path_w), NULL, 0, NULL, NULL);
+  std::string utf8_path(size_needed, 0);
+  WideCharToMultiByte                  (CP_UTF8, 0, &path_w[0], wcslen(path_w), &utf8_path[0], size_needed, NULL, NULL);
+
+  if(utf8_path.length() == 0)
+    throw IRISException("Can not convert APPDATA path to multi-byte string");
+
+  // Temporary crap-out
+  if(utf8_path.length() != wcslen(path_w))
+    throw IRISException("ITK-SNAP currently does not support non-ASCII characters in user names on Windows (tm) platforms. This will be fixed in the future.");
+
+  // Append the full information
+  std::string strPath = utf8_path + "/itksnap.org/ITK-SNAP";
+
+  itksys::SystemTools::ConvertToUnixSlashes(strPath);
+
+  return strPath;
+}
+
+/*
+std::string
+SystemInterface::GetApplicationDataDirectory()
+{
+  // This old code seems unnecessary - Qt delegate returns the right place for Mac
+  // std::string path("~/Library/Application Support/itksnap.org/ITK-SNAP");
+  std::string path = m_SystemInfoDelegate->GetApplicationPermanentDataLocation();
+  itksys::SystemTools::ConvertToUnixSlashes(path);
+  return path;
+}
+*/
+
+
+#elif defined(__APPLE__)
+
+std::string
+SystemInterface::GetApplicationDataDirectory()
+{
+  // This old code seems unnecessary - Qt delegate returns the right place for Mac
+  // std::string path("~/Library/Application Support/itksnap.org/ITK-SNAP");
+  std::string path = m_SystemInfoDelegate->GetApplicationPermanentDataLocation();
+  itksys::SystemTools::ConvertToUnixSlashes(path);
+  return path;
+}
+
+#else
+
+std::string
+SystemInterface::GetApplicationDataDirectory()
+{
+  std::string path("~/.itksnap.org/ITK-SNAP");
+  itksys::SystemTools::ConvertToUnixSlashes(path);
+  return path;
+}
+
+#endif
+
 SystemInterface
 ::SystemInterface()
 {
+  // Crash if no delegate
+  if(!SystemInterface::m_SystemInfoDelegate)
+    throw IRISException("Creating SystemInterface without a global SystemInfoDelegate set!");
+
   // Initialize the registry
   m_RegistryIO = new SNAPRegistryIO;
 
+  // Initialize the history manager
+  m_HistoryManager = new HistoryManager();
+
   // Register the Image IO factories that are not part of ITK
   itk::ObjectFactoryBase::RegisterFactory( 
     itk::VoxBoCUBImageIOFactory::New() );
 
-  // Create a preferences object
-  Fl_Preferences test(Fl_Preferences::USER,"itk.org","SNAP");
-  
-  // Use it to get a path for user data
-  char userDataPath[1024]; 
-  test.getUserdataPath(userDataPath,1024);
-  
-  // Construct a valid path
-  m_UserPreferenceFile = string(userDataPath) + "/" + "UserPreferences.txt";
-
-  // Get the process ID
-#ifdef WIN32
-  m_ProcessID = _getpid();
-#else
-  m_ProcessID = getpid();
-#endif
+  // Make sure we have a preferences directory
+  std::string appdir = GetApplicationDataDirectory();
+  if(!itksys::SystemTools::MakeDirectory(appdir.c_str()))
+     throw IRISException("Unable to create application data directory %s.", appdir.c_str());
 
-  // Set the message ID and last sender/message id values
-  m_LastReceivedMessageID = -1;
-  m_LastSender = -1;
-  m_MessageID = 0;
-
-  // Attach to the shared memory
-  IPCAttach();
+  // Set the preferences file
+  m_UserPreferenceFile = appdir + "/UserPreferences.xml";
 }
 
 SystemInterface
 ::~SystemInterface()
 {
   delete m_RegistryIO;
+  delete m_HistoryManager;
+}
 
-  // Detach shared memory
-  IPCClose();
+string SystemInterface::GetFullPathToExecutable() const
+{
+  assert(m_SystemInfoDelegate);
+  return m_SystemInfoDelegate->GetApplicationFile();
 }
 
 
@@ -111,7 +195,11 @@ void
 SystemInterface
 ::SaveUserPreferences()
 {
-  WriteToFile(m_UserPreferenceFile.c_str());
+  // Write all the global histories to the registry
+  m_HistoryManager->SaveGlobalHistory(this->Folder("IOHistory"));
+
+  // Write the registry to disk
+  WriteToXMLFile(m_UserPreferenceFile.c_str());
 }
 
 
@@ -123,7 +211,7 @@ SystemInterface
   if(SystemTools::FileExists(m_UserPreferenceFile.c_str()))
     {
     // Read the contents of the preferences from file
-    ReadFromFile(m_UserPreferenceFile.c_str());
+    ReadFromXMLFile(m_UserPreferenceFile.c_str());
 
     // Check if the preferences contain a version string
     string version = Entry("System.CreatedBySNAPVersion")["00000000"];
@@ -136,201 +224,180 @@ SystemInterface
       this->Clear();
       }
     }
+
   // Enter the current SNAP version into the registry
   Entry("System.CreatedBySNAPVersion") << SNAPCurrentVersionReleaseDate;
+
+  // Read all the global histories from the file.
+  m_HistoryManager->LoadGlobalHistory(this->Folder("IOHistory"));
 }
 
-/** 
- * A method that checks whether the SNAP system directory can be found and 
- * if it can't, prompts the user for the directory.  The path parameter is the
- * location of the executable, i.e., argv[0] 
- */
-bool 
-SystemInterface
-::FindDataDirectory(const char *pathToExe)
+void SystemInterface
+::LaunchChildSNAP(int argc, char **argv, bool terminate_parent)
 {
-  // Get the directory where the SNAP executable was launched
-  using namespace itksys;
-  typedef std::string StringType;
-
-  // This is the directory we're trying to set
-  StringType sRootDir = "";
-
-  // This is a key that we will use to represent the executable location
-  StringType sCodedExePath;
-
-  // First of all, find the executable file.  Since the program may have been
-  // in the $PATH variable, we don't know for sure where the data is
-  // Create a vector of paths that will be searched for 
-  // the file SNAPProgramDataDirectory.txt
-  StringType sExeFullPath = SystemTools::FindProgram(pathToExe);
-  if(sExeFullPath.length())
-    {
-    // Encode the path to the executable so that we can search for an associated
-    // program data path
-    sCodedExePath = EncodeFilename(sExeFullPath);    
-    }
-  else
-    {
-    // Use a dummy token, so that next time the user runs without an executable,
-    // we can find a data directory
-    sCodedExePath = "00000000";
-    }
+  // Create new argument list
+  char **newargv = new char * [argc + 2];
+
+  // Zeroth argument remains
+  newargv[0] = argv[0];
 
-  // Check if there is a path associated with the code
-  StringType sAssociationKey = 
-    Key("System.ProgramDataDirectory.Element[%s]",sCodedExePath.c_str());
-  StringType sAssociatedPath = Entry(sAssociationKey)[""];
+  // First argument is --no-fork
+  newargv[1] = new char[40];
+  strcpy(newargv[1], "--no-fork");
+
+  // Now copy all the other parameters
+  for (int i = 1; i < argc; i++)
+    newargv[i + 1] = argv[i];
+
+  newargv[argc + 1] = NULL;
+
+  // Now we have a nice argument list to send to the child SNAP process
+#ifdef WIN32
 
-  // If the associated path exists, prepemd the path to the search list
-  if(sAssociatedPath.length())
+  // On windows, these functions screw up when arguments contain spaces!
+  char **quoted = new char * [argc + 2];
+  for (int i = 0; i < argc + 1; i++)
     {
-    // Check that the associated path is a real path containing the required 
-    // file
-    StringType sSearchName = sAssociatedPath + "/" + 
-      GetProgramDataDirectoryTokenFileName();
-
-    // Perform a sanity check on the directory
-    if(SystemTools::FileIsDirectory(sAssociatedPath.c_str()) && 
-       SystemTools::FileExists(sSearchName.c_str()))
+    if (strchr(newargv[i], '  '))
       {
-      // We've found the path
-      sRootDir = sAssociatedPath;
+      //  On  windows,  try  to  get  the  short  path  instead
+      long length = 0;
+
+      //  First  obtain  the  size  needed  by  passing  NULL  and  0.
+      length = GetShortPathName(newargv[i], NULL, 0);
+      if (length == 0)
+        throw  IRISException("Unable  to  obtain  short  filename  for  %s", newargv[i]);
+
+      //  Dynamically  allocate  the  correct  size  
+      //  (terminating  null  char  was  included  in  length)
+      quoted[i] = new char[length];
+
+      //  Now  simply  call  again  using  same  long  path.
+      length = GetShortPathName(newargv[i], quoted[i], length);
+      if (length == 0)
+        throw  IRISException("Unable  to  obtain  short  filename  for  %s", newargv[i]);
+      }
+    else
+      {
+      quoted[i] = new char[strlen(newargv[i]) + 1];
+      strcpy(quoted[i], newargv[i]);
       }
-    }
-  
-  // If the associated path check failed, but the executable has been found,
-  // which should be the case the first time the program is run, look around
-  // the executable to find the path
-  if(!sRootDir.length() && sExeFullPath.length())
-    {
-    // Create a search list for the filename
-    vector<StringType> vPathList;
-
-    // Look at the directory where the exe sits
-    vPathList.push_back(
-      SystemTools::GetFilenamePath(sExeFullPath) + "/ProgramData");
-
-    // Look one directory up from that
-    vPathList.push_back(
-      SystemTools::GetFilenamePath(
-        SystemTools::GetFilenamePath(sExeFullPath)) + 
-      "/ProgramData");
-
-    // Also, for UNIX installations, look for ${INSTALL_PATH}/share/snap/ProgramData
-    vPathList.push_back(
-       SystemTools::GetFilenamePath(
-         SystemTools::GetFilenamePath(sExeFullPath)) + 
-       "/share/snap/ProgramData");
-
-    // Search for the token file in the path list
-    StringType sFoundFile = 
-      SystemTools::FindFile(
-        GetProgramDataDirectoryTokenFileName(),vPathList);
-    if(sFoundFile.length())
-      sRootDir = SystemTools::GetFilenamePath(sFoundFile);
     }
 
-  // If we still don't have a root path, there's no home
-  if(!sRootDir.length())
-    return false;
+  quoted[argc + 1] = NULL;
 
-  // Store the property, so the next time we don't have to search at all
-  Entry(sAssociationKey) << sRootDir;
-  
-  // Set the root directory and relative paths
-  m_DataDirectory = sRootDir;
+  _spawnvp(_P_NOWAIT, newargv[0], quoted);
 
-  // Append the paths to get the other directories
-  m_DocumentationDirectory = m_DataDirectory + "/HTMLHelp";
+#else
+  pid_t pid = fork();
+  if(pid == 0)
+    {
+    /* Make sure we survive our shell */
+    setsid();
 
-  // Save the path to executable
-  m_FullPathToExecutable = sExeFullPath;
+    /* Restarts the vim process, will not return. */
+    execvp(argv[0], newargv);
 
-  // Done, success
-  return true;
+    /* Should never get here! */
+    exit(-1);
+    }
+  else
+    {
+    if(terminate_parent)
+      exit(0);
+    }
+#endif
 }
 
-
 void 
 SystemInterface
-::LaunchChildSNAP(std::list<std::string> args)
+::LaunchChildSNAPSimple(std::list<std::string> args)
 {
   // Must have a valid path to the EXE
-  if(m_FullPathToExecutable.length() == 0)
+  std::string exefile = this->GetFullPathToExecutable();
+  if(exefile.length() == 0)
     throw IRISException("Path to executable unknown in LaunchChildSNAP");
 
   // Create the argument array
   char **argv = new char* [args.size()+2];
   int iarg = 0;
-  argv[iarg++] = (char *) m_FullPathToExecutable.c_str();
+  argv[iarg++] = (char *) exefile.c_str();
   for(std::list<std::string>::iterator it=args.begin(); it!=args.end(); ++it)
     argv[iarg++] = (char *) it->c_str();
   argv[iarg++] = NULL;
 
   // Create child process
-#ifdef WIN32
-  _spawnvp(_P_NOWAIT, m_FullPathToExecutable.c_str(), argv);
-#else
-  int pid;
-  if((pid = fork()) == 0)
-    {
-    if(execvp(m_FullPathToExecutable.c_str(), argv) < 0)
-      exit(-1);
-    } 
-#endif
+  LaunchChildSNAP(args.size()+1, argv, false);
 }
 
 std::string
 SystemInterface
-::GetFileInRootDirectory(const char *fnRelative)
+::FindUniqueCodeForFile(const char *file, bool generate_if_not_found)
 {
-  // Construct the file name
-  string path = m_DataDirectory + "/" + fnRelative;
+  // Convert the filename to absolute path
+  string path = SystemTools::CollapseFullPath(file);
+
+  // Convert to unix slashes for consistency
+  SystemTools::ConvertToUnixSlashes(path);
 
-  // Make sure the file exists ?
+  // Encode the filename as ASCII
+  path = EncodeFilename(path);
 
-  // Return the file
-  return path;
+  // Get the key associated with this filename
+  string key = this->Key("ImageAssociation.Mapping.Element[%s]",path.c_str());
+
+  // Return the existing code for this key
+  string code = this->Entry(key)[""];
+
+  // If the code was not found, create a new code if requested
+  if(generate_if_not_found && code.size() == 0)
+    {
+    // Compute a timestamp from the start of computer time
+    time_t timestr = time(NULL);
+
+    // Compute a hash
+    long hash = 0;
+    for(int i = 0; i < path.size(); i+=sizeof(long))
+      {
+      long word = 0;
+      for(int j = i, k = 0; j < path.size() && k < sizeof(long); j++,k++)
+        word += ((long) path[j]) << (8 * k);
+      hash ^= word;
+      }
+
+    // Create a key for the file
+    IRISOStringStream scode;
+    scode << setfill('0') << setw(16) << hex << timestr;
+    scode << setfill('0') << setw(2 * sizeof(long)) << hex << hash;
+
+    // Return the existing key or the new key
+    code = scode.str();
+
+    // Store the code
+    this->Entry(key) << code;
+    }
+
+  return code;
 }
 
 bool 
 SystemInterface
 ::FindRegistryAssociatedWithFile(const char *file, Registry &registry)
 {
-  // Convert the file to an absolute path
-  char buffer[1024];
-  fl_filename_absolute(buffer,1024,file);
-
-  // Convert to unix slashes for consistency
-  string path(buffer);
-  SystemTools::ConvertToUnixSlashes(path);
-
-  // Convert the filename to a numeric string (to prevent clashes with the Registry class)
-  path = EncodeFilename(path);
-
-  // Get the key associated with this filename
-  string key = Key("ImageAssociation.Mapping.Element[%s]",path.c_str());
-  string code = Entry(key)[""];
+  // Find the code previously associated with that file
+  string code = this->FindUniqueCodeForFile(file, false);
 
   // If the code does not exist, return w/o success
   if(code.length() == 0) return false;
 
-  // Create a preferences object for the associations subdirectory
-  Fl_Preferences test(Fl_Preferences::USER,"itk.org","SNAP/ImageAssociations");
-
-  // Use it to get a path for user data
-  char userDataPath[1024]; 
-  test.getUserdataPath(userDataPath,1024);
-
-  // Create a save filename
-  IRISOStringStream sfile;
-  sfile << userDataPath << "/" << "ImageAssociation." << code << ".txt";
+  // Generate the association filename
+  string appdir = GetApplicationDataDirectory();
+  string assfil = appdir + "/ImageAssociations/" + code + ".xml";
 
   // Try loading the registry
   try 
     {
-    registry.ReadFromFile(sfile.str().c_str());
+    registry.ReadFromXMLFile(assfil.c_str());
     return true;
     }
   catch(...)
@@ -394,32 +461,29 @@ vector<string>
 SystemInterface
 ::GetSavedObjectNames(const char *category)
 {
-  // Create a preferences object for the associations subdirectory
-  string subpath("SNAP/");
-  subpath += category;
-  Fl_Preferences pref(Fl_Preferences::USER,"itk.org",subpath.c_str());
-
-  // Use it to get a path for user data
-  char userDataPath[1024]; 
-  pref.getUserdataPath(userDataPath,1024);
+  // Make sure we have a directory for this category
+  std::string appdir = GetApplicationDataDirectory();
+  std::string catdir = appdir + std::string("/") + std::string(category);
+  if(!itksys::SystemTools::MakeDirectory(catdir.c_str()))
+     throw IRISException("Unable to create data directory %s", catdir.c_str());
 
   // Get the names
   vector<string> names;
 
   // Get the listing of all files in there
   Directory dlist;
-  dlist.Load(userDataPath);
+  dlist.Load(catdir.c_str());
   for(size_t i = 0; i < dlist.GetNumberOfFiles(); i++)
     {
     string fname = dlist.GetFile(i);
 
     // Check regular file
     ostringstream ffull; 
-    ffull << userDataPath << "/" << fname;
+    ffull << catdir << "/" << fname;
     if(SystemTools::FileExists(ffull.str().c_str(), true))
       {
       // Check extension
-      if(SystemTools::GetFilenameExtension(fname) == ".txt")
+      if(SystemTools::GetFilenameExtension(fname) == ".xml")
         {
         string base = SystemTools::GetFilenameWithoutExtension(fname);
         string name = DecodeObjectName(base);
@@ -436,25 +500,23 @@ Registry
 SystemInterface
 ::ReadSavedObject(const char *category, const char *name)
 {
-  // Create a preferences object for the associations subdirectory
-  string subpath("SNAP/");
-  subpath += category;
-  Fl_Preferences pref(Fl_Preferences::USER,"itk.org",subpath.c_str());
-
-  // Use it to get a path for user data
-  char userDataPath[1024]; 
-  pref.getUserdataPath(userDataPath,1024);
+  // Make sure we have a directory for this category
+  std::string appdir = GetApplicationDataDirectory();
+  std::string catdir = appdir + std::string("/") + std::string(category);
+  if(!itksys::SystemTools::MakeDirectory(catdir.c_str()))
+     throw IRISException("Unable to create data directory %s", catdir.c_str());
 
   // Create a save filename
   IRISOStringStream sfile;
-  sfile << userDataPath << "/" << EncodeObjectName(name) << ".txt";
+  sfile << catdir << "/" << EncodeObjectName(name) << ".xml";
   string fname = sfile.str();
 
   // Check the filename
   if(!SystemTools::FileExists(fname.c_str(), true))
     throw IRISException("Saved object file does not exist");
 
-  Registry reg(fname.c_str());
+  Registry reg;
+  reg.ReadFromXMLFile(fname.c_str());
   return reg;
 }
 
@@ -462,40 +524,34 @@ void
 SystemInterface
 ::UpdateSavedObject(const char *category, const char *name, Registry &folder)
 {
-  // Create a preferences object for the associations subdirectory
-  string subpath("SNAP/");
-  subpath += category;
-  Fl_Preferences pref(Fl_Preferences::USER,"itk.org",subpath.c_str());
-
-  // Use it to get a path for user data
-  char userDataPath[1024]; 
-  pref.getUserdataPath(userDataPath,1024);
+  // Make sure we have a directory for this category
+  std::string appdir = GetApplicationDataDirectory();
+  std::string catdir = appdir + std::string("/") + std::string(category);
+  if(!itksys::SystemTools::MakeDirectory(catdir.c_str()))
+     throw IRISException("Unable to create data directory %s", catdir.c_str());
 
   // Create a save filename
   IRISOStringStream sfile;
-  sfile << userDataPath << "/" << EncodeObjectName(name) << ".txt";
+  sfile << catdir << "/" << EncodeObjectName(name) << ".xml";
   string fname = sfile.str();
 
   // Save the data
-  folder.WriteToFile(fname.c_str());
+  folder.WriteToXMLFile(fname.c_str());
 }
 
 void 
 SystemInterface
 ::DeleteSavedObject(const char *category, const char *name)
 {
-  // Create a preferences object for the associations subdirectory
-  string subpath("SNAP/");
-  subpath += category;
-  Fl_Preferences pref(Fl_Preferences::USER,"itk.org",subpath.c_str());
-
-  // Use it to get a path for user data
-  char userDataPath[1024]; 
-  pref.getUserdataPath(userDataPath,1024);
+  // Make sure we have a directory for this category
+  std::string appdir = GetApplicationDataDirectory();
+  std::string catdir = appdir + std::string("/") + std::string(category);
+  if(!itksys::SystemTools::MakeDirectory(catdir.c_str()))
+     throw IRISException("Unable to create data directory %s", catdir.c_str());
 
   // Create a save filename
   IRISOStringStream sfile;
-  sfile << userDataPath << "/" << EncodeObjectName(name) << ".txt";
+  sfile << catdir << "/" << EncodeObjectName(name) << ".txt";
 
   // Save the data
   SystemTools::RemoveFile(sfile.str().c_str());
@@ -509,9 +565,13 @@ SystemInterface
 ::EncodeFilename(const string &src)
 {
   IRISOStringStream sout;
-  
-  for(unsigned int i=0;i<src.length();i++)
-    sout << setw(2) << setfill('0') << hex << (int)src[i];
+
+  const char *chararray = src.c_str();
+  for(unsigned int i=0;i<strlen(chararray);i++)
+    {
+    unsigned char c = (unsigned char) chararray[i];
+    sout << setw(2) << setfill('0') << (int) c;
+    }
 
   return sout.str();
 }
@@ -520,45 +580,23 @@ bool
 SystemInterface
 ::AssociateRegistryWithFile(const char *file, Registry &registry)
 {
-  // Convert the file to an absolute path
-  char buffer[1024];
-  fl_filename_absolute(buffer,1024,file);
-
-  // Convert to unix slashes for consistency
-  string path(buffer);
-  SystemTools::ConvertToUnixSlashes(path);
-  path = EncodeFilename(path);
-
-  // Compute a timestamp from the start of computer time
-  time_t timestr = time(NULL);
-
-  // Create a key for the file
-  IRISOStringStream scode;
-  scode << setfill('0') << setw(16) << hex << timestr;
-  
-  // Look for the file in the registry (may already exist, if not use the
-  // code just generated
-  string key = Key("ImageAssociation.Mapping.Element[%s]",path.c_str());
-  string code = Entry(key)[scode.str().c_str()];
+  // Get the unique code
+  string code = FindUniqueCodeForFile(file, true);
   
-  // Put the key in the registry
-  Entry(key) << code;
+  // Create an association file in the settings directory
+  string appdir = this->GetApplicationDataDirectory();
+  string assdir = appdir + "/ImageAssociations";
+  if(!SystemTools::MakeDirectory(assdir.c_str()))
+    throw IRISException("Unable to create image associations directory %s",
+                        assdir.c_str());
 
-  // Create a preferences object for the associations subdirectory
-  Fl_Preferences test(Fl_Preferences::USER,"itk.org","SNAP/ImageAssociations");
-
-  // Use it to get a path for user data
-  char userDataPath[1024]; 
-  test.getUserdataPath(userDataPath,1024);
-
-  // Create a save filename
-  IRISOStringStream sfile;
-  sfile << userDataPath << "/" << "ImageAssociation." << code << ".txt";
+  // Create the association filename
+  string assfil = assdir + "/" + code + ".xml";
 
   // Store the registry to that path
   try 
     {
-    registry.WriteToFile(sfile.str().c_str());
+    registry.WriteToXMLFile(assfil.c_str());
     return true;
     }
   catch(...)
@@ -582,6 +620,24 @@ SystemInterface
   return AssociateRegistryWithFile(file,registry);
 }
 
+std::string
+SystemInterface
+::GetThumbnailAssociatedWithFile(const char *file)
+{
+  // Get a string giving the thumbnail name
+  string code = this->FindUniqueCodeForFile(file, true);
+
+  // Create an association file in the settings directory
+  string appdir = this->GetApplicationDataDirectory();
+  string thumbdir = appdir + "/Thumbnails";
+  if(!SystemTools::MakeDirectory(thumbdir.c_str()))
+    throw IRISException("Unable to create thumbnail directory %s",
+                        thumbdir.c_str());
+
+  // Create the association filename
+  return thumbdir + "/" + code + ".png";
+}
+
 bool 
 SystemInterface
 ::RestoreSettingsAssociatedWithImageFile(
@@ -603,274 +659,6 @@ SystemInterface
     return false;
 }
 
-/** Get a filename history list by a particular name */
-SystemInterface::HistoryListType 
-SystemInterface
-::GetHistory(const char *key)
-{
-  // Get the history array
-  return Folder("IOHistory").Folder(string(key)).GetArray(string(""));
-}
-
-/** Update a filename history list with another filename */
-void
-SystemInterface
-::UpdateHistory(const char *key, const char *filename)
-{
-  // Create a string for the new file
-  string file(filename);
-
-  // Get the current history registry
-  HistoryListType array = GetHistory(key);
-
-  // First, search the history for the instance of the file and delete
-  // existing occurences
-  HistoryListType::iterator it;
-  while((it = find(array.begin(),array.end(),file)) != array.end())
-    array.erase(it);
-
-  // Append the file to the end of the array
-  array.push_back(file);
-
-  // Trim the array to appropriate size
-  if(array.size() > 20)
-    array.erase(array.begin(),array.begin() + array.size() - 20);
-
-  // Store the new array to the registry
-  Folder("IOHistory").Folder(string(key)).PutArray(array);
-
-  // Save the preferences at this point
-  SaveUserPreferences();
-}
-
-
-// We start versioning at 1000. Every time we change
-// the protocol, we should increment the version id
-const short SystemInterface::IPC_VERSION = 0x1003;
-
-void
-SystemInterface
-::IPCAttach()
-{
-  // Initialize the data pointer
-  m_IPCSharedData = NULL;
-
-  // Determine size of shared memory
-  size_t msize = sizeof(IPCMessage) + sizeof(short);
-
-#ifdef WIN32
-  // Create a shared memory block (key based on the preferences file)
-  m_IPCHandle = CreateFileMapping(
-    INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, msize, m_UserPreferenceFile.c_str());
-
-  // If the return value is NULL, something failed
-  if(m_IPCHandle)
-    {
-    // Attach to the shared memory block
-    m_IPCSharedData = MapViewOfFile(m_IPCHandle, FILE_MAP_ALL_ACCESS, 0, 0, msize);
-    }
-
-#else
-
-  // Create a unique key for this user 
-  key_t keyid = ftok(m_UserPreferenceFile.c_str(), IPC_VERSION);
-
-  // Get a handle to shared memory
-  m_IPCHandle = shmget(keyid, msize, IPC_CREAT | 0644);
-
-  // There may be an error!
-  if(m_IPCHandle < 0)
-    {
-    cerr << "Shared memory (shmget) error: " << strerror(errno) << endl;
-    cerr << "Multisession support is disabled" << endl;
-    m_IPCSharedData = NULL;
-    }
-  else
-    {
-    // Get a pointer to shared data block
-    m_IPCSharedData = shmat(m_IPCHandle, (void *) 0, 0);
-
-    // Check errors again
-    if(!m_IPCSharedData)
-      {
-      cerr << "Shared memory (shmat) error: " << strerror(errno) << endl;
-      cerr << "Multisession support is disabled" << endl;
-      m_IPCSharedData = NULL;
-      }
-    }
-
-#endif
-
-}
-
-bool 
-SystemInterface
-::IPCRead(IPCMessage &msg)
-{
-  // Must have some shared memory
-  if(!m_IPCSharedData) 
-    return false;
-
-  // Read the first short, make sure it's the version number
-  short *vid = static_cast<short *>(m_IPCSharedData);
-  if(*vid != IPC_VERSION)
-    return false;
-
-  // Cast shared memory to the message type
-  IPCMessage *p = reinterpret_cast<IPCMessage *>(vid + 1);
-
-  // Return a copy
-  msg = *p;
-
-  // Store the last sender / id
-  m_LastSender = p->sender_pid;
-  m_LastReceivedMessageID = p->message_id;
-
-  // Success!
-  return true;
-}
-
-
-bool 
-SystemInterface
-::IPCReadIfNew(IPCMessage &msg)
-{
-  // Must have some shared memory
-  if(!m_IPCSharedData) 
-    return false;
-
-  // Read the first short, make sure it's the version number
-  short *vid = static_cast<short *>(m_IPCSharedData);
-  if(*vid != IPC_VERSION)
-    return false;
-
-  // Cast shared memory to the message type
-  IPCMessage *p = reinterpret_cast<IPCMessage *>(vid + 1);
-
-  // If we are the sender, the message should be ignored
-  if(p->sender_pid == this->GetProcessID())
-    return false;
-
-  // If we have already seen this message from this sender, also ignore it
-  if(m_LastSender == p->sender_pid && m_LastReceivedMessageID == p->message_id)
-    return false;
-
-  // Store the last sender / id
-  m_LastSender = p->sender_pid;
-  m_LastReceivedMessageID = p->message_id;
-
-  // Return a copy
-  msg = *p;
-
-  // Success!
-  return true;
-}
-
-bool
-SystemInterface
-::IPCBroadcastCursor(Vector3d cursor)
-{
-  // Try reading the current memory
-  IPCMessage mcurr;
-  
-  // This may fail, but that's ok
-  IPCRead(mcurr);
-
-  // Update the message
-  mcurr.cursor = cursor;
-  return IPCBroadcast(mcurr);
-}
-
-bool
-SystemInterface
-::IPCBroadcastTrackball(Trackball tball)
-{
-  // Try reading the current memory
-  IPCMessage mcurr;
-  
-  // This may fail, but that's ok
-  IPCRead(mcurr);
-
-  // Update the message
-  mcurr.trackball = tball;
-  return IPCBroadcast(mcurr);
-}
-
-bool
-SystemInterface
-::IPCBroadcastZoomLevel(double zoom_level)
-{
-  // Try reading the current memory
-  IPCMessage mcurr;
-  
-  // This may fail, but that's ok
-  IPCRead(mcurr);
-
-  // Update the message
-  mcurr.zoom_level = zoom_level;
-  return IPCBroadcast(mcurr);
-}
-
-bool
-SystemInterface
-::IPCBroadcastViewPosition(Vector2f vec[3])
-{
-  // Try reading the current memory
-  IPCMessage mcurr;
-  
-  // This may fail, but that's ok
-  IPCRead(mcurr);
-
-  // Update the message
-  mcurr.viewPositionRelative[0] = vec[0];
-  mcurr.viewPositionRelative[1] = vec[1];
-  mcurr.viewPositionRelative[2] = vec[2];
-
-  return IPCBroadcast(mcurr);
-}
-
-bool
-SystemInterface
-::IPCBroadcast(IPCMessage msg)
-{
-  // Write to the shared memory
-  if(m_IPCSharedData)
-    {
-    // Write version number
-    short *vid = static_cast<short *>(m_IPCSharedData);
-    *vid = IPC_VERSION;
-
-    // Write the process ID
-    msg.sender_pid = this->GetProcessID();
-    msg.message_id = ++m_MessageID;
-
-    // Write message
-    IPCMessage *p = reinterpret_cast<IPCMessage *>(vid + 1);
-    *p = msg;
-
-    // Done
-    return true;
-    }
-  return false;
-}
-
-void 
-SystemInterface
-::IPCClose()
-{
-#ifdef WIN32
-  CloseHandle(m_IPCHandle);
-#else
-  // Detach from the shared memory segment
-  shmdt(m_IPCSharedData);
-
-  // If there is noone attached to the memory segment, destroy it
-  struct shmid_ds dsinfo;
-  shmctl(m_IPCHandle, IPC_STAT, &dsinfo);
-  if(dsinfo.shm_nattch == 0)
-    shmctl(m_IPCHandle, IPC_RMID, NULL);
-#endif
-}
 
 
 // Socket headers
@@ -896,22 +684,20 @@ SystemInterface
     {
     // Check the last update time stamp
     string lastUpdateTimeStamp = Entry("System.LastUpdateTimeStamp")["00000000"];
+
     // check for update every week
     if (atoi(lastUpdateTimeStamp.c_str()) == 0)
       {
-   	 // std::cout << "initialize auto update" << std::endl;
       Entry("System.LastUpdateTimeStamp") << time(NULL);
-	 }
+      }
     else if (atoi(lastUpdateTimeStamp.c_str()) + 604800 >= time(NULL))
       {
-      // std::cout << "too soon for auto update check" << std::endl;
       return US_TOO_SOON;
       }
     else
       {
-   	 // std::cout << "auto update" << std::endl;
       Entry("System.LastUpdateTimeStamp") << time(NULL);
-  	 }
+      }
     }
 
   int rv = -1, sockfd = -1, n = -1;
@@ -972,7 +758,7 @@ SystemInterface
 
     // Create the HTTP request
     ostringstream oss;
-    oss << "GET /version/" << SNAPArch 
+    oss << "GET /version3/" << SNAPArch
       << ".txt HTTP/1.1\r\nHost: www.itksnap.org\r\n\r\n";
 
     // Create HTTP request
@@ -1011,7 +797,8 @@ SystemInterface
 
     // Read the next four values
     unsigned int vmajor = 0, vminor = 0, vpatch = 0;
-    string vqual;
+    string vqual, vdate;
+    iss >> vdate;
     iss >> vmajor;
     iss >> vminor;
     iss >> vpatch;
@@ -1019,13 +806,13 @@ SystemInterface
 
     // Format the version in printable format
     ostringstream over;
-    over << vmajor << "." << vminor << "." << vpatch << vqual;
+    over << vmajor << "." << vminor << "." << vpatch;
+    if(vqual.length())
+      over << "-" << vqual;
     newversion = over.str();
 
     // Compare version
-    if(vmajor > SNAPVersionMajor
-      || (vmajor == SNAPVersionMajor && vminor > SNAPVersionMinor)
-      || (vmajor == SNAPVersionMajor && vminor == SNAPVersionMinor && vpatch > SNAPVersionPatch))
+    if(atoi(vdate.c_str()) > atoi(SNAPCurrentVersionReleaseDate))
       us = US_OUT_OF_DATE;
     else 
       us = US_UP_TO_DATE;
@@ -1051,3 +838,17 @@ SystemInterface
   return us;
 }
 
+long get_system_time_ms()
+{
+#ifdef WIN32
+  SYSTEMTIME time;
+  GetSystemTime(&time);
+  WORD millis = (time.wSecond * 1000) + time.wMilliseconds;
+  return (long) millis;
+#else
+  timeval time;
+  gettimeofday(&time, NULL);
+  long millis = (time.tv_sec * 1000) + (time.tv_usec / 1000);
+  return millis;
+#endif
+}
diff --git a/Common/SystemInterface.h b/Common/SystemInterface.h
index decc03d..2b00492 100644
--- a/Common/SystemInterface.h
+++ b/Common/SystemInterface.h
@@ -37,10 +37,13 @@
 #define __SystemInterface_h_
 
 #include "Registry.h"
-#include "Trackball.h"
+#include "GlobalState.h"
 
 class IRISApplication;
 class SNAPRegistryIO;
+class HistoryManager;
+class SystemInfoDelegate;
+class vtkCamera;
 
 #ifdef WIN32
 #include <windows.h>
@@ -58,18 +61,22 @@ public:
   SystemInterface();
   virtual ~SystemInterface();
 
-  /** 
-   * A method that checks whether the SNAP system directory can be found and 
-   * if it can't, prompts the user for the directory.  If the user refuses to 
-   * supply the directory, it throws an exception 
+  /**
+   * Set a pointer to the delegate class that can be used to access
+   * system-specific information. This method should be called before
+   * the first time SystemInterface is constructed, otherwise an exception
+   * will be fired.
    */
-  bool FindDataDirectory(const char *pathToExe);
+  static SystemInfoDelegate * GetSystemInfoDelegate()
+    { return m_SystemInfoDelegate; }
 
-  /** 
-   * Get a file relative to the root directory (returns absolute filename), or
-   * throws exception if the file does not exist
+  static void SetSystemInfoDelegate(SystemInfoDelegate *_arg)
+    { m_SystemInfoDelegate = _arg; }
+
+  /**
+   * Get the full path to executable
    */
-  std::string GetFileInRootDirectory(const char *fnRelative);
+  std::string GetFullPathToExecutable() const;
 
   /** Loads the registry containing user preferences */
   void LoadUserPreferences();
@@ -78,9 +85,9 @@ public:
   void SaveUserPreferences();
 
   /** Get the filename for the user preferences */
-  const char *GetUserPreferencesFileName() 
-  { 
-    return m_UserPreferenceFile.c_str(); 
+  const char *GetUserPreferencesFileName()
+  {
+    return m_UserPreferenceFile.c_str();
   }
 
   /** The name of the token file that sits at the root of the program data
@@ -90,14 +97,8 @@ public:
     return "SNAPProgramDataDirectory.txt";
   }
 
-  // Typedef for history lists
-  typedef std::vector<std::string> HistoryListType;
-
   /** Get a filename history list by a particular name */
-  HistoryListType GetHistory(const char *key);
-
-  /** Update a filename history list with another filename */
-  void UpdateHistory(const char *key, const char *file);
+  irisGetMacro(HistoryManager, HistoryManager*);
 
   /** Find and load a registry file associated with a filename in the system.*/
   bool FindRegistryAssociatedWithFile(const char *file, 
@@ -106,6 +107,9 @@ public:
   /** Find and load a registry file associated with a filename in the system */
   bool AssociateRegistryWithFile(const char *file, Registry &registry);
 
+  /** Get the thumbnail filename associated with an image file */
+  std::string GetThumbnailAssociatedWithFile(const char *file);
+
   /** A higher level method: associates current settings with the current image
    * so that the next time the image is loaded, it can be saved */
   bool AssociateCurrentSettingsWithCurrentImageFile(
@@ -129,8 +133,8 @@ public:
   Registry ReadSavedObject(const char *category, const char *name);
   void UpdateSavedObject(const char *category, const char *name, Registry &folder);
   void DeleteSavedObject(const char *category, const char *name);
-  std::string DecodeObjectName(std::string fname);
-  std::string EncodeObjectName(std::string fname);
+  static std::string DecodeObjectName(std::string fname);
+  static std::string EncodeObjectName(std::string fname);
 
   
   /** 
@@ -140,49 +144,6 @@ public:
   */
   void LoadPreviousGreyImageFile(const char *filename, Registry *registry);
 
-  /** Structure passed on to IPC */
-  struct IPCMessage 
-    {
-    // Process ID of the sender
-    long sender_pid, message_id;
-
-    // The cursor position in world coordinates
-    Vector3d cursor;
-
-    // The common zoom factor (screen pixels / mm)
-    double zoom_level;   
-
-    // The position of the viewport center relative to cursor
-    // in all three slice views
-    Vector2f viewPositionRelative[3];
-
-    // 3D view settings
-    Trackball trackball;
-    };
-
-  /** Get process ID */
-  long GetProcessID() 
-    { return m_ProcessID; }
-
-  /** Interprocess communication: attach to shared memory */
-  void IPCAttach();
-
-  /** Interprocess communication: read shared memory */
-  bool IPCRead(IPCMessage &mout);
-
-  /** Read IPC message, but only if it's new data */
-  bool IPCReadIfNew(IPCMessage &mout);
-
-  /** Interprocess communication: write shared memory */
-  bool IPCBroadcast(IPCMessage mout);
-  bool IPCBroadcastCursor(Vector3d cursor);
-  bool IPCBroadcastTrackball(Trackball tball);
-  bool IPCBroadcastZoomLevel(double zoom);
-  bool IPCBroadcastViewPosition(Vector2f vec[3]);
-
-  /** Interprocess communication: release shared memory */
-  void IPCClose();
-
   /** Enum for automatic update checking */
   enum UpdateStatus 
     {
@@ -196,43 +157,37 @@ public:
   UpdateStatus CheckUpdate(std::string &newversion, size_t sec, size_t usec, bool force = false);
 
   /**
-   * Launch a child SNAP process with specified command line options
+   * Launch a child SNAP process with specified command line options. The first
+   * option in argv should be the path to the SNAP executable
    */
-  void LaunchChildSNAP(std::list<std::string> args);
+  static void LaunchChildSNAP(int argc, char **argv, bool terminate_parent);
+
+  /** Simplified, non-static version of the above */
+  void LaunchChildSNAPSimple(std::list<std::string> args);
 
 private:
   std::string m_UserPreferenceFile;
-  std::string m_DataDirectory;
   std::string m_DocumentationDirectory;
-  std::string m_FullPathToExecutable;
 
   // An object used to write large chunks of SNAP data to the registry
   SNAPRegistryIO *m_RegistryIO;
 
-  // Filename encoder
-  std::string EncodeFilename(const std::string &src);
+  // History manager
+  HistoryManager *m_HistoryManager;
 
-  // System-specific IPC related stuff
-#ifdef WIN32
-  HANDLE m_IPCHandle;
-#else
-  int m_IPCHandle;
-#endif
+  // Delegate
+  static SystemInfoDelegate *m_SystemInfoDelegate;
 
-  // The version of the SNAP-IPC protocol. This way, when versions are different
-  // IPC will not work. This is to account for an off chance of a someone running
-  // two different versions of SNAP
-  static const short IPC_VERSION;
+  // Filename encoder
+  std::string EncodeFilename(const std::string &src);
 
-  // Generic: shared data for IPC
-  void *m_IPCSharedData;
+  // Associate a file with a unique code
+  std::string FindUniqueCodeForFile(const char *file, bool generate_if_not_found);
 
-  // Process ID and other values used by IPC
-  long m_ProcessID, m_MessageID, m_LastSender, m_LastReceivedMessageID;
+  // Get the directory where application data (pref files, etc) should go
+  std::string GetApplicationDataDirectory();
 };
 
 
 
-
-
 #endif //__SystemInterface_h_
diff --git a/Common/ThreadSpecificData.cxx b/Common/ThreadSpecificData.cxx
new file mode 100644
index 0000000..e5ea337
--- /dev/null
+++ b/Common/ThreadSpecificData.cxx
@@ -0,0 +1,115 @@
+#include "ThreadSpecificData.h"
+#include "itkMultiThreader.h"
+#include "IRISException.h"
+
+#if defined(ITK_USE_PTHREADS)
+
+void ThreadSpecificDataSupport::Deleter(void *p)
+{
+  free(p);
+}
+
+ThreadSpecificDataSupport::ThreadSpecificDataSupport()
+{
+  // Allocate storage for a key
+  pthread_key_t *pkey = new pthread_key_t[1];
+
+  // Create the key
+  int rc = pthread_key_create(pkey, &ThreadSpecificDataSupport::Deleter);
+  if(rc)
+    throw IRISException("pthread_key_create failed with rc = %d", rc);
+
+  // Store the key
+  m_KeyPointer = pkey;
+}
+
+ThreadSpecificDataSupport::~ThreadSpecificDataSupport()
+{
+  // Delete the key
+  pthread_key_t *pkey = (pthread_key_t *) m_KeyPointer;
+  int rc = pthread_key_delete(pkey[0]);
+  if(rc)
+    throw IRISException("pthread_key_delete failed with rc = %d", rc);
+}
+
+void *ThreadSpecificDataSupport::GetPtrCreateIfNeeded(size_t data_size)
+{
+  pthread_key_t *pkey = (pthread_key_t *) m_KeyPointer;
+  void *pdata = pthread_getspecific(pkey[0]);
+  if(!pdata)
+    {
+    pdata = malloc(data_size);
+    int rc  = pthread_setspecific(pkey[0], pdata);
+    if(rc)
+      throw IRISException("pthread_setspecific failed with rc = %d", rc);
+    }
+  return pdata;
+}
+
+void *ThreadSpecificDataSupport::GetPtr() const
+{
+  pthread_key_t *pkey = (pthread_key_t *) m_KeyPointer;
+  void *pdata = pthread_getspecific(pkey[0]);
+  return pdata;
+}
+
+#elif defined(ITK_USE_WIN32_THREADS)
+
+void ThreadSpecificDataSupport::Deleter(void *p)
+{
+}
+
+ThreadSpecificDataSupport::ThreadSpecificDataSupport()
+{
+  DWORD *key = new DWORD[1];
+  key[0] = TlsAlloc();
+  if(key[0] == TLS_OUT_OF_INDEXES)
+    throw IRISException("TlsAlloc failed with error %d", GetLastError());
+  m_KeyPointer = key;
+}
+
+ThreadSpecificDataSupport::~ThreadSpecificDataSupport()
+{
+  DWORD *key = (DWORD *) m_KeyPointer;
+  
+  // Delete the stored stuff
+  void *pdata = TlsGetValue(key[0]);
+  if(pdata)
+    free(pdata);
+
+  TlsFree(key[0]);
+  delete [] key;
+}
+
+void *ThreadSpecificDataSupport::GetPtrCreateIfNeeded(size_t data_size)
+{
+  DWORD *key = (DWORD *) m_KeyPointer;
+  void *pdata = TlsGetValue(key[0]);
+
+  if(!pdata)
+    {
+    if(GetLastError() != ERROR_SUCCESS)
+      throw IRISException("TlsGetValue failed with error %d", GetLastError());
+
+    pdata = malloc(data_size);
+    if(!TlsSetValue(key[0], pdata))
+      throw IRISException("TlsSetValue failed with error %d", GetLastError());
+    }
+
+  return pdata;
+}
+
+void *ThreadSpecificDataSupport::GetPtr() const
+{
+  DWORD *key = (DWORD *) m_KeyPointer;
+  void *pdata = TlsGetValue(key[0]);
+  return pdata;
+}
+
+
+#else
+
+#pragma warning("No support for non-pthread threads in ITK-SNAP yet!")
+
+#endif
+
diff --git a/Common/ThreadSpecificData.h b/Common/ThreadSpecificData.h
new file mode 100644
index 0000000..71ae387
--- /dev/null
+++ b/Common/ThreadSpecificData.h
@@ -0,0 +1,76 @@
+#ifndef THREADSPECIFICDATA_H
+#define THREADSPECIFICDATA_H
+
+#include <cstdlib>
+
+/** Support class for ThreadSpecificData */
+class ThreadSpecificDataSupport
+{
+public:
+  ThreadSpecificDataSupport();
+  ~ThreadSpecificDataSupport();
+
+  /**
+    Get a pointer to the cached data, allocating memory of data_size bytes
+    if cached data does not exist. The data will be automatically deallocated
+    when the thread terminates
+    */
+  void *GetPtrCreateIfNeeded(size_t datasize);
+
+  /**
+    Get a pointer. If it has not been created (a value already assigned),
+    then this will return NULL.
+    */
+  void *GetPtr() const;
+
+protected:
+
+  static void Deleter(void *p);
+
+  // The key. To avoid having to do platform-specific stuff here,
+  // we just make this key a void pointer. The key is used to create
+  // specific data objects;
+  void *m_KeyPointer;
+};
+
+/**
+  Encapsulates the functionality provided by pthread_key_create,
+  pthread_getspecific and pthread_setspecific. This allows an instance
+  of an atomic type to be cached on a per-thread basis. To use this class
+  in an ITK filter, just add a variable of this type to the class. Then,
+  inside of the threaded code, use the object as you would a regular variable
+  to set and get the values.
+  */
+template <class TAtomic>
+class ThreadSpecificData
+{
+public:
+  typedef ThreadSpecificData<TAtomic> Self;
+
+  /**
+    Assign a value to the cache. Make sure to do this before trying to access
+    the value using the cast operator below, or you will get a segfault.
+    */
+  Self & operator = (const TAtomic &value)
+  {
+    TAtomic *p = (TAtomic *)(m_Support.GetPtrCreateIfNeeded(sizeof(TAtomic)));
+    *p = value;
+    return *this;
+  }
+
+  /**
+    Get the value from the cache. If the value has not been previously set,
+    this will probably segfault. For speed, there is no check implemented!
+    */
+  operator TAtomic() const
+  {
+    TAtomic *p = (TAtomic *)(m_Support.GetPtr());
+    return *p;
+  }
+
+protected:
+
+  ThreadSpecificDataSupport m_Support;
+};
+
+#endif // THREADSPECIFICDATA_H
diff --git a/UserInterface/Window3D/Trackball.cxx b/Common/Trackball.cxx
similarity index 100%
rename from UserInterface/Window3D/Trackball.cxx
rename to Common/Trackball.cxx
diff --git a/Common/Trackball.h b/Common/Trackball.h
new file mode 100644
index 0000000..36b31fb
--- /dev/null
+++ b/Common/Trackball.h
@@ -0,0 +1,129 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Trackball.h,v $
+  Language:  C++
+  Date:      $Date: 2007/12/30 04:05:29 $
+  Version:   $Revision: 1.2 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#ifndef __Trackball_h_
+#define __Trackball_h_
+
+#include <SNAPOpenGL.h>
+
+/**
+ * \class Trackball
+ * \brief Virtual trackball for the 3D window
+ *
+ * \sa Window3D
+ */
+class Trackball  
+{
+private:
+  GLboolean m_TrackingMotion;
+  float m_Angle;
+  float m_Axis[3];
+  float m_LastPosition[3];
+  GLfloat m_RotationMatrix[4][4];
+  GLfloat m_Zoom, m_OldZoom;
+  GLfloat m_PanX, m_PanY;
+  GLfloat m_OldPanX, m_OldPanY;
+  
+  void PToV( int x, int y, int width, int height, float v[3] );
+
+public:
+  Trackball();
+  Trackball( const Trackball& T );
+  ~Trackball();
+
+  void Reset();
+  void StartPan( int x, int y );
+  void StopPan();
+  void TrackPan( int x, int y, int w, int h, float ratew, float rateh );
+  void StartZoom( int y );
+  void StopZoom();
+  void TrackZoom( int y );
+  void StartRot( int x, int y, int w, int h );
+  void StopRot();
+  void TrackRot( int x, int y, int w, int h );
+  inline GLfloat *GetRot() { return( (GLfloat*) m_RotationMatrix ); };
+  inline GLfloat GetZoom() { return( m_Zoom ); };
+  inline GLfloat GetPanX() { return( m_PanX ); };
+  inline GLfloat GetPanY() { return( m_PanY ); };
+};
+
+#endif // __Trackball_h_
+
+/*
+ *$Log: Trackball.h,v $
+ *Revision 1.2  2007/12/30 04:05:29  pyushkevich
+ *GPL License
+ *
+ *Revision 1.1  2006/12/02 04:22:27  pyushkevich
+ *Initial sf checkin
+ *
+ *Revision 1.1.1.1  2006/09/26 23:56:17  pauly2
+ *Import
+ *
+ *Revision 1.5  2004/08/26 18:29:20  pauly
+ *ENH: New user interface for configuring the UI options
+ *
+ *Revision 1.4  2003/10/02 14:55:53  pauly
+ *ENH: Development during the September code freeze
+ *
+ *Revision 1.1  2003/09/11 13:51:15  pauly
+ *FIX: Enabled loading of images with different orientations
+ *ENH: Implemented image save and load operations
+ *
+ *Revision 1.3  2003/08/27 14:03:24  pauly
+ *FIX: Made sure that -Wall option in gcc generates 0 warnings.
+ *FIX: Removed 'comment within comment' problem in the cvs log.
+ *
+ *Revision 1.2  2003/08/27 04:57:47  pauly
+ *FIX: A large number of bugs has been fixed for 1.4 release
+ *
+ *Revision 1.1  2003/07/12 04:46:51  pauly
+ *Initial checkin of the SNAP application into the InsightApplications tree.
+ *
+ *Revision 1.3  2003/07/12 01:34:18  pauly
+ *More final changes before ITK checkin
+ *
+ *Revision 1.2  2003/07/11 23:25:33  pauly
+ **** empty log message ***
+ *
+ *Revision 1.1  2003/03/07 19:29:48  pauly
+ *Initial checkin
+ *
+ *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
+ *Started the project repository
+ *
+ *
+ *Revision 1.2  2002/03/08 14:06:32  moon
+ *Added Header and Log tags to all files
+ **/
diff --git a/Documentation/DesignNotes/gui_design.txt b/Documentation/DesignNotes/gui_design.txt
new file mode 100644
index 0000000..a7cf2fe
--- /dev/null
+++ b/Documentation/DesignNotes/gui_design.txt
@@ -0,0 +1,56 @@
+ITK-SNAP 3.0 GUI Design Notes
+=============================
+
+
+This document contains Paul's notes on designing the second-generation user
+interface for SNAP. The notes may not be complete or up-to-date, this is more
+or less a scaratch pad for my ideas.
+
+Isolating GUI Models from GUI Toolkit (Qt)
+------------------------------------------
+
+The first design principle is that we want to make it easy in the future to
+abandon Qt in favor of some other toolkit. We just don't know how long Qt is
+going to be around. Plus, maybe one day we want to build an iPad version of
+SNAP, and this would require a native iOS implementation. So the idea is to
+move as much as possible into the toolkit-agnostic GUI Model layer, leaving
+just a thin layer that is Qt-aware.
+
+Lightweight Events
+------------------
+
+The original SNAP interface did not use events much. Instead, every call that
+would make changes to the state of the system would tell other widgets to
+update themselves. This resulted in very highly coupled code, and in a huge
+UserInterfaceLogic class, where most of the connector code resided. It also
+made it difficult to make more than cosmetic changes to the code. 
+
+In the second generation, we will make much greater use of the Observer/Event
+pattern. Objects upstream of the GUI (IRISApplication, etc) will fire events
+when their state is modified, and downstream objects will subscribe to these
+events.
+
+However, the observer pattern is quite dangerous for large projects. When
+there are lots of events and lots of listeners, it becomes very hard to keep
+track of what object is calling what object when, and it is possible to have
+situations when a downstream object is called in the middle of an update to an
+upstream object, leaving the upstream object in an incomplete state. There is
+also no control over the order in which events are processed. For for example
+action A may result in events P and Q, where Q implies P (e.g., Q =
+ImageReloaded, P = CursorMoved). You would want the downstream object to
+respond to Q before it responds to P, not the other way around. 
+
+To alleviate this problem, we are placing some constraints on the event
+handling system. Namely, event handling code has to be extremely lightweight.
+All that objects are allowed to do in response to an event is to record that
+the event took place, and notify downstream objects of the event. The actual
+handling of the event must take place later, after the action that caused the
+upstream event has completed and returned control to the Qt main loop. 
+
+How can we make it work? The most downstream objects, when receiving event
+notifications, call `QWidget::update()`. This means asking Qt to paint the
+widget on the next opportunity. When the paintEvent() occurs, the object is
+responsible for refreshing its widgets by getting the data from the model. The
+object must make sure that the upstream model is up-to-date by calling the
+model's `Update()` function. This function, in turn, checks what events have
+been sent to the model, and updates the model accordingly. 
diff --git a/Documentation/Shortcuts/Shortcuts_SNAP3.pages b/Documentation/Shortcuts/Shortcuts_SNAP3.pages
new file mode 100644
index 0000000..e01fb23
Binary files /dev/null and b/Documentation/Shortcuts/Shortcuts_SNAP3.pages differ
diff --git a/Documentation/Shortcuts/Shortcuts_SNAP3.pdf b/Documentation/Shortcuts/Shortcuts_SNAP3.pdf
new file mode 100644
index 0000000..a90af72
Binary files /dev/null and b/Documentation/Shortcuts/Shortcuts_SNAP3.pdf differ
diff --git a/GUI/Model/AbstractLayerAssociatedModel.h b/GUI/Model/AbstractLayerAssociatedModel.h
new file mode 100644
index 0000000..fa7131d
--- /dev/null
+++ b/GUI/Model/AbstractLayerAssociatedModel.h
@@ -0,0 +1,258 @@
+#ifndef ABSTRACTLAYERASSOCIATEDMODEL_H
+#define ABSTRACTLAYERASSOCIATEDMODEL_H
+
+#include "AbstractModel.h"
+#include "LayerAssociation.h"
+#include "GlobalUIModel.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "SNAPEventListenerCallbacks.h"
+#include "ImageWrapperBase.h"
+#include "PropertyModel.h"
+
+/**
+  This is an abstract class for a special type of UI model that can be
+  associated with different image layers in SNAP. Examples of these models
+  are models for contrast adjustment, colormap adjustment, etc., i.e.,
+  models that link the GUI with one image layer. Two options were available:
+  to associate a single such model with each image layer, or to create just
+  one model, and allow the layer for that model to be switched. I chose
+  the second option because it reduced the number of models that have to be
+  kept around. However, the model has to keep track of layer-specific
+  properties, and also has to be smart about registering and unregistering
+  for events originating from the layers.
+
+  This class is templated over a properties object, which contains some
+  layer-specific properties that the model needs to store. For example, it
+  can be the number of histogram bins to display for the contrast dialog.
+
+  The second parameter is the type of the image wrapper that can participate
+  in the association. It can be ImageWrapperBase or one of its subclasses.
+*/
+template <class TProperties, class TWrapper = ImageWrapperBase>
+class AbstractLayerAssociatedModel : public AbstractModel
+{
+public:
+
+  typedef AbstractLayerAssociatedModel<TProperties,TWrapper> Self;
+  typedef AbstractModel Superclass;
+  typedef SmartPtr<Self> Pointer;
+  typedef SmartPtr<const Self> ConstPointer;
+  itkTypeMacro(AbstractLayerAssociatedModel, AbstractModel)
+
+  // An event fired when the selected layer changes
+  itkEventMacro(ActiveLayerChangedEvent, ModelUpdateEvent)
+  itkEventMacro(LayerStructureChangedEvent, ModelUpdateEvent)
+
+  FIRES(LayerStructureChangedEvent)
+  FIRES(ActiveLayerChangedEvent)
+
+  irisGetMacro(ParentModel, GlobalUIModel *)
+  void SetParentModel(GlobalUIModel *parent)
+  {
+    // Store the parent model
+    m_ParentModel = parent;
+
+    // Associate the layers with properties.
+    m_LayerProperties.SetSource(m_ParentModel->GetDriver());
+
+    // Layer changes in the parent are rebroadcast as model updates
+    Rebroadcast(m_ParentModel, LayerChangeEvent(), LayerStructureChangedEvent());
+
+    // Set active layer to NULL
+    this->SetLayer(NULL);
+  }
+
+
+
+  /**
+    Set the layer with which the model is associated. This can be NULL,
+    in which case, the model will be dissasociated from all layers.
+    */
+  void SetLayer(TWrapper *layer)
+  {
+    // There is nothing to do if the layer is already set
+    if(layer && m_Layer == layer)
+      return;
+
+    // Make sure the layer-specific stuff is up to date
+    m_LayerProperties.Update();
+
+    // Unregister from the current layer
+    if(m_LayerProperties.HasLayer(m_Layer))
+      {
+      // Remove the deletion listener
+      m_Layer->RemoveObserver(m_DeleteEventObserverTag);
+
+      // Call the child's unregister method
+      this->UnRegisterFromLayer(m_Layer, false);
+      }
+
+    // Set the layer
+    m_Layer = layer;
+
+    // Handle events. Need to be careful here, because layers are dynamically
+    // changing, and we don't want to add more than one observer to any layer.
+    // Note that we don't remove the observer from the old layer because when
+    // this method is called, the old layer may have already been destroyed!
+    if(m_Layer)
+      {
+      // Listen for delete events from the layer
+      m_DeleteEventObserverTag =
+          AddListener(m_Layer, itk::DeleteEvent(),
+                      this, &Self::LayerDeletionCallback);
+
+#ifdef SNAP_DEBUG_EVENTS
+      if(flag_snap_debug_events)
+        {
+        std::cout << "DeleteEvent registration "
+                  << " layer " << m_Layer << " id " << m_Layer->GetUniqueId()
+                  << " observer " << this << std::endl << std::flush;
+        }
+#endif
+
+      // Do whatever needs to be done to listen to layer events
+      this->RegisterWithLayer(m_Layer);
+      }
+
+    // Fire an event to indicate the change
+    InvokeEvent(ActiveLayerChangedEvent());
+  }
+
+
+  /** Get the layer associated with the model, or NULL if there is none */
+  irisGetMacro(Layer, TWrapper *)
+
+  /** Get the properties associated with the current layer */
+  TProperties &GetProperties()
+  {
+    assert(m_Layer);
+    TProperties *p = m_LayerProperties[m_Layer];
+    return *p;
+  }
+
+
+  /**
+    This method should be implemented by the child class. It registers
+    the child class to rebroadcast whatever events it needs from the layer
+    with which it has been associated to the downstream objects.
+  */
+  virtual void RegisterWithLayer(TWrapper *layer) = 0;
+
+
+  /**
+    This method should be implemented by the child class. It disconnects
+    the chold class from the associated layer (just before breaking the
+    association). For the Register/Unregister pair to work, the Register
+    method implementation should retain the tag returned by the call to
+    the Rebroadcast method. This tag can be placed in the layer-associated
+    properties, and then used during the call to UnRegister.
+
+    The second parameter to this method specifies whether the method is
+    called in response to the layer being deleted or not. If they layer is
+    being deleted, we are unsure about the state of the layer and we don't
+    need to remove observers from it.
+. */
+  virtual void UnRegisterFromLayer(TWrapper *layer, bool being_deleted) = 0;
+
+  /**
+    The model has its own OnUpdate implementation, which handles changes
+    in the layer structure. If the event bucket has a LayerChangeEvent,
+    the model will automatically rebuild it's layer associations, and
+    may reset the current layer to NULL if the current layer has been
+    removed.
+
+    If child models reimplement OnUpdate(), they must call
+    AbstractLayerAssociatedModel::OnUpdate() within the reimplemented method.
+    */
+  virtual void OnUpdate()
+  {
+    if(m_EventBucket->HasEvent(LayerChangeEvent()))
+      {
+      // If the layers have changed, we need to update the layer properties
+      // object. Then we need to see if the current layer has actually been
+      // destroyed
+      m_LayerProperties.Update();
+
+      // Was the current layer removed?
+      if(!m_LayerProperties.HasLayer(m_Layer))
+        this->SetLayer(NULL);
+      }
+  }
+
+  /**
+   * A boolean property model indicating whether the model is holding a
+   * layer or not. This can be used to toggle parts of the user interface
+   */
+  irisGetMacro(HasLayerModel, AbstractSimpleBooleanProperty * )
+
+
+protected:
+  AbstractLayerAssociatedModel()
+  {
+    // Set up the factory
+    PropertiesFactory factory;
+    factory.m_Model = this;
+    m_LayerProperties.SetDelegate(factory);
+
+    m_ParentModel = NULL;
+    m_Layer = NULL;
+
+    m_HasLayerModel = wrapGetterSetterPairAsProperty(
+          this, &Self::GetHasLayerValue);
+  }
+
+  virtual ~AbstractLayerAssociatedModel() {}
+
+  /** Create a  property object for a new layer */
+  TProperties *CreateProperty(TWrapper *w)
+  {
+    return new TProperties();
+  }
+
+  void LayerDeletionCallback()
+  {
+    // Unregister from the current layer
+    this->UnRegisterFromLayer(m_Layer, true);
+
+    // Set the layer to NULL
+    m_Layer = NULL;
+
+    // Fire an event to indicate the change
+    InvokeEvent(ActiveLayerChangedEvent());
+  }
+
+  // Parent model
+  GlobalUIModel *m_ParentModel;
+
+  // Currently associated layer
+  TWrapper *m_Layer;
+
+  // Tag used to manage deletion observers on the current layer
+  unsigned long m_DeleteEventObserverTag;
+
+  // A factory class for creating properties
+  class PropertiesFactory
+  {
+  public:
+    TProperties *New(TWrapper *w)
+      { return m_Model->CreateProperty(w); }
+    Self *m_Model;
+  };
+
+  // Model as to whether the layer is set
+  SmartPtr<AbstractSimpleBooleanProperty> m_HasLayerModel;
+  bool GetHasLayerValue()
+  {
+    return this->m_Layer != NULL;
+  }
+
+  // Association between a layer and a set of properties
+  typedef LayerAssociation<
+    TProperties,TWrapper,PropertiesFactory> LayerMapType;
+
+  LayerMapType m_LayerProperties;
+
+};
+
+#endif // ABSTRACTLAYERASSOCIATEDMODEL_H
diff --git a/GUI/Model/AbstractLayerInfoItemSetDomain.h b/GUI/Model/AbstractLayerInfoItemSetDomain.h
new file mode 100644
index 0000000..12219ee
--- /dev/null
+++ b/GUI/Model/AbstractLayerInfoItemSetDomain.h
@@ -0,0 +1,62 @@
+#ifndef ABSTRACTLAYERINFOITEMSETDOMAIN_H
+#define ABSTRACTLAYERINFOITEMSETDOMAIN_H
+
+#include <PropertyModel.h>
+#include <IRISApplication.h>
+
+/**
+  This is a base class for domain descriptions that provide some piece
+  of information about every ITK-SNAP layer. This is used in conjunction
+  with the PropertyModel system to provide the GUI with tables and combos
+  that list layers, along with specific properties of interest.
+  */
+template <class TDesc>
+class AbstractLayerInfoItemSetDomain :
+    public AbstractItemSetDomain<size_t, TDesc, LayerIterator>
+{
+public:
+
+  // To avoid storing pointers, we cast them into size_t objects. Otherwise
+  // this screws up some of the Qt stuff
+  typedef size_t ValueType;
+
+  /** Initializes domain that iterates through layers based on the filter */
+  AbstractLayerInfoItemSetDomain(IRISApplication *app = NULL,
+                                 int role_filter = ALL_ROLES)
+    { m_Driver = app; m_RoleFilter = role_filter; }
+
+  LayerIterator begin() const
+  {
+    return m_Driver->GetCurrentImageData()->GetLayers(m_RoleFilter);
+  }
+
+  LayerIterator end() const
+  {
+    return m_Driver->GetCurrentImageData()->GetLayers(m_RoleFilter).MoveToEnd();
+  }
+
+  LayerIterator find(const ValueType &value) const
+  {
+    return m_Driver->GetCurrentImageData()->GetLayers(m_RoleFilter).Find(
+          reinterpret_cast<ImageWrapperBase *>(value));
+  }
+
+  ValueType GetValue(const LayerIterator &it) const
+  {
+    return reinterpret_cast<size_t>(it.GetLayer());
+  }
+
+  bool operator == (const AbstractLayerInfoItemSetDomain<TDesc> &cmp) const
+    { return m_Driver == cmp.m_Driver && m_RoleFilter == cmp.m_RoleFilter; }
+
+  bool operator != (const AbstractLayerInfoItemSetDomain<TDesc> &cmp) const
+    { return m_Driver != cmp.m_Driver || m_RoleFilter != cmp.m_RoleFilter; }
+
+  virtual bool isAtomic() { return false; }
+
+protected:
+  IRISApplication *m_Driver;
+  int m_RoleFilter;
+};
+
+#endif // ABSTRACTLAYERINFOITEMSETDOMAIN_H
diff --git a/GUI/Model/CollectionModel.cxx b/GUI/Model/CollectionModel.cxx
new file mode 100644
index 0000000..78f4076
--- /dev/null
+++ b/GUI/Model/CollectionModel.cxx
@@ -0,0 +1,5 @@
+#include "CollectionModel.h"
+
+CollectionModel::CollectionModel()
+{
+}
diff --git a/GUI/Model/CollectionModel.h b/GUI/Model/CollectionModel.h
new file mode 100644
index 0000000..ff5337b
--- /dev/null
+++ b/GUI/Model/CollectionModel.h
@@ -0,0 +1,210 @@
+#ifndef COLLECTIONMODEL_H
+#define COLLECTIONMODEL_H
+
+#include "AbstractModel.h"
+
+
+/**
+ * A model representing a collection of items. Each item has a unique value
+ * (like a key in a database) and a descriptor (object describing the item's
+ * properties). The model supports iteration. The model can be wrapped around
+ * an existing stl container, or it can subclass from an stl container.
+ *
+ * The model emits events when there are changes in the structure of the
+ * collection, as well as when there are changes in the descriptors of the
+ * collection.
+ *
+ * The model is meant to interface with GUI list/combo/table widgets.
+ */
+template <class TVal, class TDesc, class TIterator>
+class AbstractCollectionModel : public AbstractModel
+{
+public:
+  typedef TIterator const_iterator;
+  typedef TVal ValueType;
+  typedef TDesc DescriptorType;
+
+  FIRES(CollectionStructureChangedEvent)
+  FIRES(CollectionDataChangedEvent)
+
+  virtual const_iterator begin() const = 0;
+  virtual const_iterator end() const  = 0;
+  virtual const_iterator find(const TVal &value) const = 0;
+  virtual TVal GetValue(const const_iterator &it) const  = 0;
+  virtual TDesc GetDescription(const const_iterator &it) const  = 0;
+  virtual void SetDescription(const const_iterator &it, const TDesc &desc) const {}
+  virtual ~AbstractItemSetDomain() {}
+};
+
+
+/**
+  This is an implementation of the domain that wraps around an stl::map from
+  values to descriptors. The map is not stored in the domain, but referenced
+  from another object to avoid duplicating data.
+  */
+template <class TVal, class TDesc>
+class STLMapWrapperModel :
+    public AbstractCollectionModel<TVal, TDesc,
+                                 typename std::map<TVal,TDesc>::const_iterator>
+{
+public:
+
+  typedef typename std::map<TVal, TDesc> MapType;
+  typedef typename MapType::const_iterator const_iterator;
+  typedef AbstractCollectionModel<TVal, TDesc, const_iterator> Superclass;
+  typedef STLMapWrapperModel<TVal, TDesc> Self;
+
+  itkNewMacro(Self)
+  itkTypeMacro(STLMapWrapperModel, AbstractCollectionModel)
+
+  const_iterator begin() const
+    { assert(m_SourceMap); return m_SourceMap->begin(); }
+
+  const_iterator end() const
+    { assert(m_SourceMap); return m_SourceMap->end(); }
+
+  const_iterator find(const TVal &value) const
+    { assert(m_SourceMap); return m_SourceMap->find(value); }
+
+  TVal GetValue(const const_iterator &it) const
+    { return it->first; }
+
+  TDesc GetDescription(const const_iterator &it) const
+    { return it->second; }
+
+  void SetWrappedMap(const MapType *refmap) { m_SourceMap = refmap; }
+
+  virtual bool operator == (const Self &cmp) const
+    { return m_SourceMap == cmp.m_SourceMap; }
+
+  virtual bool operator != (const Self &cmp) const
+    { return m_SourceMap != cmp.m_SourceMap; }
+
+  // An atomic domain holds its own state, so it is possible to compare two
+  // atomic domains to determine if they are the same or different. Domains
+  // that store references to external objects are not atomic.
+  virtual bool isAtomic() { return false; }
+
+protected:
+  STLMapWrapperModel() { m_SourceMap = NULL; }
+  STLMapWrapperModel(const MapType *refmap) { m_SourceMap = refmap; }
+  virtual ~STLMapWrapperModel() {}
+
+  const MapType *m_SourceMap;
+};
+
+
+/**
+  This is an implementation of the domain that wraps around an stl::vector
+  of descriptors. TVal should be an integer type that can be used as an index
+  (int, unsigned int, enum, etc)
+  */
+template <class TVal, class TDesc>
+class STLVectorWrapperModel :
+    public AbstractCollectionModel<TVal, TDesc,
+                                 typename std::vector<TDesc>::const_iterator>
+{
+public:
+
+  typedef STLVectorWrapperModel<TVal, TDesc> Self;
+  typedef typename std::vector<TDesc> VectorType;
+  typedef typename VectorType::const_iterator const_iterator;
+  typedef AbstractCollectionModel<TVal, TDesc, const_iterator> Superclass;
+
+  itkNewMacro(Self)
+  itkTypeMacro(STLMapWrapperModel, AbstractCollectionModel)
+
+  const_iterator begin() const
+    { assert(m_SourceVector); return m_SourceVector->begin(); }
+
+  const_iterator end() const
+    { assert(m_SourceVector); return m_SourceVector->end(); }
+
+  const_iterator find(const TVal &value) const
+    { assert(m_SourceVector); return m_SourceVector->begin() + value; }
+
+  TVal GetValue(const const_iterator &it) const
+    { assert(m_SourceVector); return it - m_SourceVector->begin(); }
+
+  TDesc GetDescription(const const_iterator &it) const
+    { assert(m_SourceVector); return *it; }
+
+  virtual bool operator == (const Self &cmp) const
+    { return m_SourceVector == cmp.m_SourceVector; }
+
+  virtual bool operator != (const Self &cmp) const
+    { return m_SourceVector != cmp.m_SourceVector; }
+
+  // An atomic domain holds its own state, so it is possible to compare two
+  // atomic domains to determine if they are the same or different. Domains
+  // that store references to external objects are not atomic.
+  virtual bool isAtomic() { return false; }
+
+protected:
+  STLVectorWrapperModel() { m_SourceVector = NULL; }
+  STLVectorWrapperModel(const VectorType *refvec) { m_SourceVector = refvec; }
+  virtual ~STLVectorWrapperModel() {}
+
+  const VectorType *m_SourceVector;
+};
+
+/**
+  This is an item domain implementation that is just an stl::map, i.e., it
+  owns the data, as opposed to STLMapWrapperItemSetDomain, which references
+  the data from another map. This implementation is useful for small domains
+  where there is no cost in passing the domain by value.
+  */
+template<class TVal, class TDesc>
+class ConcreteItemCollectionModel : public
+    AbstractCollectionModel<TVal, TDesc, typename std::map<TVal,TDesc>::const_iterator>
+{
+public:
+  typedef std::map<TVal, TDesc> MapType;
+  typedef typename MapType::const_iterator const_iterator;
+  typedef ConcreteItemCollectionModel<TVal, TDesc> Self;
+  typedef AbstractCollectionModel<TVal, TDesc, const_iterator> Superclass;
+
+  itkNewMacro(Self)
+  itkTypeMacro(ConcreteItemCollectionModel, AbstractCollectionModel)
+
+  const_iterator begin() const
+    { return m_Map.begin(); }
+
+  const_iterator end() const
+    { return m_Map.end(); }
+
+  const_iterator find(const TVal &value) const
+    { return m_Map.find(value); }
+
+  TVal GetValue(const const_iterator &it) const
+    { return it->first; }
+
+  TDesc GetDescription(const const_iterator &it) const
+    { return it->second; }
+
+  // Standard stl::map operator
+  TDesc & operator [] (const TVal &key) { return m_Map[key]; }
+
+  const TDesc & operator [] (const TVal &key) const { return m_Map[key]; }
+
+  virtual bool operator == (const Self &cmp) const
+    { return m_Map == cmp.m_Map; }
+
+  virtual bool operator != (const Self &cmp) const
+    { return m_Map != cmp.m_Map; }
+
+  // An atomic domain holds its own state, so it is possible to compare two
+  // atomic domains to determine if they are the same or different. Domains
+  // that store references to external objects are not atomic.
+  virtual bool isAtomic() { return true; }
+
+protected:
+  SimpleItemSetDomain() : Superclass() { }
+
+  MapType m_Map;
+};
+
+
+
+
+#endif // COLLECTIONMODEL_H
diff --git a/GUI/Model/ColorLabelPropertyModel.cxx b/GUI/Model/ColorLabelPropertyModel.cxx
new file mode 100644
index 0000000..fe198c1
--- /dev/null
+++ b/GUI/Model/ColorLabelPropertyModel.cxx
@@ -0,0 +1,143 @@
+#include "ColorLabelPropertyModel.h"
+#include <GlobalState.h>
+
+void ConcreteColorLabelPropertyModel
+::Initialize(ColorLabelTable *clt)
+{
+  // Ititialize the domain representation
+  DomainType dom(&clt->GetValidLabels());
+  this->SetDomain(dom);
+
+  // We should also listen to events from the label table, and rebroadcast
+  // as changes to the domain. Note that there are two types of changes to the
+  // label table, one that is a reconfiguration and another that is a property
+  // change. These map to different kinds of domain change events.
+  Rebroadcast(clt, SegmentationLabelConfigurationChangeEvent(), DomainChangedEvent());
+  Rebroadcast(clt, SegmentationLabelPropertyChangeEvent(), DomainDescriptionChangedEvent());
+}
+
+DrawOverLabelItemSetIterator
+::DrawOverLabelItemSetIterator(ColorLabelTable *table)
+{
+  m_LabelIter = table->GetValidLabels().begin();
+  m_PointedMode = PAINT_OVER_ALL;
+}
+
+DrawOverLabelItemSetIterator&
+DrawOverLabelItemSetIterator
+::operator ++()
+{
+  // Iterate over modes
+  if(m_PointedMode == PAINT_OVER_ALL)
+    m_PointedMode = PAINT_OVER_VISIBLE;
+  else if(m_PointedMode == PAINT_OVER_VISIBLE)
+    m_PointedMode = PAINT_OVER_ONE;
+  else
+    ++m_LabelIter;
+
+  return *this;
+}
+
+bool
+DrawOverLabelItemSetIterator
+::operator ==(const Self &comp)
+{
+  return (m_PointedMode == comp.m_PointedMode)
+      && (m_LabelIter == comp.m_LabelIter);
+}
+
+bool
+DrawOverLabelItemSetIterator
+::operator !=(const Self &comp)
+{
+  return (m_PointedMode != comp.m_PointedMode)
+      || (m_LabelIter != comp.m_LabelIter);
+}
+
+DrawOverLabelItemSetDomain
+::DrawOverLabelItemSetDomain()
+{
+  m_LabelTable = NULL;
+}
+
+void DrawOverLabelItemSetDomain
+::Initialize(ColorLabelTable *clt)
+{
+  this->m_LabelTable = clt;
+}
+
+DrawOverLabelItemSetDomain::const_iterator
+DrawOverLabelItemSetDomain::begin() const
+{
+  const_iterator it(m_LabelTable);
+  return it;
+}
+
+DrawOverLabelItemSetDomain::const_iterator
+DrawOverLabelItemSetDomain::end() const
+{
+  const_iterator it(m_LabelTable);
+  it.m_PointedMode = PAINT_OVER_ONE;
+  it.m_LabelIter = m_LabelTable->end();
+  return it;
+}
+
+DrawOverLabelItemSetDomain::const_iterator
+DrawOverLabelItemSetDomain::find(const DrawOverFilter &value) const
+{
+  const_iterator it(m_LabelTable);
+  it.m_PointedMode = value.CoverageMode;
+  if(value.CoverageMode == PAINT_OVER_ONE)
+    it.m_LabelIter = m_LabelTable->GetValidLabels().find(value.DrawOverLabel);
+  return it;
+}
+
+DrawOverFilter
+DrawOverLabelItemSetDomain::GetValue(const const_iterator &it) const
+{
+  DrawOverFilter filter;
+  filter.CoverageMode = it.m_PointedMode;
+  filter.DrawOverLabel = it.m_LabelIter->first;
+  return filter;
+}
+
+ColorLabel
+DrawOverLabelItemSetDomain::GetDescription(const const_iterator &it) const
+{
+  // For the override modes, return a dummy color label
+  if(it.m_PointedMode != PAINT_OVER_ONE)
+    return ColorLabel();
+  else
+    return it.m_LabelIter->second;
+}
+
+bool
+DrawOverLabelItemSetDomain::operator == (
+    const DrawOverLabelItemSetDomain &refdom)
+{
+  return m_LabelTable == refdom.m_LabelTable;
+}
+
+bool
+DrawOverLabelItemSetDomain::operator != (
+    const DrawOverLabelItemSetDomain &refdom)
+{
+  return m_LabelTable != refdom.m_LabelTable;
+}
+
+
+void ConcreteDrawOverFilterPropertyModel
+::Initialize(ColorLabelTable *clt)
+{
+  // Ititialize the domain representation
+  DomainType dom;
+  dom.Initialize(clt);
+  this->SetDomain(dom);
+
+  // We should also listen to events from the label table, and rebroadcast
+  // as changes to the domain. Note that there are two types of changes to the
+  // label table, one that is a reconfiguration and another that is a property
+  // change. These map to different kinds of domain change events.
+  Rebroadcast(clt, SegmentationLabelConfigurationChangeEvent(), DomainChangedEvent());
+  Rebroadcast(clt, SegmentationLabelPropertyChangeEvent(), DomainDescriptionChangedEvent());
+}
diff --git a/GUI/Model/ColorLabelPropertyModel.h b/GUI/Model/ColorLabelPropertyModel.h
new file mode 100644
index 0000000..0b8e213
--- /dev/null
+++ b/GUI/Model/ColorLabelPropertyModel.h
@@ -0,0 +1,117 @@
+#ifndef COLORLABELPROPERTYMODEL_H
+#define COLORLABELPROPERTYMODEL_H
+
+#include <PropertyModel.h>
+#include <ColorLabel.h>
+#include <ColorLabelTable.h>
+
+/*
+  This module contains property models having to do with selection of
+  color labels from the color label table.
+  */
+
+// Define the domain that wraps around a std::map of color labels
+typedef STLMapWrapperItemSetDomain<LabelType, ColorLabel> ColorLabelItemSetDomain;
+
+// Base class typedef for the concrete implementation below
+typedef ConcretePropertyModel<LabelType, ColorLabelItemSetDomain>
+  ConcreteColorLabelPropertyModelBase;
+
+/**
+  This is an ITK-SNAP model that internally stores a color label and provides
+  a set of options, correponding to currently available color labels
+  */
+class ConcreteColorLabelPropertyModel
+    : public ConcretePropertyModel<LabelType, ColorLabelItemSetDomain>
+{
+public:
+  // Standard ITK stuff
+  irisITKObjectMacro(ConcreteColorLabelPropertyModel,
+                     ConcreteColorLabelPropertyModelBase)
+
+  // Domain typedef
+  typedef ColorLabelItemSetDomain DomainType;
+
+  /** Set the color label table, from which this model constructs its domain
+    representation */
+  void Initialize(ColorLabelTable *clt);
+};
+
+/**
+  This iterator presents all the draw-over options in a linear fashion.
+  It first go through the wildcard coverage modes (PAINT_OVER_ALL,
+  PAINT_OVER_VISIBLE) and then throught the valid labels
+  */
+class DrawOverLabelItemSetIterator
+{
+public:
+  typedef DrawOverLabelItemSetIterator Self;
+
+  Self& operator ++();
+
+  bool operator == (const Self &ref);
+  bool operator != (const Self &ref);
+
+  friend class DrawOverLabelItemSetDomain;
+
+private:
+  DrawOverLabelItemSetIterator(ColorLabelTable *table);
+  CoverageModeType m_PointedMode;
+  ColorLabelTable::ValidLabelConstIterator m_LabelIter;
+};
+
+// A custom domain for working with draw-over compound
+class DrawOverLabelItemSetDomain : public AbstractItemSetDomain<
+    DrawOverFilter, ColorLabel, DrawOverLabelItemSetIterator>
+{
+public:
+  typedef DrawOverLabelItemSetIterator const_iterator;
+
+  DrawOverLabelItemSetDomain();
+  virtual ~DrawOverLabelItemSetDomain() {}
+
+  void Initialize(ColorLabelTable *clt);
+
+  virtual const_iterator begin() const;
+  virtual const_iterator end() const;
+  virtual const_iterator find(const DrawOverFilter &value) const;
+  virtual DrawOverFilter GetValue(const const_iterator &it) const;
+  virtual ColorLabel GetDescription(const const_iterator &it) const;
+
+  bool operator == (const DrawOverLabelItemSetDomain &refdom);
+  bool operator != (const DrawOverLabelItemSetDomain &refdom);
+
+  bool isAtomic() { return false; }
+
+private:
+
+  ColorLabelTable *m_LabelTable;
+};
+
+// Base class for the following model
+typedef ConcretePropertyModel<DrawOverFilter, DrawOverLabelItemSetDomain>
+  ConcreteDrawOverFilterPropertyModelBase;
+
+/**
+  This is an ITK-SNAP model that internally stores a draw-over state atomic
+  object.
+  */
+class ConcreteDrawOverFilterPropertyModel
+    : public ConcreteDrawOverFilterPropertyModelBase
+{
+public:
+  // Standard ITK stuff
+  irisITKObjectMacro(ConcreteDrawOverFilterPropertyModel,
+                     ConcreteDrawOverFilterPropertyModelBase)
+
+  // Domain typedef
+  typedef DrawOverLabelItemSetDomain DomainType;
+
+  /** Set the color label table, from which this model constructs its domain
+    representation */
+  void Initialize(ColorLabelTable *clt);
+};
+
+
+
+#endif // COLORLABELPROPERTYMODEL_H
diff --git a/GUI/Model/ColorLabelQuickListModel.cxx b/GUI/Model/ColorLabelQuickListModel.cxx
new file mode 100644
index 0000000..a87cd3c
--- /dev/null
+++ b/GUI/Model/ColorLabelQuickListModel.cxx
@@ -0,0 +1,131 @@
+#include "ColorLabelQuickListModel.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "ColorLabelTable.h"
+#include <queue>
+
+ColorLabelQuickListModel::ColorLabelQuickListModel()
+{
+  m_ActiveComboModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetActiveComboValueAndRange,
+        &Self::SetActiveComboValue);
+}
+
+ColorLabelQuickListModel::~ColorLabelQuickListModel()
+{
+}
+
+/*
+void ColorLabelQuickListModel::ComputeRecent()
+{
+  // Get the color label table
+  ColorLabelTable *clt = m_Parent->GetDriver()->GetColorLabelTable();
+
+  // We use a pair of label id, access time to represent each label
+  typedef std::pair<int, int> LabelPair;
+
+  // Build the priority queue for keeping track of the most recent
+  typedef std::priority_queue<LabelPair> HeapType;
+  HeapType heap;
+
+  // Go through all the items in the label list, maintaining the smallest
+  // items in the queue
+  for(ColorLabelTable::ValidLabelConstIterator it = clt->begin();
+      it != clt->end(); ++it)
+    {
+    // Encode the label as (timestamp, -id) for sorting
+    LabelPair pair = std::make_pair(-it->second.GetTimeStamp(), (int) it->first);
+
+    // If the queue is not full, push the pair
+    if(heap.size() < m_MaxStoredLabels)
+      {
+      heap.push(pair);
+      }
+    else if(heap.top() < pair)
+      {
+      heap.pop();
+      heap.push(pair);
+      }
+    }
+
+  // Now the list has the most recent labels
+  unsigned int nItems = std::min(m_MaxStoredLabels, (unsigned int) heap.size());
+  m_RecentLabels.resize(nItems);
+  for(int i = 1; i <= nItems; i++)
+    {
+    m_RecentLabels[nItems-i] = heap.top().second;
+    heap.pop();
+    }
+
+  // Now we sort the list by label id. The effect of this is that the order
+  // of the labels in the list does not change as the user picks labels from
+  // the quick list
+  std::sort(m_RecentLabels.begin(), m_RecentLabels.end());
+}
+*/
+
+void ColorLabelQuickListModel::SetParentModel(GlobalUIModel *parent)
+{
+  m_Parent = parent;
+  m_LabelHistory = m_Parent->GetDriver()->GetLabelUseHistory();
+
+  // Rebroadcast the segmentation and color label update events as
+  // update events from this model
+  Rebroadcast(m_Parent->GetDriver()->GetColorLabelTable(),
+              SegmentationLabelConfigurationChangeEvent(), ModelUpdateEvent());
+  Rebroadcast(m_LabelHistory, itk::ModifiedEvent(), ModelUpdateEvent());
+
+  // The active label model needs to rebroadcast events from the active drawing
+  // label in GlobalState
+  m_ActiveComboModel->RebroadcastFromSourceProperty(
+        m_Parent->GetDriver()->GetGlobalState()->GetDrawingColorLabelModel());
+  m_ActiveComboModel->RebroadcastFromSourceProperty(
+        m_Parent->GetDriver()->GetGlobalState()->GetDrawOverFilterModel());
+}
+
+void ColorLabelQuickListModel::OnUpdate()
+{
+  if(!m_EventBucket->IsEmpty())
+    {
+    // Update the table of recent labels
+    m_RecentCombos.clear();
+    int nItems = m_LabelHistory->GetSize();
+    for(int i = 0; i < nItems; i++)
+      m_RecentCombos.push_back(m_LabelHistory->GetHistoryEntry(i));
+
+    // The last item is always the clear label
+    m_RecentCombos.push_back(std::make_pair(0, DrawOverFilter()));
+    }
+}
+
+
+bool ColorLabelQuickListModel::GetActiveComboValueAndRange(int &value)
+{
+  // Record the current state
+  LabelCombo state = std::make_pair(
+        m_Parent->GetGlobalState()->GetDrawingColorLabel(),
+        m_Parent->GetGlobalState()->GetDrawOverFilter());
+
+  // See if any of the active labels matches the current state
+  for(int i = 0; i < m_RecentCombos.size(); i++)
+    {
+    if(m_RecentCombos[i] == state)
+      {
+      value = i;
+      return true;
+      }
+    }
+
+  // Nothing matched, return false
+  return false;
+}
+
+void ColorLabelQuickListModel::SetActiveComboValue(int value)
+{
+  assert(value < m_RecentCombos.size());
+  LabelCombo state = m_RecentCombos[value];
+
+  m_Parent->GetGlobalState()->SetDrawingColorLabel(state.first);
+  m_Parent->GetGlobalState()->SetDrawOverFilter(state.second);
+}
diff --git a/GUI/Model/ColorLabelQuickListModel.h b/GUI/Model/ColorLabelQuickListModel.h
new file mode 100644
index 0000000..c675b65
--- /dev/null
+++ b/GUI/Model/ColorLabelQuickListModel.h
@@ -0,0 +1,59 @@
+#ifndef COLORLABELQUICKLISTMODEL_H
+#define COLORLABELQUICKLISTMODEL_H
+
+#include <PropertyModel.h>
+#include <LabelUseHistory.h>
+
+class GlobalUIModel;
+
+/**
+ * This model provides a list of the recently used color labels in ITK-SNAP.
+ * It can be used to create quick palettes of labels.
+ */
+class ColorLabelQuickListModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(ColorLabelQuickListModel, AbstractModel)
+
+  // Foreground/background label combination
+  typedef LabelUseHistory::Entry LabelCombo;
+  typedef std::vector<LabelCombo> ComboList;
+
+  /** Assign a parent model to this model */
+  void SetParentModel(GlobalUIModel *parent);
+
+  /** Get the list of combos to include */
+  irisGetMacro(RecentCombos, const ComboList &)
+
+  /** This model describes the active label combination in the quick list */
+  irisSimplePropertyAccessMacro(ActiveCombo, int)
+
+protected:
+
+  // The parent model
+  GlobalUIModel *m_Parent;
+
+  // The label history object
+  LabelUseHistory *m_LabelHistory;
+
+  // Cached list of active combos
+  ComboList m_RecentCombos;
+
+  // Model for the active label
+  SmartPtr<AbstractSimpleIntProperty> m_ActiveComboModel;
+
+  bool GetActiveComboValueAndRange(int &value);
+  void SetActiveComboValue(int value);
+
+  ColorLabelQuickListModel();
+  ~ColorLabelQuickListModel();
+
+  // Respond to an update in the model
+  virtual void OnUpdate();
+
+  // Compute the recent labels
+  void ComputeRecent();
+};
+
+#endif // COLORLABELQUICKLISTMODEL_H
diff --git a/GUI/Model/ColorMapModel.cxx b/GUI/Model/ColorMapModel.cxx
new file mode 100644
index 0000000..f5fff45
--- /dev/null
+++ b/GUI/Model/ColorMapModel.cxx
@@ -0,0 +1,661 @@
+#include "ColorMapModel.h"
+#include "LayerAssociation.txx"
+#include "NumericPropertyToggleAdaptor.h"
+#include "ColorMapPresetManager.h"
+
+#include <algorithm>
+
+// This compiles the LayerAssociation for the color map
+template class LayerAssociation<ColorMapLayerProperties,
+                                ImageWrapperBase,
+                                ColorMapModelBase::PropertiesFactory>;
+
+ColorMapModel::ColorMapModel()
+{
+  // Set up the models
+  m_MovingControlPositionModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetMovingControlPositionValueAndRange,
+        &Self::SetMovingControlPosition);
+
+  // Get the component model for opacity
+  m_MovingControlOpacityModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetMovingControlOpacityValueAndRange,
+        &Self::SetMovingControlOpacity);
+
+  m_MovingControlSideModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetMovingControlSide,
+        &Self::SetMovingControlSide);
+
+  m_MovingControlContinuityModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetMovingControlType,
+        &Self::SetMovingControlType);
+
+  m_MovingControlIndexModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetMovingControlIndexValueAndRange,
+        &Self::SetMovingControlIndex);
+
+  m_LayerOpacityModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetLayerOpacityValueAndRange,
+        &Self::SetLayerOpacity);
+
+  m_LayerVisibilityModel =
+      NewNumericPropertyToggleAdaptor(m_LayerOpacityModel.GetPointer(), 0., 50.);
+
+  // Create the color map preset manager
+  m_PresetManager = NULL;
+
+  // The model update events should also be rebroadcast as state changes
+  Rebroadcast(this, ModelUpdateEvent(), StateMachineChangeEvent());
+}
+
+ColorMap* ColorMapModel::GetColorMap(ImageWrapperBase *layer)
+{
+  // Get the display mapping cast to a type that supports colormap
+  return layer->GetDisplayMapping()->GetColorMap();
+}
+
+
+ColorMap* ColorMapModel::GetColorMap()
+{
+  return this->GetColorMap(this->GetLayer());
+}
+
+bool
+ColorMapModel
+::IsControlSelected(int cp, Side side)
+{
+  ColorMap *cm = this->GetColorMap();
+  ColorMapLayerProperties &p = this->GetProperties();
+
+  if(p.GetSelectedControlIndex() == cp)
+    {
+    if(cm->GetCMPoint(cp).m_Type == ColorMap::CONTINUOUS)
+      return true;
+    else return p.GetSelectedControlSide() == side;
+    }
+  else return false;
+}
+
+bool
+ColorMapModel
+::SetSelection(int cp, Side side)
+{
+  ColorMap *cm = this->GetColorMap();
+  ColorMapLayerProperties &p = this->GetProperties();
+  int cp_current = p.GetSelectedControlIndex();
+  Side side_current = p.GetSelectedControlSide();
+
+  // Check if the control point has changed
+  bool changed = (cp != cp_current || side != side_current);
+
+  // Check the validity of the new selection
+  if(cp >= 0)
+    {
+    bool disc = cm->GetCMPoint(cp).m_Type == ColorMap::DISCONTINUOUS;
+    assert((disc && side != ColorMapLayerProperties::NA) ||
+           (!disc && side == ColorMapLayerProperties::NA));
+    }
+  else
+    {
+    assert(side == ColorMapLayerProperties::NA);
+    }
+
+  // Set the new selection
+  if(changed)
+    {
+    p.SetSelectedControlIndex(cp);
+    p.SetSelectedControlSide(side);
+    InvokeEvent(ModelUpdateEvent());
+    }
+
+  return changed;
+}
+
+
+void ColorMapModel::RegisterWithLayer(ImageWrapperBase *layer)
+{
+  // Register for the model events
+  ColorMap *cm = this->GetColorMap(layer);
+  ColorMapLayerProperties &p = GetProperties();
+
+  // Rebroadcast wrapper change events
+  p.SetLayerObserverTag(
+        Rebroadcast(layer,WrapperDisplayMappingChangeEvent(), ModelUpdateEvent()));
+
+  // Update the cached preset value
+  if(cm)
+    p.SetSelectedPreset(m_PresetManager->QueryPreset(cm));
+}
+
+void ColorMapModel::UnRegisterFromLayer(ImageWrapperBase *layer, bool being_deleted)
+{
+  if(!being_deleted)
+    {
+    unsigned long tag;
+    ColorMapLayerProperties &p = GetProperties();
+    if((tag = p.GetLayerObserverTag()))
+      {
+      layer->RemoveObserver(tag);
+      }
+    }
+}
+
+bool ColorMapModel::ProcessMousePressEvent(const Vector3d &x)
+{
+  assert(m_ViewportReporter && m_ViewportReporter->CanReportSize());
+  Vector2ui vp = m_ViewportReporter->GetLogicalViewportSize();
+
+  // Reference to the color map
+  ColorMap *cm = this->GetColorMap();
+
+  // Check if the press occurs near a control point
+  for(size_t i = 0; i < cm->GetNumberOfCMPoints(); i++)
+    {
+    ColorMap::CMPoint p = cm->GetCMPoint(i);
+    double dx = fabs(x[0] - p.m_Index);
+    double dy0 = fabs(x[1] - p.m_RGBA[0][3] / 255.0);
+    double dy1 = fabs(x[1] - p.m_RGBA[1][3] / 255.0);
+
+    if(dx / 1.2 < 5.0 / vp[0])
+      {
+      if(dy0 / 1.2 < 5.0 / vp[1])
+        {
+        // We return 0 when the selected point changes to avoid dragging
+        if(p.m_Type == ColorMap::CONTINUOUS)
+          this->SetSelection(i, ColorMapLayerProperties::NA);
+        else
+          this->SetSelection(i, ColorMapLayerProperties::LEFT);
+        return 1;
+        }
+      else if (dy1 / 1.2 < 5.0 / vp[1])
+        {
+        this->SetSelection(i, ColorMapLayerProperties::RIGHT);
+        return true;
+        }
+      }
+    }
+
+  // No selection has been made, so we insert a new point
+  if(x[0] > 0.0 && x[0] < 1.0)
+    {
+    size_t sel = cm->InsertInterpolatedCMPoint(x[0]);
+    this->SetSelection(sel, ColorMapLayerProperties::NA);
+    return true;
+    }
+
+  return false;
+}
+
+bool ColorMapModel::ProcessMouseDragEvent(const Vector3d &x)
+{
+  // Reference to the color map
+  ColorMap *cm = this->GetColorMap();
+  ColorMapLayerProperties &p  = this->GetProperties();
+  int isel = p.GetSelectedControlIndex();
+  Side side = p.GetSelectedControlSide();
+
+  // Nothing happens if zero is selected
+  if(isel < 0) return false;
+
+  // Get the selected point
+  ColorMap::CMPoint psel = cm->GetCMPoint(isel);
+
+  // Get the new alpha and index
+  double j = x[0];
+  double a = x[1] * 255;
+
+  // Clip the new index
+  if(isel == 0 || isel == (int)cm->GetNumberOfCMPoints()-1)
+    {
+    // The first and last point can not be moved left or right
+    j = psel.m_Index;
+    }
+  else
+    {
+    // Other points are constrained by neighbors
+    ColorMap::CMPoint p0 = cm->GetCMPoint(isel-1);
+    ColorMap::CMPoint p1 = cm->GetCMPoint(isel+1);
+    if(j < p0.m_Index) j = p0.m_Index;
+    if(j > p1.m_Index) j = p1.m_Index;
+    }
+
+  // Update the index of the point
+  psel.m_Index = j;
+
+  // Clip the new alpha
+  if(a < 0) a = 0;
+  if(a > 255) a = 255;
+
+  // Assign the alpha
+  if(side != ColorMapLayerProperties::RIGHT)
+    psel.m_RGBA[0][3] = (unsigned char) a;
+  if(side != ColorMapLayerProperties::LEFT)
+    psel.m_RGBA[1][3] = (unsigned char) a;
+
+  // Redraw
+  cm->UpdateCMPoint(isel, psel);
+
+  return true;
+}
+
+bool ColorMapModel::ProcessMouseReleaseEvent(const Vector3d &x)
+{
+  return true;
+}
+
+void ColorMapModel::OnUpdate()
+{
+  Superclass::OnUpdate();
+
+  // If the preset changed or the color map changed, we should update the
+  // currently selected preset
+  if(m_Layer && this->GetColorMap())
+    {
+    if(m_EventBucket->HasEvent(itk::ModifiedEvent(), m_PresetManager)
+       || m_EventBucket->HasEvent(WrapperDisplayMappingChangeEvent()))
+      {
+      ColorMapLayerProperties &p = this->GetProperties();
+      p.SetSelectedPreset(m_PresetManager->QueryPreset(this->GetColorMap()));
+      }
+    }
+}
+
+bool
+ColorMapModel
+::GetMovingControlPositionValueAndRange(
+    double &value, NumericValueRange<double> *range)
+{
+  // When no layer is set, the value is invalid
+  if(!m_Layer) return false;
+
+  ColorMapLayerProperties &p = this->GetProperties();
+  ColorMap *cmap = this->GetColorMap();
+  int idx = p.GetSelectedControlIndex();
+  if(idx >= 0)
+    {
+    value = cmap->GetCMPoint(idx).m_Index;
+    if(range)
+      {
+      range->StepSize = 0.01;
+      if(idx == 0)
+        {
+        range->Minimum = 0.0;
+        range->Maximum = 0.0;
+        }
+      else if (idx == (int) cmap->GetNumberOfCMPoints()-1)
+        {
+        range->Minimum = 1.0;
+        range->Maximum = 1.0;
+        }
+      else
+        {
+        range->Minimum = cmap->GetCMPoint(idx - 1).m_Index;
+        range->Maximum = cmap->GetCMPoint(idx + 1).m_Index;
+        }
+      }
+    return true;
+    }
+  else return false;
+}
+
+void
+ColorMapModel
+::SetMovingControlPosition(double value)
+{
+  ColorMapLayerProperties &p = this->GetProperties();
+  ColorMap *cmap = this->GetColorMap();
+  int idx = p.GetSelectedControlIndex();
+  assert(idx >= 0);
+
+  ColorMap::CMPoint pt = cmap->GetCMPoint(idx);
+  pt.m_Index = value;
+  cmap->UpdateCMPoint(idx, pt);
+}
+
+
+
+bool ColorMapModel::GetSelectedRGBA(ColorMap::RGBAType &rgba)
+{
+  // When no layer is set, the value is invalid
+  if(!m_Layer) return false;
+
+  ColorMapLayerProperties &p = this->GetProperties();
+  ColorMap *cmap = this->GetColorMap();
+  int idx = p.GetSelectedControlIndex();
+  Side side = p.GetSelectedControlSide();
+
+  if(idx >= 0)
+    {
+    ColorMap::CMPoint pt = cmap->GetCMPoint(idx);
+    int iside = (pt.m_Type == ColorMap::DISCONTINUOUS &&
+                 side == ColorMapLayerProperties::RIGHT) ? 1 : 0;
+    rgba = pt.m_RGBA[iside];
+    return true;
+    }
+  else return false;
+}
+
+void ColorMapModel::SetSelectedRGBA(ColorMap::RGBAType rgba)
+{
+  ColorMapLayerProperties &p = this->GetProperties();
+  ColorMap *cmap = this->GetColorMap();
+  int idx = p.GetSelectedControlIndex();
+  Side side = p.GetSelectedControlSide();
+  assert(idx >= 0);
+
+  // Assign to left, right, or both sides
+  ColorMap::CMPoint pt = cmap->GetCMPoint(idx);
+  if(pt.m_Type == ColorMap::CONTINUOUS || side == ColorMapLayerProperties::LEFT)
+    pt.m_RGBA[0] = rgba;
+  if(pt.m_Type == ColorMap::CONTINUOUS || side == ColorMapLayerProperties::RIGHT)
+    pt.m_RGBA[1] = rgba;
+
+  cmap->UpdateCMPoint(idx, pt);
+}
+
+Vector3d ColorMapModel::GetSelectedColor()
+{
+  ColorMap::RGBAType rgba;
+  if(this->GetSelectedRGBA(rgba))
+    return Vector3d(rgba[0] / 255., rgba[1] / 255., rgba[2] / 255.);
+  else
+    return Vector3d(0,0,0);
+}
+
+
+void ColorMapModel::SetSelectedColor(Vector3d rgb)
+{
+  ColorMap::RGBAType rgba;
+  if(this->GetSelectedRGBA(rgba))
+    {
+    rgba[0] = (unsigned char)(255.0 * rgb[0]);
+    rgba[1] = (unsigned char)(255.0 * rgb[1]);
+    rgba[2] = (unsigned char)(255.0 * rgb[2]);
+    this->SetSelectedRGBA(rgba);
+    }
+}
+
+
+bool
+ColorMapModel
+::GetMovingControlOpacityValueAndRange(
+    double &value, NumericValueRange<double> *range)
+{
+  // When no layer is set, the value is invalid
+  if(!m_Layer) return false;
+
+  ColorMap::RGBAType rgba;
+  if(this->GetSelectedRGBA(rgba))
+    {
+    value = rgba[3] / 255.0;
+    if(range)
+      {
+      range->Set(0.0, 1.0, 0.01);
+      }
+    return true;
+    }
+  else return false;
+}
+
+void
+ColorMapModel
+::SetMovingControlOpacity(double value)
+{
+  ColorMap::RGBAType rgba;
+  if(this->GetSelectedRGBA(rgba))
+    {
+    rgba[3] = (unsigned char)(255.0 * value);
+    this->SetSelectedRGBA(rgba);
+    }
+}
+
+
+bool
+ColorMapModel
+::CheckState(ColorMapModel::UIState state)
+{
+  // All flags are false if no layer is loaded
+  if(this->GetLayer() == NULL || this->GetColorMap() == NULL)
+    return false;
+
+  // Otherwise get the properties
+  ColorMapLayerProperties &p = this->GetProperties();
+  int idx = p.GetSelectedControlIndex();
+  int npts = (int) this->GetColorMap()->GetNumberOfCMPoints();
+
+  switch(state)
+    {
+    case UIF_LAYER_ACTIVE:
+      return true;
+    case UIF_CONTROL_SELECTED:
+      return idx >= 0;
+    case UIF_CONTROL_SELECTED_IS_NOT_ENDPOINT:
+      return idx > 0 && idx < npts - 1;
+    case UIF_CONTROL_SELECTED_IS_DISCONTINUOUS:
+      return idx >= 0 && this->GetColorMap()->GetCMPoint(idx).m_Type ==
+          ColorMap::DISCONTINUOUS;
+    case UIF_PRESET_SELECTED:
+      return p.GetSelectedPreset().first != ColorMapPresetManager::PRESET_NONE;
+    case UIF_USER_PRESET_SELECTED:
+      return p.GetSelectedPreset().first == ColorMapPresetManager::PRESET_USER;
+    }
+  return false;
+}
+
+bool ColorMapModel
+::GetMovingControlSide(Side &value)
+{
+  // When no layer is set, the value is invalid
+  if(!m_Layer) return false;
+
+  ColorMapLayerProperties &p = this->GetProperties();
+  int idx = p.GetSelectedControlIndex();
+
+  if(idx >= 0)
+    {
+    value = p.GetSelectedControlSide();
+    return true;
+    }
+  return false;
+}
+
+void
+ColorMapModel
+::SetMovingControlSide(Side value)
+{
+  ColorMapLayerProperties &p = this->GetProperties();
+  ColorMap *cmap = this->GetColorMap();
+  int idx = p.GetSelectedControlIndex();
+  assert(idx >= 0);
+  ColorMap::CMPoint pt = cmap->GetCMPoint(idx);
+  assert(pt.m_Type == ColorMap::DISCONTINUOUS);
+  p.SetSelectedControlSide(value);
+  InvokeEvent(ModelUpdateEvent());
+}
+
+bool ColorMapModel::GetMovingControlType(Continuity &value)
+{
+  // When no layer is set, the value is invalid
+  if(!m_Layer) return false;
+
+  ColorMapLayerProperties &p = this->GetProperties();
+  ColorMap *cmap = this->GetColorMap();
+  int idx = p.GetSelectedControlIndex();
+
+  if(idx >= 0)
+    {
+    value = cmap->GetCMPoint(idx).m_Type;
+    return true;
+    }
+  else return false;
+}
+
+void ColorMapModel::SetMovingControlType(Continuity value)
+{
+  ColorMapLayerProperties &p = this->GetProperties();
+  ColorMap *cmap = this->GetColorMap();
+  int idx = p.GetSelectedControlIndex();
+  Side side = p.GetSelectedControlSide();
+  assert(idx >= 0);
+  ColorMap::CMPoint pt = cmap->GetCMPoint(idx);
+
+  if(value != pt.m_Type)
+    {
+    pt.m_Type = value;
+    if(value == ColorMap::CONTINUOUS)
+      {
+      p.SetSelectedControlSide(ColorMapLayerProperties::NA);
+      if(side == ColorMapLayerProperties::LEFT)
+        pt.m_RGBA[1] = pt.m_RGBA[0];
+      else
+        pt.m_RGBA[0] = pt.m_RGBA[1];
+      }
+    else
+      {
+      p.SetSelectedControlSide(ColorMapLayerProperties::LEFT);
+      }
+
+    cmap->UpdateCMPoint(idx, pt);
+    InvokeEvent(ModelUpdateEvent());
+    }
+}
+
+// TODO: this copies the names needlessly
+void ColorMapModel::GetPresets(
+    ColorMapModel::PresetList &system, ColorMapModel::PresetList &user)
+{
+  system = m_PresetManager->GetSystemPresets();
+  user = m_PresetManager->GetUserPresets();
+}
+
+void ColorMapModel::SelectPreset(const std::string &preset)
+{
+  // Is this a system preset?
+  if(preset.length())
+    m_PresetManager->SetToPreset(this->GetColorMap(), preset);
+
+  // Clear the selection
+  this->GetProperties().SetSelectedControlIndex(-1);
+  this->GetProperties().SetSelectedControlSide(ColorMapLayerProperties::NA);
+  this->InvokeEvent(ModelUpdateEvent());
+}
+
+void ColorMapModel::SetParentModel(GlobalUIModel *parent)
+{
+  Superclass::SetParentModel(parent);
+
+  // Get the pointer to the system interface
+  m_System = m_ParentModel->GetDriver()->GetSystemInterface();
+  m_PresetManager = m_ParentModel->GetDriver()->GetColorMapPresetManager();
+
+  // Rebroadcast modifications in the preset manager as our own events
+  Rebroadcast(m_PresetManager, itk::ModifiedEvent(), PresetUpdateEvent());
+}
+
+#include <algorithm>
+
+void ColorMapModel::SaveAsPreset(std::string name)
+{
+  // Save preset
+  m_PresetManager->SaveAsPreset(this->GetColorMap(), name);
+}
+
+void ColorMapModel::DeletePreset(std::string name)
+{
+  // Delete the preset
+  m_PresetManager->DeletePreset(name);
+}
+
+std::string ColorMapModel::GetSelectedPreset()
+{
+  return this->GetProperties().GetSelectedPreset().second;
+}
+
+bool ColorMapModel::GetMovingControlIndexValueAndRange(
+    int &value, NumericValueRange<int> *range)
+{
+  // When no layer is set, the value is invalid
+  if(!m_Layer) return false;
+
+  ColorMapLayerProperties &p = this->GetProperties();
+  ColorMap *cmap = this->GetColorMap();
+  int idx = p.GetSelectedControlIndex();
+  if(idx >= 0)
+    {
+    value = idx + 1;
+    if(range)
+      range->Set(1, cmap->GetNumberOfCMPoints(), 1);
+    return true;
+    }
+  return false;
+}
+
+void ColorMapModel::SetMovingControlIndex(int value)
+{
+  ColorMapLayerProperties &p = this->GetProperties();
+  ColorMap *cmap = this->GetColorMap();
+  ColorMap::CMPoint pt = cmap->GetCMPoint(value - 1);
+
+  Side newside = ColorMapLayerProperties::NA;
+  if(pt.m_Type == ColorMap::DISCONTINUOUS)
+    {
+    // Pick the side that is closest to the current selection
+    if(value < p.GetSelectedControlIndex())
+      newside = ColorMapLayerProperties::RIGHT;
+    else
+      newside = ColorMapLayerProperties::LEFT;
+    }
+
+  this->SetSelection(value - 1, newside);
+}
+
+void ColorMapModel::DeleteSelectedControl()
+{
+  ColorMapLayerProperties &p = this->GetProperties();
+  int sel = p.GetSelectedControlIndex();
+  ColorMap *cmap = this->GetColorMap();
+
+  if(sel > 0 && sel < (int)(cmap->GetNumberOfCMPoints() - 1))
+    {
+    // Delete the point
+    cmap->DeleteCMPoint(sel);
+
+    // Update the selection
+    this->SetMovingControlIndex(sel);
+    }
+}
+
+bool ColorMapModel
+::GetLayerOpacityValueAndRange(
+    double &value, NumericValueRange<double> *range)
+{
+  if(!m_Layer)
+    return false;
+
+  value = (double) (255.0 * m_Layer->GetAlpha());
+  if(range)
+    {
+    range->Set(0, 255, 1);
+    }
+
+  return true;
+}
+
+void ColorMapModel::SetLayerOpacity(double value)
+{
+  assert(m_Layer);
+  m_Layer->SetAlpha(value / 255.0);
+}
+
+
+
+
+
+
+
diff --git a/GUI/Model/ColorMapModel.h b/GUI/Model/ColorMapModel.h
new file mode 100644
index 0000000..fae95bb
--- /dev/null
+++ b/GUI/Model/ColorMapModel.h
@@ -0,0 +1,234 @@
+#ifndef COLORMAPMODEL_H
+#define COLORMAPMODEL_H
+
+#include "AbstractLayerAssociatedModel.h"
+#include "PropertyModel.h"
+#include <UIReporterDelegates.h>
+#include "ColorMap.h"
+#include "ColorMapPresetManager.h"
+
+class ColorMap;
+class SystemInterface;
+
+class ColorMapLayerProperties
+{
+public:
+
+  irisGetSetMacro(LayerObserverTag, unsigned long)
+
+  ColorMapLayerProperties()
+  {
+    m_SelectedControlIndex = -1;
+    m_SelectedControlSide = NA;
+    m_LayerObserverTag = 0;
+    m_SelectedPreset =
+        std::make_pair(ColorMapPresetManager::PRESET_NONE, std::string());
+  }
+
+  virtual ~ColorMapLayerProperties() {}
+
+  enum Side {LEFT = 0, RIGHT, NA};
+
+  irisGetSetMacro(SelectedControlIndex, int)
+  irisGetSetMacro(SelectedControlSide, Side)
+  irisGetSetMacro(SelectedPreset, ColorMapPresetManager::PresetMatch)
+
+protected:
+
+  // Control point being edited
+  int m_SelectedControlIndex;
+
+  // Side of the control point, if discontinuous
+  Side m_SelectedControlSide;
+
+  // Cached information about the currently selected preset
+  ColorMapPresetManager::PresetMatch m_SelectedPreset;
+
+  // Whether or not we are already listening to events from this layer
+  unsigned long m_ColorMapObserverTag, m_LayerObserverTag;
+};
+
+typedef AbstractLayerAssociatedModel<
+    ColorMapLayerProperties, ImageWrapperBase> ColorMapModelBase;
+
+
+/**
+  The UI model for color map editing
+  */
+class ColorMapModel : public ColorMapModelBase
+{
+public:
+  irisITKObjectMacro(ColorMapModel, ColorMapModelBase)
+
+  typedef ColorMapLayerProperties::Side Side;
+  typedef ColorMap::CMPointType Continuity;
+  typedef std::vector<std::string> PresetList;
+
+  // This event only affects this model
+  itkEventMacro(PresetUpdateEvent, IRISEvent)
+
+  // This event is fired when the presets are changed
+  FIRES(PresetUpdateEvent)
+
+  /**
+    States in which the model can be, which allow the activation and
+    deactivation of various widgets in the interface
+    */
+  enum UIState {
+    UIF_LAYER_ACTIVE,
+    UIF_CONTROL_SELECTED,
+    UIF_CONTROL_SELECTED_IS_NOT_ENDPOINT,
+    UIF_CONTROL_SELECTED_IS_DISCONTINUOUS,
+    UIF_PRESET_SELECTED,
+    UIF_USER_PRESET_SELECTED
+    };
+
+  void SetParentModel(GlobalUIModel *parent);
+
+  /**
+    Check the state flags above
+    */
+  bool CheckState(UIState state);
+
+  // Implementation of virtual functions from parent class
+  void RegisterWithLayer(ImageWrapperBase *layer);
+  void UnRegisterFromLayer(ImageWrapperBase *layer, bool being_deleted);
+
+  /** Before using the model, it must be coupled with a size reporter */
+  irisGetSetMacro(ViewportReporter, ViewportSizeReporter *)
+
+  /**
+    Process colormap box interaction events
+    */
+  bool ProcessMousePressEvent(const Vector3d &x);
+  bool ProcessMouseDragEvent(const Vector3d &x);
+  bool ProcessMouseReleaseEvent(const Vector3d &x);
+
+  /** Update the model in response to upstream events */
+  virtual void OnUpdate();
+
+  typedef AbstractPropertyModel<Continuity> ContinuityValueModel;
+  typedef AbstractPropertyModel<Side> SideValueModel;
+
+  /** The model for setting moving control point position */
+  irisGetMacro(MovingControlPositionModel, AbstractRangedDoubleProperty *)
+
+  /** The model for setting moving control point opacity */
+  irisGetMacro(MovingControlOpacityModel, AbstractRangedDoubleProperty *)
+
+  /** The model for setting moving control point continuity */
+  irisGetMacro(MovingControlContinuityModel, ContinuityValueModel *)
+
+  /** The model for setting moving control point side */
+  irisGetMacro(MovingControlSideModel, SideValueModel *)
+
+  /** The index of the moving control point */
+  irisGetMacro(MovingControlIndexModel, AbstractRangedIntProperty *)
+
+  /** The overall opacity of the selected layer */
+  irisGetMacro(LayerOpacityModel, AbstractRangedDoubleProperty *)
+
+  /** The overall visibility of the selected layer */
+  irisGetMacro(LayerVisibilityModel, AbstractSimpleBooleanProperty *)
+
+  /** Get the color map in associated layer */
+  ColorMap *GetColorMap();
+
+  /** Check whether a particular control point is selected */
+  bool IsControlSelected(int cp, Side side);
+
+  /** Set the selected control point, return true if selection
+      changed as the result */
+  bool SetSelection(int cp, Side side = ColorMapLayerProperties::NA);
+
+  /** Delete the selected control */
+  void DeleteSelectedControl();
+
+  /** Get the color of the selected point */
+  Vector3d GetSelectedColor();
+
+  /** Set the color of the selected point */
+  void SetSelectedColor(Vector3d rgb);
+
+  /** Get the list of color map presets */
+  void GetPresets(PresetList &system, PresetList &user);
+
+  /** Get the preset manager object */
+  irisGetMacro(PresetManager, ColorMapPresetManager *)
+
+  /** Select one of the presets. The index is into the combined list
+    of system and user presets */
+  void SelectPreset(const std::string &preset);
+
+  /** Save the current state as a preset */
+  void SaveAsPreset(std::string name);
+
+  /** Delete a selected preset */
+  void DeletePreset(std::string name);
+
+  /** Get the currently selected preset */
+  std::string GetSelectedPreset();
+
+protected:
+
+  ColorMapModel();
+
+  SmartPtr<AbstractRangedDoubleProperty> m_MovingControlPositionModel;
+  SmartPtr<AbstractRangedDoubleProperty> m_MovingControlOpacityModel;
+  SmartPtr<SideValueModel> m_MovingControlSideModel;
+  SmartPtr<ContinuityValueModel> m_MovingControlContinuityModel;
+  SmartPtr<AbstractRangedIntProperty> m_MovingControlIndexModel;
+  SmartPtr<AbstractRangedDoubleProperty> m_LayerOpacityModel;
+  SmartPtr<AbstractSimpleBooleanProperty> m_LayerVisibilityModel;
+
+  // A pointer to the system interface object
+  SystemInterface *m_System;
+
+  // A size reporter delegate (notifies the model when the size of the
+  // corresponding widget changes).
+  ViewportSizeReporter *m_ViewportReporter;
+
+  // Color map preset manager
+  ColorMapPresetManager *m_PresetManager;
+
+  // Colormap presets
+  // PresetList m_PresetSystem, m_PresetUser;
+
+  // Get the RGBA for selected point
+  bool GetSelectedRGBA(ColorMap::RGBAType &rgba);
+  void SetSelectedRGBA(ColorMap::RGBAType rgba);
+
+  // Control point position
+  bool GetMovingControlPositionValueAndRange(
+      double &value, NumericValueRange<double> *range);
+  void SetMovingControlPosition(double value);
+
+  // Control point opacity
+  bool GetMovingControlOpacityValueAndRange(
+      double &value, NumericValueRange<double> *range);
+  void SetMovingControlOpacity(double value);
+
+  // Control point style
+  bool GetMovingControlType(Continuity &value);
+  void SetMovingControlType(Continuity value);
+
+  // Control point style
+  bool GetMovingControlSide(Side &value);
+  void SetMovingControlSide(Side value);
+
+  // Selected control point index
+  bool GetMovingControlIndexValueAndRange(
+      int &value, NumericValueRange<int> *range);
+  void SetMovingControlIndex(int value);
+
+  // Opacity of the selected layer
+  bool GetLayerOpacityValueAndRange(
+      double &value, NumericValueRange<double> *range);
+  void SetLayerOpacity(double value);
+
+  // Extract a colormap from the layer if it has one
+  ColorMap *GetColorMap(ImageWrapperBase *layer);
+
+};
+
+#endif // COLORMAPMODEL_H
diff --git a/GUI/Model/CursorInspectionModel.cxx b/GUI/Model/CursorInspectionModel.cxx
new file mode 100644
index 0000000..59de5ea
--- /dev/null
+++ b/GUI/Model/CursorInspectionModel.cxx
@@ -0,0 +1,162 @@
+#include "CursorInspectionModel.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "ColorLabelTable.h"
+#include "IntensityCurveModel.h"
+#include "ColorMapModel.h"
+
+#include <QtTableWidgetCoupling.h>
+
+#include <iomanip>
+
+/**
+  The domain used to present intensity information about the voxel under
+  the cursor
+
+  TODO: eventually, it would be nice to have a tree display for multi-component
+  data, so that we can see the values of all components at once.
+  */
+CurrentVoxelInfoItemSetDomain
+::CurrentVoxelInfoItemSetDomain(
+    IRISApplication *app, int role_filter)
+  : Superclass(app, role_filter), m_Driver(app)
+{
+}
+
+LayerCurrentVoxelInfo
+CurrentVoxelInfoItemSetDomain
+::GetDescription(const LayerIterator &it) const
+{
+  // The output structure
+  LayerCurrentVoxelInfo vox;
+
+  // Set the name
+  vox.LayerName = it.GetLayer()->GetNickname().c_str();
+
+  // Make sure that the layer is initialized
+  if(it.GetLayer()->IsInitialized())
+    {
+    // Get the cursor position
+    Vector3ui cursor = m_Driver->GetCursorPosition();
+
+    // Create a string output
+    std::ostringstream oss;
+
+    // Get the intensity or intensities that the user is seeing and the RGB
+    vnl_vector<double> v;
+    ImageWrapperBase::DisplayPixelType disprgb;
+    it.GetLayer()->GetVoxelUnderCursorDisplayedValueAndAppearance(v, disprgb);
+
+    // Print with varying degrees of precision
+    if(v.size() == 1)
+      {
+      oss << std::setprecision(4);
+      oss << v[0];
+      }
+    else if(v.size() == 3)
+      {
+      oss << std::setprecision(2);
+      oss << v[0] << "," << v[1] << "," << v[2];
+      }
+
+    vox.IntensityValue = oss.str();
+
+    // Get the displayed color
+    vox.Color = Vector3ui(disprgb[0], disprgb[1], disprgb[2]);
+
+    // Return the description
+    return vox;
+    }
+  else
+    {
+    vox.IntensityValue = "";
+    vox.Color = Vector3ui(0);
+    }
+
+  return vox;
+}
+
+CursorInspectionModel::CursorInspectionModel()
+{
+  // Create the child models
+  m_LabelUnderTheCursorIdModel = wrapGetterSetterPairAsProperty(
+        this, &CursorInspectionModel::GetLabelUnderTheCursorIdValue);
+
+  m_LabelUnderTheCursorTitleModel = wrapGetterSetterPairAsProperty(
+        this, &CursorInspectionModel::GetLabelUnderTheCursorTitleValue);
+
+  // Create the child model for the intensity list
+  m_VoxelAtCursorModel = ConcreteLayerVoxelAtCursorModel::New();
+}
+
+void CursorInspectionModel::SetParentModel(GlobalUIModel *parent)
+{
+  // Set the parent
+  m_Parent = parent;
+
+  // Get the app
+  IRISApplication *app = parent->GetDriver();
+
+  // Initialize the layer voxel list model
+  int role =
+      MAIN_ROLE |
+      OVERLAY_ROLE |
+      SNAP_ROLE;
+
+  CurrentVoxelInfoItemSetDomain dom(app, role);
+  m_VoxelAtCursorModel->SetDomain(dom);
+
+  // Make this model listen to events that affect its domain
+  m_VoxelAtCursorModel->Rebroadcast(
+        app, LayerChangeEvent(), DomainChangedEvent());
+  m_VoxelAtCursorModel->Rebroadcast(
+        this, ModelUpdateEvent(), DomainDescriptionChangedEvent());
+  m_VoxelAtCursorModel->Rebroadcast(
+        app, WrapperDisplayMappingChangeEvent(), DomainDescriptionChangedEvent());
+  m_VoxelAtCursorModel->Rebroadcast(
+        app, WrapperMetadataChangeEvent(), DomainDescriptionChangedEvent());
+
+  // Rebroadcast events from the parent as model update events. This could
+  // have a little more granularity, but for the moment, mapping all these
+  // events to a ModelUpdateEvent seems fine.
+  Rebroadcast(app, CursorUpdateEvent(), ModelUpdateEvent());
+  Rebroadcast(app, LayerChangeEvent(), ModelUpdateEvent());
+  Rebroadcast(app->GetColorLabelTable(),
+              SegmentationLabelChangeEvent(), ModelUpdateEvent());
+  Rebroadcast(app, SegmentationChangeEvent(), ModelUpdateEvent());
+
+
+}
+
+bool CursorInspectionModel::GetLabelUnderTheCursorIdValue(LabelType &value)
+{
+  IRISApplication *app = m_Parent->GetDriver();
+  GenericImageData *id = app->GetCurrentImageData();
+  if(id->IsSegmentationLoaded())
+    {
+    value = id->GetSegmentation()->GetVoxel(app->GetCursorPosition());
+    return true;
+    }
+  return false;
+}
+
+bool CursorInspectionModel::GetLabelUnderTheCursorTitleValue(std::string &value)
+{
+  IRISApplication *app = m_Parent->GetDriver();
+  GenericImageData *id = m_Parent->GetDriver()->GetCurrentImageData();
+  if(id->IsSegmentationLoaded())
+    {
+    LabelType label = id->GetSegmentation()->GetVoxel(app->GetCursorPosition());
+    value = app->GetColorLabelTable()->GetColorLabel(label).GetLabel();
+    return true;
+    }
+  return false;
+}
+
+AbstractRangedUIntVec3Property * CursorInspectionModel::GetCursorPositionModel() const
+{
+  return m_Parent->GetCursorPositionModel();
+}
+
+
diff --git a/GUI/Model/CursorInspectionModel.h b/GUI/Model/CursorInspectionModel.h
new file mode 100644
index 0000000..9aa2f43
--- /dev/null
+++ b/GUI/Model/CursorInspectionModel.h
@@ -0,0 +1,99 @@
+#ifndef CURSORINSPECTIONMODEL_H
+#define CURSORINSPECTIONMODEL_H
+
+#include <AbstractModel.h>
+#include <PropertyModel.h>
+#include <GenericImageData.h>
+#include <AbstractLayerInfoItemSetDomain.h>
+
+class GlobalUIModel;
+class IRISApplication;
+
+/**
+  This structure describes the intensity information at a cursor location
+  in a particular layer - which is displayed in the table
+  */
+struct LayerCurrentVoxelInfo
+{
+  std::string LayerName;
+  std::string IntensityValue;
+  Vector3ui Color;
+};
+
+/**
+  A definition of the item set domain for the table that shows current
+  under the cursor intensity values
+  */
+class CurrentVoxelInfoItemSetDomain :
+  public AbstractLayerInfoItemSetDomain<LayerCurrentVoxelInfo>
+{
+public:
+
+  typedef AbstractLayerInfoItemSetDomain<LayerCurrentVoxelInfo> Superclass;
+
+  // Define the domain with the specificed filter
+  CurrentVoxelInfoItemSetDomain(
+      IRISApplication *app = NULL, int role_filter = ALL_ROLES);
+
+  // Define the description method
+  LayerCurrentVoxelInfo GetDescription(const LayerIterator &it) const;
+
+protected:
+  IRISApplication *m_Driver;
+};
+
+// A concrete model encapsulating the above domain
+typedef ConcretePropertyModel<int, CurrentVoxelInfoItemSetDomain>
+  ConcreteLayerVoxelAtCursorModel;
+
+/**
+  This little model handles the logic for the cursor inspection page
+  */
+class CursorInspectionModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(CursorInspectionModel, AbstractModel)
+
+  void SetParentModel(GlobalUIModel *parent);
+
+  irisGetMacro(Parent, GlobalUIModel*)
+
+  /** Get the model for the label under the cursor */
+  irisGetMacro(LabelUnderTheCursorIdModel, AbstractSimpleLabelTypeProperty*)
+
+  /** Get the model for the label description under the cursor */
+  irisGetMacro(LabelUnderTheCursorTitleModel, AbstractSimpleStringProperty*)
+
+  /** Get the model for the cursor location */
+  AbstractRangedUIntVec3Property *GetCursorPositionModel() const;
+
+  // The model for a table of intensity values at cursor
+  irisGetMacro(VoxelAtCursorModel, ConcreteLayerVoxelAtCursorModel *)
+
+protected:
+
+  CursorInspectionModel();
+
+private:
+
+  // Label under the cursor
+  SmartPtr<AbstractSimpleLabelTypeProperty> m_LabelUnderTheCursorIdModel;
+  bool GetLabelUnderTheCursorIdValue(LabelType &value);
+
+  // Title of the label under the cursor
+  SmartPtr<AbstractSimpleStringProperty> m_LabelUnderTheCursorTitleModel;
+  bool GetLabelUnderTheCursorTitleValue(std::string &value);
+
+  // A pointer to the parent's cusror model
+  AbstractRangedUIntVec3Property *m_CursorPositionModel;
+
+  // The model for the intensity table
+  SmartPtr<ConcreteLayerVoxelAtCursorModel> m_VoxelAtCursorModel;
+
+  // Parent
+  GlobalUIModel *m_Parent;
+
+};
+
+#endif // CURSORINSPECTIONMODEL_H
diff --git a/GUI/Model/DisplayLayoutModel.cxx b/GUI/Model/DisplayLayoutModel.cxx
new file mode 100644
index 0000000..1867802
--- /dev/null
+++ b/GUI/Model/DisplayLayoutModel.cxx
@@ -0,0 +1,215 @@
+#include "DisplayLayoutModel.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+
+DisplayLayoutModel::DisplayLayoutModel()
+{
+  // Initialize the view layout to four views
+  m_ViewPanelLayoutModel = ConcreteViewPanelLayoutProperty::New();
+  m_ViewPanelLayoutModel->SetValue(VIEW_ALL);
+
+  // Rebroadcast relevant events from child models
+  Rebroadcast(m_ViewPanelLayoutModel, ValueChangedEvent(), ViewPanelLayoutChangeEvent());
+
+  // Set up the boolean visibility models
+  for(int panel = 0; panel < 4; panel++)
+    {
+    // Create the derived property for panel visibility
+    m_ViewPanelVisibilityModel[panel] = wrapIndexedGetterSetterPairAsProperty(
+          this, panel,
+          &Self::GetNthViewPanelVisibilityValue);
+
+    // The derived model must react to changes in view panel layout
+    m_ViewPanelVisibilityModel[panel]->Rebroadcast(
+          this, ViewPanelLayoutChangeEvent(), ValueChangedEvent());
+
+    // Create a derived property for panel expand action
+    m_ViewPanelExpandButtonActionModel[panel] = wrapIndexedGetterSetterPairAsProperty(
+          this, panel,
+          &Self::GetNthViewPanelExpandButtonActionValue);
+
+    // The derived model must react to changes in view panel layout
+    m_ViewPanelExpandButtonActionModel[panel]->Rebroadcast(
+          this, ViewPanelLayoutChangeEvent(), ValueChangedEvent());
+    }
+
+  // The tiling model
+  m_SliceViewLayerTilingModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetSliceViewLayerTilingValue);
+
+  // The derived model must react to changes to the internal values
+  m_SliceViewLayerTilingModel->Rebroadcast(
+        this, LayerLayoutChangeEvent(), ValueChangedEvent());
+
+}
+
+void DisplayLayoutModel::SetParentModel(GlobalUIModel *parentModel)
+{
+  m_ParentModel = parentModel;
+
+  // We need to rebroadcast the change in the display-to-anatomy mapping
+  // as one of our own events, which will in turn be rebroadcast as value
+  // change events in the derived models.
+  Rebroadcast(m_ParentModel->GetDriver(),
+              DisplayToAnatomyCoordinateMappingChangeEvent(),
+              ViewPanelLayoutChangeEvent());
+
+  // We need to be notified when the number of overlays changes
+  Rebroadcast(m_ParentModel->GetDriver(),
+              LayerChangeEvent(), LayerLayoutChangeEvent());
+
+  // and when the tiled/stacked mode changes
+  Rebroadcast(m_ParentModel->GetGlobalState()->GetSliceViewLayerLayoutModel(),
+              ValueChangedEvent(), LayerLayoutChangeEvent());
+
+  // We also need notification when the layer stickiness changes
+  Rebroadcast(m_ParentModel->GetDriver(),
+              WrapperVisibilityChangeEvent(), LayerLayoutChangeEvent());
+
+}
+
+AbstractPropertyModel<LayerLayout, TrivialDomain> *
+DisplayLayoutModel::GetSliceViewLayerLayoutModel() const
+{
+  return m_ParentModel->GetGlobalState()->GetSliceViewLayerLayoutModel();
+}
+
+bool DisplayLayoutModel
+::GetNthViewPanelVisibilityValue(int panel, bool &value)
+{
+  // The current layout
+  ViewPanelLayout layout = m_ViewPanelLayoutModel->GetValue();
+
+  // If the current mode is four views, then every view is visible
+  if(layout == VIEW_ALL)
+    {
+    value = true;
+    }
+
+  // If asking about the 3D window, there is no need to check display orientation
+  else if(panel == 3)
+    {
+    value = (layout == VIEW_3D);
+    }
+
+  // Otherwise, we need to know the orientation of the panel in question
+  else
+    {
+    IRISApplication *driver = m_ParentModel->GetDriver();
+    int wAxial = driver->GetDisplayWindowForAnatomicalDirection(ANATOMY_AXIAL);
+    int wCoronal = driver->GetDisplayWindowForAnatomicalDirection(ANATOMY_CORONAL);
+    int wSagittal = driver->GetDisplayWindowForAnatomicalDirection(ANATOMY_SAGITTAL);
+    value = (layout == VIEW_AXIAL && panel == wAxial)
+        || (layout == VIEW_CORONAL && panel == wCoronal)
+        || (layout == VIEW_SAGITTAL && panel == wSagittal);
+    }
+
+  return true;
+}
+
+bool DisplayLayoutModel::GetNthViewPanelExpandButtonActionValue(
+    int panel, DisplayLayoutModel::ViewPanelLayout &value)
+{
+  // The current layout
+  ViewPanelLayout layout = m_ViewPanelLayoutModel->GetValue();
+
+  // When the mode is 4-views, the action is to expand to the individual view
+  if(layout == VIEW_ALL)
+    {
+    IRISApplication *driver = m_ParentModel->GetDriver();
+    if(panel == (int) driver->GetDisplayWindowForAnatomicalDirection(ANATOMY_AXIAL))
+      value = VIEW_AXIAL;
+    else if (panel == (int) driver->GetDisplayWindowForAnatomicalDirection(ANATOMY_CORONAL))
+      value = VIEW_CORONAL;
+    else if (panel == (int) driver->GetDisplayWindowForAnatomicalDirection(ANATOMY_SAGITTAL))
+      value = VIEW_SAGITTAL;
+    else
+      value = VIEW_3D;
+    }
+
+  // Otherwise, the action is to return back to 4 views
+  else
+    {
+    value = VIEW_ALL;
+    }
+
+  return true;
+}
+
+bool DisplayLayoutModel::GetSliceViewLayerTilingValue(Vector2ui &value)
+{
+  value = m_LayerTiling;
+  return true;
+}
+
+void DisplayLayoutModel::UpdateSliceViewTiling()
+{
+  GenericImageData *id = m_ParentModel->GetDriver()->GetCurrentImageData();
+
+  // In stacked layout, there is only one layer to draw
+  if(m_ParentModel->GetGlobalState()->GetSliceViewLayerLayout() == LAYOUT_STACKED)
+    {
+    m_LayerTiling.fill(1);
+    }
+
+  // Also, when there is no data, the layout is 1x1
+  else if(!m_ParentModel->GetDriver()->IsMainImageLoaded())
+    {
+    m_LayerTiling.fill(1);
+    }
+
+  // Otherwise, we need to figure out in a smart way... But for now, we
+  // should just use some default tiling scheme
+  else
+    {
+    // Count the number of non-sticky layers, always counting main layer as 1
+    int n = 0;
+    for(LayerIterator it = id->GetLayers(); !it.IsAtEnd(); ++it)
+      {
+      if(it.GetRole() == MAIN_ROLE || !it.GetLayer()->IsSticky())
+        n++;
+      }
+
+    // A simple algorithm to solve min(ab) s.t. ab >= n, k >= a/b >= 1, where
+    // k is an aspect ratio value
+    // TODO: replace this with a smart algorithm that uses current window size
+    // and the amount of white space wasted in the currently visible views?
+    m_LayerTiling.fill(n);
+    double k = 2.01;
+    for(unsigned int a = 1; a <= n; a++)
+      {
+      unsigned int b0 = (unsigned int)(ceil(a/k));
+      for(unsigned int b = b0; b <= a; b++)
+        {
+        if(a * b >= n)
+          {
+          if(a * b < m_LayerTiling[1] * m_LayerTiling[0])
+            {
+            m_LayerTiling[1] = a;
+            m_LayerTiling[0] = b;
+            }
+          }
+        }
+      }
+    }
+}
+
+void DisplayLayoutModel::OnUpdate()
+{
+  // If there has been a layer change event, we need to recompute the tiling
+  // model
+  if(m_EventBucket->HasEvent(LayerChangeEvent())
+     || m_EventBucket->HasEvent(ValueChangedEvent(),
+                                m_ParentModel->GetGlobalState()->GetSliceViewLayerLayoutModel())
+     || m_EventBucket->HasEvent(WrapperVisibilityChangeEvent())
+     )
+    {
+    this->UpdateSliceViewTiling();
+    }
+}
+
+
+
+
diff --git a/GUI/Model/DisplayLayoutModel.h b/GUI/Model/DisplayLayoutModel.h
new file mode 100644
index 0000000..e784f8e
--- /dev/null
+++ b/GUI/Model/DisplayLayoutModel.h
@@ -0,0 +1,113 @@
+#ifndef DISPLAYLAYOUTMODEL_H
+#define DISPLAYLAYOUTMODEL_H
+
+class GlobalUIModel;
+
+#include "PropertyModel.h"
+#include "GlobalState.h"
+
+/**
+ * @brief A model that manages display layout properties. This model is
+ * just a collection of specific properties
+ */
+class DisplayLayoutModel : public AbstractModel
+{
+public:
+
+  // ITK macros
+  irisITKObjectMacro(DisplayLayoutModel, AbstractModel)
+
+  // Parent event type for all events fired by this model
+  itkEventMacro(DisplayLayoutChangeEvent, IRISEvent)
+
+  // Event fired when the layout of the slice panels changes
+  itkEventMacro(ViewPanelLayoutChangeEvent, DisplayLayoutChangeEvent)
+
+  // Event fired when the layout of the overlays in a slice panel changes
+  itkEventMacro(LayerLayoutChangeEvent, DisplayLayoutChangeEvent)
+
+  // This model fires a ModelUpdateEvent whenever there is a change in the
+  // display layout
+  FIRES(ViewPanelLayoutChangeEvent)
+  FIRES(LayerLayoutChangeEvent)
+
+  /** Layout of the SNAP slice views */
+  enum ViewPanelLayout {
+    VIEW_ALL = 0, VIEW_AXIAL, VIEW_CORONAL, VIEW_SAGITTAL, VIEW_3D
+  };
+
+  typedef AbstractPropertyModel<ViewPanelLayout> AbstractViewPanelLayoutProperty;
+
+  /** Get the parent model */
+  irisGetMacro(ParentModel, GlobalUIModel *)
+
+  /** Assign the parent model */
+  void SetParentModel(GlobalUIModel *parentModel);
+
+  /** Model managing the view panel layouts */
+  irisGetMacro(ViewPanelLayoutModel, AbstractViewPanelLayoutProperty *)
+
+  /**
+   * Read-only boolean property models for the visibility of any specific
+   * view panel (0-2 are slice windows, 3 is the 3D window).
+   */
+  AbstractSimpleBooleanProperty *GetViewPanelVisibilityModel(int view) const
+    { return m_ViewPanelVisibilityModel[view]; }
+
+  /**
+   * A model handing the layout of the layers in a slice view. This gives
+   * the number of rows and columns into which the slice views are broken
+   * up when displaying overlays. When this is 1x1, the overlays are painted
+   * on top of each other using transparency. Otherwise, each overlay is shown
+   * in its own cell.
+   */
+  irisGetMacro(SliceViewLayerTilingModel, AbstractSimpleUIntVec2Property *)
+
+  /**
+   * A model for the layout of the layers in a slice view. This model sets
+   * the stacked/tiled state. If the state is set to tiled, the number of
+   * tiles will be updated as the number of loaded images changes. This model
+   * actually just returns the model with the same name in the global state
+   */
+  AbstractPropertyModel<LayerLayout, TrivialDomain> *GetSliceViewLayerLayoutModel() const;
+
+  /**
+   * Read-only boolean property models that dictate what icon should be
+   * displayed in the expand/contract buttons in each slice view. There
+   * are four of these models (one for each slice view), and they are of
+   * the type ViewPanelLayout()
+   */
+  AbstractViewPanelLayoutProperty *GetViewPanelExpandButtonActionModel(int view) const
+    { return m_ViewPanelExpandButtonActionModel[view]; }
+
+protected:
+
+  GlobalUIModel *m_ParentModel;
+
+  typedef ConcretePropertyModel<ViewPanelLayout> ConcreteViewPanelLayoutProperty;
+  SmartPtr<ConcreteViewPanelLayoutProperty> m_ViewPanelLayoutModel;
+
+  SmartPtr<AbstractSimpleBooleanProperty> m_ViewPanelVisibilityModel[4];
+
+  SmartPtr<AbstractViewPanelLayoutProperty> m_ViewPanelExpandButtonActionModel[4];
+
+  bool GetNthViewPanelVisibilityValue(int panel, bool &value);
+
+  SmartPtr<AbstractSimpleUIntVec2Property> m_SliceViewLayerTilingModel;
+  bool GetSliceViewLayerTilingValue(Vector2ui &value);
+
+  bool GetNthViewPanelExpandButtonActionValue(int panel, ViewPanelLayout &value);
+
+  // Update the tiling based on the number of layouts in memory
+  void UpdateSliceViewTiling();
+
+  // The current tiling dimensons
+  Vector2ui m_LayerTiling;
+
+  virtual void OnUpdate();
+
+  DisplayLayoutModel();
+  virtual ~DisplayLayoutModel() {}
+};
+
+#endif // DISPLAYLAYOUTMODEL_H
diff --git a/GUI/Model/Generic3DModel.cxx b/GUI/Model/Generic3DModel.cxx
new file mode 100644
index 0000000..3ceb81b
--- /dev/null
+++ b/GUI/Model/Generic3DModel.cxx
@@ -0,0 +1,453 @@
+#include "Generic3DModel.h"
+#include "Generic3DRenderer.h"
+#include "GlobalUIModel.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "ImageWrapperBase.h"
+#include "MeshManager.h"
+#include "Window3DPicker.h"
+#include "vtkRenderWindow.h"
+#include "vtkRendererCollection.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkPointData.h"
+#include "itkMutexLockHolder.h"
+#include "MeshOptions.h"
+
+// All the VTK stuff
+#include "vtkPolyData.h"
+
+#include <vnl/vnl_inverse.h>
+
+Generic3DModel::Generic3DModel()
+{
+  // Initialize the matrix to nil
+  m_WorldMatrix.set_identity();
+
+  // Create the spray points
+  vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
+  m_SprayPoints = vtkSmartPointer<vtkPolyData>::New();
+  m_SprayPoints->SetPoints(pts);
+
+  // Create the renderer
+  m_Renderer = Generic3DRenderer::New();
+
+  // Continuous update model
+  m_ContinuousUpdateModel = NewSimpleConcreteProperty(false);
+
+  // Scalpel
+  m_ScalpelStatus = SCALPEL_LINE_NULL;
+
+  // Reset clear time
+  m_ClearTime = 0;
+}
+
+#include "itkImage.h"
+
+void Generic3DModel::Initialize(GlobalUIModel *parent)
+{
+  // Store the parent
+  m_ParentUI = parent;
+  m_Driver = parent->GetDriver();
+
+  // Update our geometry model
+  OnImageGeometryUpdate();
+
+  // Initialize the renderer
+  m_Renderer->SetModel(this);
+
+  // Listen to the layer change events
+  Rebroadcast(m_Driver, MainImageDimensionsChangeEvent(), ModelUpdateEvent());
+
+  // Listen to segmentation change events
+  Rebroadcast(m_Driver, SegmentationChangeEvent(), StateMachineChangeEvent());
+  Rebroadcast(m_Driver, LevelSetImageChangeEvent(), StateMachineChangeEvent());
+
+  // Rebroadcast model change events as state changes
+  Rebroadcast(this, ModelUpdateEvent(), StateMachineChangeEvent());
+  Rebroadcast(this, SprayPaintEvent(), StateMachineChangeEvent());
+  Rebroadcast(this, ScalpelEvent(), StateMachineChangeEvent());
+  Rebroadcast(m_ParentUI->GetGlobalState()->GetToolbarMode3DModel(),
+              ValueChangedEvent(), StateMachineChangeEvent());
+  Rebroadcast(m_ParentUI->GetGlobalState()->GetMeshOptions(),
+              ChildPropertyChangedEvent(), StateMachineChangeEvent());
+}
+
+bool Generic3DModel::CheckState(Generic3DModel::UIState state)
+{
+  if(!m_ParentUI->GetDriver()->IsMainImageLoaded())
+    return false;
+
+  ToolbarMode3DType mode = m_ParentUI->GetGlobalState()->GetToolbarMode3D();
+
+  switch(state)
+    {
+    case UIF_MESH_DIRTY:
+      {
+      if(m_Driver->GetMeshManager()->IsMeshDirty())
+        return true;
+
+      if(m_Driver->GetMeshManager()->GetBuildTime() <= this->m_ClearTime)
+        return true;
+
+      return false;
+      }
+
+    case UIF_MESH_ACTION_PENDING:
+      {
+      if(mode == SPRAYPAINT_MODE)
+        return m_SprayPoints->GetNumberOfPoints() > 0;
+
+      else if (mode == SCALPEL_MODE)
+        return m_ScalpelStatus == SCALPEL_LINE_COMPLETED;
+
+      else return false;
+      }
+
+    case UIF_CAMERA_STATE_SAVED:
+      {
+      return m_Renderer->IsSavedCameraStateAvailable();
+      }
+
+    case UIF_FLIP_ENABLED:
+      {
+      return mode == SCALPEL_MODE && m_ScalpelStatus == SCALPEL_LINE_COMPLETED;
+      }
+    }
+
+  return false;
+}
+
+Generic3DModel::Mat4d &Generic3DModel::GetWorldMatrix()
+{
+  return m_WorldMatrix;
+}
+
+
+Vector3d Generic3DModel::GetCenterOfRotation()
+{
+  return affine_transform_point(m_WorldMatrix, m_Driver->GetCursorPosition());
+}
+
+void Generic3DModel::ResetView()
+{
+  m_Renderer->ResetView();
+}
+
+void Generic3DModel::SaveCameraState()
+{
+  m_Renderer->SaveCameraState();
+  InvokeEvent(StateMachineChangeEvent());
+}
+
+void Generic3DModel::RestoreCameraState()
+{
+  m_Renderer->RestoreSavedCameraState();
+}
+
+#include "MeshExportSettings.h"
+#include "vtkVRMLExporter.h"
+void Generic3DModel::ExportMesh(const MeshExportSettings &settings)
+{
+  // Update the mesh
+  this->UpdateSegmentationMesh(m_ParentUI->GetProgressCommand());
+
+  // Prevent concurrent access to this method and mesh update
+  itk::MutexLockHolder<itk::SimpleFastMutexLock> mholder(m_MutexLock);
+
+  // Certain formats require a VTK exporter and use a render window. They
+  // are handled directly in this code, rather than in the Guided code.
+  // TODO: it would make sense to unify this functionality in GuidedMeshIO
+  GuidedMeshIO mesh_io;
+  Registry reg_format = settings.GetMeshFormat();
+  if(mesh_io.GetFileFormat(reg_format) == GuidedMeshIO::FORMAT_VRML)
+    {
+    // Create the exporter
+    vtkSmartPointer<vtkVRMLExporter> exporter = vtkSmartPointer<vtkVRMLExporter>::New();
+    exporter->SetFileName(settings.GetMeshFileName().c_str());
+    exporter->SetInput(m_Renderer->GetRenderWindow());
+    exporter->Update();
+    return;
+    }
+
+  // Export the mesh
+  m_ParentUI->GetDriver()->ExportSegmentationMesh(
+        settings, m_ParentUI->GetProgressCommand());
+}
+
+vtkPolyData *Generic3DModel::GetSprayPoints() const
+{
+  return m_SprayPoints.GetPointer();
+}
+
+void Generic3DModel::OnUpdate()
+{
+  // If we experienced a change in main image, we have to respond!
+  if(m_EventBucket->HasEvent(MainImageDimensionsChangeEvent()))
+    {
+    // There is no more mesh to render - until the user does something!
+    // m_Mesh->DiscardVTKMeshes();
+
+    // Clear the spray points
+    m_SprayPoints->GetPoints()->Reset();
+    m_SprayPoints->Modified();
+
+    // The geometry has changed
+    this->OnImageGeometryUpdate();
+    }
+}
+
+void Generic3DModel::OnImageGeometryUpdate()
+{
+  // Update the world matrix and other stored variables
+  if(m_Driver->IsMainImageLoaded())
+    {
+    ImageWrapperBase *main = m_Driver->GetCurrentImageData()->GetMain();
+    m_WorldMatrix = main->GetNiftiSform();
+    m_WorldMatrixInverse = main->GetNiftiInvSform();
+    }
+  else
+    {
+    m_WorldMatrix.set_identity();
+    m_WorldMatrixInverse.set_identity();
+    }
+}
+
+#include "itkMutexLockHolder.h"
+
+void Generic3DModel::UpdateSegmentationMesh(itk::Command *callback)
+{
+  // Prevent concurrent access to this method
+  itk::MutexLockHolder<itk::SimpleFastMutexLock> mholder(m_MutexLock);
+
+  try
+  {
+    // Generate all the mesh objects
+    m_MeshUpdating = true;
+    m_Driver->GetMeshManager()->UpdateVTKMeshes(callback);
+    m_MeshUpdating = false;
+
+    InvokeEvent(ModelUpdateEvent());
+  }
+  catch(vtkstd::bad_alloc &)
+  {
+    throw IRISException("Out of memory during mesh computation");
+  }
+  catch(IRISException & IRISexc)
+  {
+    throw IRISexc;
+  }
+}
+
+bool Generic3DModel::IsMeshUpdating()
+{
+  return m_MeshUpdating;
+}
+
+bool Generic3DModel::AcceptAction()
+{
+  ToolbarMode3DType mode = m_ParentUI->GetGlobalState()->GetToolbarMode3D();
+  IRISApplication *app = m_ParentUI->GetDriver();
+
+  // Accept the current action
+  if(mode == SPRAYPAINT_MODE)
+    {
+    // Merge all the spray points into the segmentation
+    app->BeginSegmentationUpdate("3D spray paint");
+    for(int i = 0; i < m_SprayPoints->GetNumberOfPoints(); i++)
+      {
+      double *x = m_SprayPoints->GetPoint(i);
+      Vector3ui pos(
+            static_cast<unsigned int>(x[0]),
+            static_cast<unsigned int>(x[1]),
+            static_cast<unsigned int>(x[2]));
+      app->UpdateSegmentationVoxel(pos);
+      }
+
+    // Clear the spray points
+    m_SprayPoints->GetPoints()->Reset();
+    m_SprayPoints->Modified();
+    InvokeEvent(SprayPaintEvent());
+
+    // Return true if anything changed
+    return app->EndSegmentationUpdate() > 0;
+    }
+  else if(mode == SCALPEL_MODE && m_ScalpelStatus == SCALPEL_LINE_COMPLETED)
+    {
+    // Get the plane origin and normal in world coordinates
+    Vector3d xw = m_Renderer->GetScalpelPlaneOrigin();
+    Vector3d nw = m_Renderer->GetScalpelPlaneNormal();
+
+    // Map these properties into the image coordinates
+    Vector3d xi = affine_transform_point(m_WorldMatrixInverse, xw);
+    Vector3d ni = affine_transform_vector(m_WorldMatrixInverse, nw);
+
+    // Use the driver to relabel the plane
+    app->BeginSegmentationUpdate("3D scalpel");
+    app->RelabelSegmentationWithCutPlane(ni, dot_product(xi, ni));
+    int nMod = app->EndSegmentationUpdate();
+
+    // Reset the scalpel state, but only if the operation was successful
+    if(nMod > 0)
+      {
+      m_ScalpelStatus = SCALPEL_LINE_NULL;
+      InvokeEvent(ScalpelEvent());
+      return true;
+      }
+    else return false;
+    }
+  return true;
+}
+
+void Generic3DModel::CancelAction()
+{
+  ToolbarMode3DType mode = m_ParentUI->GetGlobalState()->GetToolbarMode3D();
+  if(mode == SPRAYPAINT_MODE)
+    {
+    // Clear the spray points
+    m_SprayPoints->GetPoints()->Reset();
+    m_SprayPoints->Modified();
+    InvokeEvent(SprayPaintEvent());
+    }
+  else if(mode == SCALPEL_MODE && m_ScalpelStatus == SCALPEL_LINE_COMPLETED)
+    {
+    // Reset the scalpel state
+    m_ScalpelStatus = SCALPEL_LINE_NULL;
+    InvokeEvent(ScalpelEvent());
+    }
+}
+
+void Generic3DModel::FlipAction()
+{
+  ToolbarMode3DType mode = m_ParentUI->GetGlobalState()->GetToolbarMode3D();
+  if(mode == SCALPEL_MODE && m_ScalpelStatus == SCALPEL_LINE_COMPLETED)
+    {
+    m_Renderer->FlipScalpelPlaneNormal();
+    }
+}
+
+void Generic3DModel::ClearRenderingAction()
+{
+  m_Renderer->ClearRendering();
+  m_ClearTime = m_Driver->GetMeshManager()->GetBuildTime();
+  InvokeEvent(ModelUpdateEvent());
+}
+
+#include "ImageRayIntersectionFinder.h"
+#include "SNAPImageData.h"
+
+/** These classes are used internally for m_Ray intersection testing */
+class LabelImageHitTester
+{
+public:
+  LabelImageHitTester(const ColorLabelTable *table = NULL)
+  {
+    m_LabelTable = table;
+  }
+
+  int operator()(LabelType label) const
+  {
+    const ColorLabel &cl = m_LabelTable->GetColorLabel(label);
+    return (cl.IsVisible() && cl.IsVisibleIn3D()) ? 1 : 0;
+  }
+
+private:
+  const ColorLabelTable *m_LabelTable;
+};
+
+class SnakeImageHitTester
+{
+public:
+  int operator()(float levelSetValue) const
+    { return levelSetValue <= 0 ? 1 : 0; }
+};
+
+bool Generic3DModel::IntersectSegmentation(int vx, int vy, Vector3i &hit)
+{
+  // World coordinate of the click position and direction
+  Vector3d x_world, d_world;
+  m_Renderer->ComputeRayFromClick(vx, vy, x_world, d_world);
+
+  // Convert these to image coordinates
+  Vector3d x_image = affine_transform_point(m_WorldMatrixInverse, x_world);
+  Vector3d d_image = affine_transform_vector(m_WorldMatrixInverse, d_world);
+
+  int result = 0;
+  if(m_Driver->IsSnakeModeLevelSetActive())
+    {
+    typedef ImageRayIntersectionFinder<float, SnakeImageHitTester> RayCasterType;
+    RayCasterType caster;
+    result = caster.FindIntersection(
+          m_ParentUI->GetDriver()->GetSNAPImageData()->GetSnake()->GetImage(),
+          x_image, d_image, hit);
+    }
+  else
+    {
+    typedef ImageRayIntersectionFinder<LabelType, LabelImageHitTester> RayCasterType;
+    RayCasterType caster;
+    LabelImageHitTester tester(m_ParentUI->GetDriver()->GetColorLabelTable());
+    caster.SetHitTester(tester);
+    result = caster.FindIntersection(
+          m_ParentUI->GetDriver()->GetCurrentImageData()->GetSegmentation()->GetImage(),
+          x_image, d_image, hit);
+    }
+
+  return (result == 1);
+}
+
+bool Generic3DModel::PickSegmentationVoxelUnderMouse(int px, int py)
+{
+  // Find the voxel under the cursor
+  Vector3i hit;
+  if(this->IntersectSegmentation(px, py, hit))
+    {
+    Vector3ui cursor = to_unsigned_int(hit);
+
+    itk::ImageRegion<3> region = m_Driver->GetCurrentImageData()->GetImageRegion();
+    if(region.IsInside(to_itkIndex(cursor)))
+      {
+      m_Driver->SetCursorPosition(cursor);
+      return true;
+      }
+    }
+
+  return false;
+}
+
+bool Generic3DModel::SpraySegmentationVoxelUnderMouse(int px, int py)
+{
+  // Find the voxel under the cursor
+  Vector3i hit;
+  if(this->IntersectSegmentation(px, py, hit))
+    {
+    itk::ImageRegion<3> region = m_Driver->GetCurrentImageData()->GetImageRegion();
+    if(region.IsInside(to_itkIndex(hit)))
+      {
+      m_SprayPoints->GetPoints()->InsertNextPoint(hit[0], hit[1], hit[2]);
+      m_SprayPoints->Modified();
+      this->InvokeEvent(SprayPaintEvent());
+      return true;
+      }
+    }
+
+  return false;
+}
+
+void Generic3DModel::SetScalpelStartPoint(int px, int py)
+{
+  m_ScalpelEnd[0] = m_ScalpelStart[0] = px;
+  m_ScalpelEnd[1] = m_ScalpelStart[1] = py;
+  m_ScalpelStatus = SCALPEL_LINE_STARTED;
+  this->InvokeEvent(ScalpelEvent());
+}
+
+void Generic3DModel::SetScalpelEndPoint(int px, int py, bool complete)
+{
+  m_ScalpelEnd[0] = px;
+  m_ScalpelEnd[1] = py;
+  if(complete)
+    m_ScalpelStatus = SCALPEL_LINE_COMPLETED;
+  this->InvokeEvent(ScalpelEvent());
+}
+
+
diff --git a/GUI/Model/Generic3DModel.h b/GUI/Model/Generic3DModel.h
new file mode 100644
index 0000000..f31995e
--- /dev/null
+++ b/GUI/Model/Generic3DModel.h
@@ -0,0 +1,173 @@
+#ifndef GENERIC3DMODEL_H
+#define GENERIC3DMODEL_H
+
+#include "AbstractModel.h"
+#include "PropertyModel.h"
+#include "vtkSmartPointer.h"
+#include "SNAPEvents.h"
+#include "itkMutexLock.h"
+
+class GlobalUIModel;
+class IRISApplication;
+class MeshManager;
+class Generic3DRenderer;
+class vtkPolyData;
+class MeshExportSettings;
+
+namespace itk
+{
+class Command;
+}
+
+class Generic3DModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(Generic3DModel, AbstractModel)
+
+  // Special events
+  itkEventMacro(SprayPaintEvent, IRISEvent)
+  itkEventMacro(ScalpelEvent, IRISEvent)
+  FIRES(SprayPaintEvent)
+  FIRES(ScalpelEvent)
+  FIRES(StateMachineChangeEvent)
+
+  // Matrix for various transforms
+  typedef vnl_matrix_fixed<double, 4, 4> Mat4d;
+
+  Generic3DModel();
+
+  // States pertaining to this model
+  enum UIState {
+    UIF_MESH_DIRTY = 0,
+    UIF_MESH_ACTION_PENDING,
+    UIF_CAMERA_STATE_SAVED,
+    UIF_FLIP_ENABLED
+  };
+
+  // State of scalpel drawging
+  enum ScalpelStatus {
+    SCALPEL_LINE_NULL = 0,
+    SCALPEL_LINE_STARTED,
+    SCALPEL_LINE_COMPLETED
+  };
+
+  // Set the parent model
+  void Initialize(GlobalUIModel *parent);
+
+  // Check the state
+  bool CheckState(UIState state);
+
+  // A flag indicating that the mesh should be continually updated
+  // TODO: replace this with an update in a background thread
+  irisSimplePropertyAccessMacro(ContinuousUpdate, bool)
+
+  // Tell the model to update the segmentation mesh
+  void UpdateSegmentationMesh(itk::Command *callback);
+
+  // Reentrant function to check if mesh is being constructed in another thread
+  bool IsMeshUpdating();
+
+  // Accept the current drawing operation
+  bool AcceptAction();
+
+  // Cancel the current drawing operation
+  void CancelAction();
+
+  // Flip the direction of the normal for the scalpel operation
+  void FlipAction();
+
+  // Clear the rendering
+  void ClearRenderingAction();
+
+  // Position cursor at the screen position under the cursor
+  bool PickSegmentationVoxelUnderMouse(int px, int py);
+
+  // Add a spraypaint bubble at the screen position under the cursor
+  bool SpraySegmentationVoxelUnderMouse(int px, int py);
+
+  // Set the endpoints of the scalpel line
+  void SetScalpelStartPoint(int px, int py);
+  irisGetMacro(ScalpelStart, Vector2i)
+
+  // Set the endpoints of the scalpel line
+  void SetScalpelEndPoint(int px, int py, bool complete);
+  irisGetMacro(ScalpelEnd, Vector2i)
+
+  irisGetSetMacro(ScalpelStatus, ScalpelStatus)
+
+  // Get the parent model
+  irisGetMacro(ParentUI, GlobalUIModel *)
+
+  // Get the renderer
+  irisGetMacro(Renderer, Generic3DRenderer *)
+
+  // Get the transform from image space to world coordinates
+  Mat4d &GetWorldMatrix();
+
+  // Get the center of rotation for the 3D window
+  Vector3d GetCenterOfRotation();
+
+  // Reset the viewpoint
+  void ResetView();
+
+  // Save the camera state
+  void SaveCameraState();
+
+  // Restore the camera state
+  void RestoreCameraState();
+
+  // Export the 3D model
+  void ExportMesh(const MeshExportSettings &settings);
+
+  // Get the spray points
+  vtkPolyData *GetSprayPoints() const;
+
+protected:
+
+  // Respond to updates
+  void OnUpdate();
+
+  // Do this when main image geometry has changed
+  void OnImageGeometryUpdate();
+
+  // Find the labeled voxel under the cursor
+  bool IntersectSegmentation(int vx, int vy, Vector3i &hit);
+
+  // Parent (where the global UI state is stored)
+  GlobalUIModel *m_ParentUI;
+
+  // Renderer
+  SmartPtr<Generic3DRenderer> m_Renderer;
+
+  // Helps to have a pointer to the iris application
+  IRISApplication *m_Driver;
+
+  // World matrix - a copy of the NIFTI transform in the main image,
+  // updated on the event main image changes
+  Mat4d m_WorldMatrix, m_WorldMatrixInverse;
+
+  // Set of spraypainted points in image coordinates
+  vtkSmartPointer<vtkPolyData> m_SprayPoints;
+
+  // On-screen endpoints of the scalpel line
+  Vector2i m_ScalpelStart, m_ScalpelEnd;
+
+  // State of the scalpel drawing
+  ScalpelStatus m_ScalpelStatus;
+
+  // Continuous update model
+  SmartPtr<ConcreteSimpleBooleanProperty> m_ContinuousUpdateModel;
+
+  // Is the mesh updating
+  bool m_MeshUpdating;
+
+  // Time of the last mesh clear operation
+  unsigned long m_ClearTime;
+
+  // A mutex lock to allow background processing of mesh updates
+  itk::SimpleFastMutexLock m_MutexLock;
+
+};
+
+#endif // GENERIC3DMODEL_H
diff --git a/GUI/Model/GenericSliceModel.cxx b/GUI/Model/GenericSliceModel.cxx
new file mode 100644
index 0000000..c90c673
--- /dev/null
+++ b/GUI/Model/GenericSliceModel.cxx
@@ -0,0 +1,598 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include <GenericSliceModel.h>
+#include <GlobalUIModel.h>
+#include <IRISException.h>
+#include <IRISApplication.h>
+#include <GenericImageData.h>
+#include <SNAPAppearanceSettings.h>
+#include <DisplayLayoutModel.h>
+
+#include <itkImage.h>
+#include <itkImageRegionIteratorWithIndex.h>
+
+GenericSliceModel::GenericSliceModel()
+{
+  // Copy parent pointers
+  m_ParentUI = NULL;
+  m_Driver = NULL;
+
+  // Set the window ID
+  m_Id = -1;
+
+  // Initalize the margin
+  m_Margin = 2;
+
+  // Initialize the zoom management
+  m_ManagedZoom = false;
+
+  // The slice is not yet initialized
+  m_SliceInitialized = false;
+
+  // Viewport size reporter is NULL
+  m_SizeReporter = NULL;
+
+  // Create submodels
+  m_SliceIndexModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetSliceIndexValueAndDomain,
+        &Self::SetSlideIndexValue);
+
+}
+
+void GenericSliceModel::Initialize(GlobalUIModel *model, int index)
+{
+  // Copy parent pointers
+  m_ParentUI = model;
+  m_Driver = model->GetDriver();
+
+  // Set the window ID
+  m_Id = index;
+
+  // The slice is not yet initialized
+  m_SliceInitialized = false;
+
+  // Listen to events that require action from this object
+  Rebroadcast(m_Driver, LayerChangeEvent(), ModelUpdateEvent());
+
+  // Listen to changes in the layout of the slice view into cells. When
+  // this change occurs, we have to modify the size of the slice views
+  DisplayLayoutModel *dlm = m_ParentUI->GetDisplayLayoutModel();
+  Rebroadcast(dlm, DisplayLayoutModel::LayerLayoutChangeEvent(), ModelUpdateEvent());
+
+  // Listen to cursor update events and rebroadcast them for the child model
+  m_SliceIndexModel->Rebroadcast(model, CursorUpdateEvent(), ValueChangedEvent());
+
+}
+
+void GenericSliceModel
+::SetSizeReporter(ViewportSizeReporter *reporter)
+{
+  m_SizeReporter = reporter;
+
+  // Rebroadcast the events from the reporter downstream to force an update
+  Rebroadcast(m_SizeReporter,
+              ViewportSizeReporter::ViewportResizeEvent(),
+              ModelUpdateEvent());
+
+  // We also rebroadcast as a special type of event that the slice coordinator
+  // is going to listen to
+  Rebroadcast(m_SizeReporter,
+              ViewportSizeReporter::ViewportResizeEvent(),
+              ViewportResizeEvent());
+}
+
+
+void GenericSliceModel::OnUpdate()
+{
+  // Has there been a change in the image dimensions?
+  if(m_EventBucket->HasEvent(MainImageDimensionsChangeEvent()))
+    {
+    // Do a complete initialization
+    this->InitializeSlice(m_Driver->GetCurrentImageData());
+    }
+
+  // TODO: what is the ValueChangeEvent here???
+  else if(m_EventBucket->HasEvent(ViewportSizeReporter::ViewportResizeEvent())
+          || m_EventBucket->HasEvent(DisplayLayoutModel::LayerLayoutChangeEvent())
+          || m_EventBucket->HasEvent(ValueChangedEvent()))
+    {
+
+    // We only react to the viewport resize if the zoom is not managed by the
+    // coordinator. When zoom is managed, the coordinator will take care of
+    // computing the optimal zoom and resetting the view
+    if(this->IsSliceInitialized() && !m_ManagedZoom)
+      {
+      // Check if the zoom should be changed in response to this operation. This
+      // is so if the zoom is currently equal to the optimal zoom, and there is
+      // no linked zoom
+      bool rezoom = (m_ViewZoom == m_OptimalZoom);
+
+      // Just recompute the optimal zoom factor
+      this->ComputeOptimalZoom();
+
+      // Keep zoom optimal if before it was optimal
+      if(rezoom)
+        this->SetViewZoom(m_OptimalZoom);
+      }
+    }
+
+}
+
+void GenericSliceModel::ComputeOptimalZoom()
+{
+  // Should be fully initialized
+  assert(IsSliceInitialized());
+
+  // Compute slice size in spatial coordinates
+  Vector2f worldSize(
+    m_SliceSize[0] * m_SliceSpacing[0],
+    m_SliceSize[1] * m_SliceSpacing[1]);
+
+  // Set the view position (position of the center of the image?)
+  m_OptimalViewPosition = worldSize * 0.5f;
+
+  // Reduce the width and height of the slice by the margin
+  Vector2ui size = this->GetSize();
+  Vector2i szCanvas =
+      Vector2i(size[0], size[1]) - Vector2i(2 * m_Margin);
+
+  // Compute the ratios of window size to slice size
+  Vector2f ratios(
+    szCanvas(0) / worldSize(0),
+    szCanvas(1) / worldSize(1));
+
+  // The zoom factor is the bigger of these ratios, the number of pixels
+  // on the screen per millimeter in world space
+  m_OptimalZoom = ratios.min_value();
+}
+
+
+GenericSliceModel
+::~GenericSliceModel()
+{
+}
+
+
+
+void
+GenericSliceModel
+::InitializeSlice(GenericImageData *imageData)
+{
+  // Store the image data pointer
+  m_ImageData = imageData;
+
+  // Quit if there is no image loaded
+  if (!m_ImageData->IsMainLoaded())
+    {
+    m_SliceInitialized = false;
+    return;
+    }
+
+  // Store the transforms between the display and image spaces
+  m_ImageToDisplayTransform =
+    imageData->GetImageGeometry().GetImageToDisplayTransform(m_Id);
+  m_DisplayToImageTransform =
+    imageData->GetImageGeometry().GetDisplayToImageTransform(m_Id);
+  m_DisplayToAnatomyTransform =
+    imageData->GetImageGeometry().GetAnatomyToDisplayTransform(m_Id).Inverse();
+
+  // Get the volume extents & voxel scale factors
+  Vector3ui imageSizeInImageSpace = m_ImageData->GetVolumeExtents();
+  Vector3f imageScalingInImageSpace = to_float(m_ImageData->GetImageSpacing());
+
+  // Initialize quantities that depend on the image and its transform
+  for(unsigned int i = 0; i < 3; i++)
+    {
+    // Get the direction in image space that corresponds to the i'th
+    // direction in slice space
+    m_ImageAxes[i] = m_DisplayToImageTransform.GetCoordinateIndexZeroBased(i);
+
+    // Record the size and scaling of the slice
+    m_SliceSize[i] = imageSizeInImageSpace[m_ImageAxes[i]];
+    m_SliceSpacing[i] = imageScalingInImageSpace[m_ImageAxes[i]]; // TODO: Reverse sign by orientation?
+    }
+
+  // We have been initialized
+  m_SliceInitialized = true;
+
+  // Compute the optimal zoom for this slice
+  ComputeOptimalZoom();
+
+  // Fire a modified event, forcing a repaint of the window
+  InvokeEvent(ModelUpdateEvent());
+}
+
+Vector2i
+GenericSliceModel
+::GetOptimalCanvasSize()
+{
+  // Compute slice size in spatial coordinates
+  Vector2i optSize(
+    (int) ceil(m_SliceSize[0] * m_SliceSpacing[0] * m_ViewZoom + 2 * m_Margin),
+    (int) ceil(m_SliceSize[1] * m_SliceSpacing[1] * m_ViewZoom + 2 * m_Margin));
+
+  return optSize;
+}
+
+void
+GenericSliceModel
+::ResetViewToFit()
+{
+  // Should be fully initialized
+  assert(IsSliceInitialized());
+
+  // The zoom factor is the bigger of these ratios, the number of pixels
+  // on the screen per millimeter in world space
+  SetViewZoom(m_OptimalZoom);
+  SetViewPosition(m_OptimalViewPosition);
+}
+
+Vector3f
+GenericSliceModel
+::MapSliceToImage(const Vector3f &xSlice)
+{
+  assert(IsSliceInitialized());
+
+  // Get corresponding position in display space
+  return m_DisplayToImageTransform.TransformPoint(xSlice);
+}
+
+/**
+ * Map a point in image coordinates to slice coordinates
+ */
+Vector3f
+GenericSliceModel
+::MapImageToSlice(const Vector3f &xImage)
+{
+  assert(IsSliceInitialized());
+
+  // Get corresponding position in display space
+  return  m_ImageToDisplayTransform.TransformPoint(xImage);
+}
+
+Vector2f
+GenericSliceModel
+::MapSliceToWindow(const Vector3f &xSlice)
+{
+  assert(IsSliceInitialized());
+
+  // Adjust the slice coordinates by the scaling amounts
+  Vector2f uvScaled(
+    xSlice(0) * m_SliceSpacing(0),xSlice(1) * m_SliceSpacing(1));
+
+  // Compute the window coordinates
+  Vector2ui size = this->GetSize();
+  Vector2f uvWindow =
+    m_ViewZoom * (uvScaled - m_ViewPosition) +
+      Vector2f(0.5f * size[0],0.5f * size[1]);
+
+  // That's it, the projection matrix is set up in the scaled-slice coordinates
+  return uvWindow;
+}
+
+Vector3f
+GenericSliceModel
+::MapWindowToSlice(const Vector2f &uvWindow)
+{
+  assert(IsSliceInitialized() && m_ViewZoom > 0);
+
+  // Compute the scaled slice coordinates
+  Vector2ui size = this->GetSize();
+  Vector2f winCenter(0.5f * size[0],0.5f * size[1]);
+  Vector2f uvScaled =
+    m_ViewPosition + (uvWindow - winCenter) / m_ViewZoom;
+
+  // The window coordinates are already in the scaled-slice units
+  Vector3f uvSlice(
+    uvScaled(0) / m_SliceSpacing(0),
+    uvScaled(1) / m_SliceSpacing(1),
+    this->GetCursorPositionInSliceCoordinates()[2]);
+
+  // Return this vector
+  return uvSlice;
+}
+
+Vector3f
+GenericSliceModel
+::MapWindowOffsetToSliceOffset(const Vector2f &uvWindowOffset)
+{
+  assert(IsSliceInitialized() && m_ViewZoom > 0);
+
+  Vector2f uvScaled = uvWindowOffset / m_ViewZoom;
+
+  // The window coordinates are already in the scaled-slice units
+  Vector3f uvSlice(
+    uvScaled(0) / m_SliceSpacing(0),
+    uvScaled(1) / m_SliceSpacing(1),
+    0);
+
+  // Return this vector
+  return uvSlice;
+}
+
+Vector2f
+GenericSliceModel
+::MapSliceToPhysicalWindow(const Vector3f &xSlice)
+{
+  assert(IsSliceInitialized());
+
+  // Compute the physical window coordinates
+  Vector2f uvPhysical;
+  uvPhysical[0] = xSlice[0] * m_SliceSpacing[0];
+  uvPhysical[1] = xSlice[1] * m_SliceSpacing[1];
+
+  return uvPhysical;
+}
+
+void
+GenericSliceModel
+::ResetViewPosition()
+{
+  // Compute slice size in spatial coordinates
+  Vector2f worldSize(
+    m_SliceSize[0] * m_SliceSpacing[0],
+    m_SliceSize[1] * m_SliceSpacing[1]);
+
+  // Set the view position (position of the center of the image?)
+  m_ViewPosition = worldSize * 0.5f;
+
+  // Update view
+  InvokeEvent(SliceModelGeometryChangeEvent());
+}
+
+void
+GenericSliceModel
+::SetViewPositionRelativeToCursor(Vector2f offset)
+{
+  // Get the crosshair position
+  Vector3ui xCursorInteger = m_Driver->GetCursorPosition();
+
+  // Shift the cursor position by by 0.5 in order to have it appear
+  // between voxels
+  Vector3f xCursorImage = to_float(xCursorInteger) + Vector3f(0.5f);
+
+  // Get the cursor position on the slice
+  Vector3f xCursorSlice = MapImageToSlice(xCursorImage);
+
+  // Subtract from the view position
+  Vector2f vp;
+  vp[0] = offset[0] + xCursorSlice[0] * m_SliceSpacing[0];
+  vp[1] = offset[1] + xCursorSlice[1] * m_SliceSpacing[1];
+  SetViewPosition(vp);
+}
+
+Vector2f
+GenericSliceModel
+::GetViewPositionRelativeToCursor()
+{
+  // Get the crosshair position
+  Vector3ui xCursorInteger = m_Driver->GetCursorPosition();
+
+  // Shift the cursor position by by 0.5 in order to have it appear
+  // between voxels
+  Vector3f xCursorImage = to_float(xCursorInteger) + Vector3f(0.5f);
+
+  // Get the cursor position on the slice
+  Vector3f xCursorSlice = MapImageToSlice(xCursorImage);
+
+  // Subtract from the view position
+  Vector2f offset;
+  offset[0] = m_ViewPosition[0] - xCursorSlice[0] * m_SliceSpacing[0];
+  offset[1] = m_ViewPosition[1] - xCursorSlice[1] * m_SliceSpacing[1];
+
+  return offset;
+}
+
+void GenericSliceModel::CenterViewOnCursor()
+{
+  Vector2f offset; offset.fill(0.0f);
+  this->SetViewPositionRelativeToCursor(offset);
+}
+
+void GenericSliceModel::ZoomInOrOut(float factor)
+{
+  float oldzoom = m_ViewZoom;
+  float newzoom = oldzoom * factor;
+
+  if( (oldzoom < m_OptimalZoom && newzoom > m_OptimalZoom) ||
+      (oldzoom > m_OptimalZoom && newzoom < m_OptimalZoom) )
+    {
+    newzoom = m_OptimalZoom;
+    }
+
+  SetViewZoom(newzoom);
+}
+
+/*
+GenericSliceModel *
+GenericSliceModel
+::GenericSliceModel()
+{
+  SliceWindowCoordinator *swc = m_ParentUI->GetSliceCoordinator();
+  return swc->GetWindow( (m_Id+1) % 3);
+}
+*/
+
+bool
+GenericSliceModel
+::IsThumbnailOn()
+{
+  const GlobalDisplaySettings *gds = m_ParentUI->GetGlobalDisplaySettings();
+  return gds->GetFlagDisplayZoomThumbnail() && (m_ViewZoom > m_OptimalZoom);
+}
+
+Vector3f GenericSliceModel::GetCursorPositionInSliceCoordinates()
+{
+  Vector3ui cursorImageSpace = m_Driver->GetCursorPosition();
+  Vector3f cursorDisplaySpace =
+    m_ImageToDisplayTransform.TransformPoint(
+      to_float(cursorImageSpace) + Vector3f(0.5f));
+  return cursorDisplaySpace;
+}
+
+unsigned int GenericSliceModel::GetSliceIndex()
+{
+  Vector3ui cursorImageSpace = m_Driver->GetCursorPosition();
+  return cursorImageSpace[m_ImageAxes[2]];
+}
+
+
+void GenericSliceModel::UpdateSliceIndex(unsigned int newIndex)
+{
+  Vector3ui cursorImageSpace = m_Driver->GetCursorPosition();
+  cursorImageSpace[m_ImageAxes[2]] = newIndex;
+  m_Driver->SetCursorPosition(cursorImageSpace);
+}
+
+void GenericSliceModel::ComputeThumbnailProperties()
+{
+  // Get the global display settings
+  const GlobalDisplaySettings *gds = m_ParentUI->GetGlobalDisplaySettings();
+
+  // The thumbnail will occupy a specified fraction of the target canvas
+  float xFraction = 0.01f * gds->GetZoomThumbnailSizeInPercent();
+
+  // But it must not exceed a predefined size in pixels in either dimension
+  float xThumbMax = gds->GetZoomThumbnailMaximumSize();
+
+  // Recompute the fraction based on maximum size restriction
+  Vector2ui size = this->GetSize();
+  float xNewFraction = xFraction;
+  if( size[0] * xNewFraction > xThumbMax )
+    xNewFraction = xThumbMax * 1.0f / size[0];
+  if( size[1] * xNewFraction > xThumbMax )
+    xNewFraction = xThumbMax * 1.0f / size[1];
+
+  // Set the position and size of the thumbnail, in pixels
+  m_ThumbnailZoom = xNewFraction * m_OptimalZoom;
+  m_ThumbnailPosition.fill(5);
+  m_ThumbnailSize[0] =
+      (int)(m_SliceSize[0] * m_SliceSpacing[0] * m_ThumbnailZoom);
+  m_ThumbnailSize[1] =
+      (int)(m_SliceSize[1] * m_SliceSpacing[1] * m_ThumbnailZoom);
+}
+
+unsigned int GenericSliceModel::GetNumberOfSlices() const
+{
+  return m_SliceSize[2];
+}
+
+/*
+void GenericSliceModel::OnSourceDataUpdate()
+{
+  this->InitializeSlice(m_Driver->GetCurrentImageData());
+}
+*/
+
+void GenericSliceModel::SetViewPosition(Vector2f pos)
+{
+  if(m_ViewPosition != pos)
+    {
+    m_ViewPosition = pos;
+    InvokeEvent(SliceModelGeometryChangeEvent());
+    }
+}
+
+
+/*
+GenericSliceWindow::EventHandler
+::EventHandler(GenericSliceWindow *parent)
+: InteractionMode(parent->GetCanvas())
+{
+  m_Parent = parent;
+}
+
+void
+GenericSliceWindow::EventHandler
+::Register()
+{
+  m_Driver = m_Parent->m_Driver;
+  m_ParentUI = m_Parent->m_ParentUI;
+  m_GlobalState = m_Parent->m_GlobalState;
+}
+
+#include <itksys/SystemTools.hxx>
+
+int
+GenericSliceWindow::OnDragAndDrop(const FLTKEvent &event)
+{
+  // Check if it is a real file
+  if(event.Id == FL_PASTE)
+    {
+    if(itksys::SystemTools::FileExists(Fl::event_text(), true))
+      {
+      m_ParentUI->OpenDraggedContent(Fl::event_text(), true);
+      return 1;
+      }
+    return 0;
+    }
+  else
+    return 1;
+}
+*/
+
+
+unsigned int
+GenericSliceModel
+::MergeSliceSegmentation(itk::Image<unsigned char, 2> *drawing)
+{
+  // Z position of slice
+  float zpos = this->GetCursorPositionInSliceCoordinates()[2];
+  return m_Driver->UpdateSegmentationWithSliceDrawing(
+        drawing, m_DisplayToImageTransform, zpos, "Polygon Drawing");
+}
+
+Vector2ui GenericSliceModel::GetSize()
+{
+  Vector2ui viewport = m_SizeReporter->GetViewportSize();
+  DisplayLayoutModel *dlm = m_ParentUI->GetDisplayLayoutModel();
+  Vector2ui layout = dlm->GetSliceViewLayerTilingModel()->GetValue();
+  unsigned int rows = layout[0], cols = layout[1];
+  return Vector2ui(viewport[0] / cols, viewport[1] / rows);
+}
+
+
+bool GenericSliceModel
+::GetSliceIndexValueAndDomain(int &value, NumericValueRange<int> *domain)
+{
+  if(!m_Driver->IsMainImageLoaded())
+    return false;
+
+  value = this->GetSliceIndex();
+  if(domain)
+    {
+    domain->Set(0, this->GetNumberOfSlices()-1, 1);
+    }
+  return true;
+}
+
+void GenericSliceModel::SetSlideIndexValue(int value)
+{
+  this->UpdateSliceIndex(value);
+}
+
diff --git a/GUI/Model/GenericSliceModel.h b/GUI/Model/GenericSliceModel.h
new file mode 100644
index 0000000..2e4ee24
--- /dev/null
+++ b/GUI/Model/GenericSliceModel.h
@@ -0,0 +1,343 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef GENERICSLICEMODEL_H
+#define GENERICSLICEMODEL_H
+
+#include <SNAPCommon.h>
+#include <ImageCoordinateTransform.h>
+#include <OpenGLSliceTexture.h>
+#include <SNAPEvents.h>
+#include "AbstractModel.h"
+#include "ImageWrapper.h"
+#include "UIReporterDelegates.h"
+#include "PropertyModel.h"
+
+
+class GlobalUIModel;
+class IRISApplication;
+class GenericImageData;
+class GenericSliceModel;
+
+// An event fired when the geometry of the slice view changes
+itkEventMacro(SliceModelImageDimensionsChangeEvent, IRISEvent)
+itkEventMacro(SliceModelGeometryChangeEvent, IRISEvent)
+
+
+
+/**
+  \class GenericSliceModel
+  \brief Describes the state of the slice panel showing an orthogonal
+  projection of a dataset in ITK-SNAP
+
+  This class holds the state of the slice viewer widget. It contains
+  information about the slice currently being shown, the mapping of
+  coordinates between slice space and image space, and other bits of
+  information. Ideally, you should be able to store and retrieve the
+  state of this object between sessions.
+
+  This class is meant to be used with arbitrary GUI environments. It is
+  unaware of Qt, FLTK, etc.
+*/
+class GenericSliceModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(GenericSliceModel, AbstractModel)
+
+  itkEventMacro(ViewportResizeEvent, IRISEvent)
+
+  FIRES(ModelUpdateEvent)
+  FIRES(SliceModelGeometryChangeEvent)
+  FIRES(ViewportResizeEvent)
+
+  // irisDeclareEventObserver(ReinitializeEvent)
+
+  /**
+   * Initializer: takes global UI model and slice ID as input
+   */
+  void Initialize(GlobalUIModel *model, int index);
+
+  /**
+    Set the viewport reporter (and listen to viewport events)
+    */
+  void SetSizeReporter(ViewportSizeReporter *reporter);
+
+  /**
+    Get viewport reporter
+    */
+  irisGetMacro(SizeReporter, ViewportSizeReporter *)
+
+
+  /**
+    Update if necessary
+    */
+  virtual void OnUpdate();
+
+  /**
+   * Initialize the slice view with image data
+   */
+  void InitializeSlice(GenericImageData *data);
+
+  /**
+   * Reset the view parameters of the window (zoom, view position) to
+   * defaults
+   */
+  virtual void ResetViewToFit();
+
+  /**
+   * Map a point in window coordinates to a point in slice coordinates
+   * (Window coordinates are the ones stored in FLTKEvent.xSpace)
+   */
+  Vector3f MapWindowToSlice(const Vector2f &xWindow);
+
+  /**
+   * Map an offset in window coordinates to an offset in slice coordinates
+   */
+  Vector3f MapWindowOffsetToSliceOffset(const Vector2f &xWindowOffset);
+
+  /**
+   * Map a point in slice coordinates to a point in window coordinates
+   * (Window coordinates are the ones stored in FLTKEvent.xSpace)
+   */
+  Vector2f MapSliceToWindow(const Vector3f &xSlice);
+
+  /**
+   * Map a point in slice coordinates to a point in PHYISCAL window coordinates
+   */
+  Vector2f MapSliceToPhysicalWindow(const Vector3f &xSlice);
+
+  /**
+   * Map a point in slice coordinates to a point in the image coordinates
+   */
+  Vector3f MapSliceToImage(const Vector3f &xSlice);
+
+  /**
+   * Map a point in image coordinates to slice coordinates
+   */
+  Vector3f MapImageToSlice(const Vector3f &xImage);
+
+  /**
+   * Get the cursor position in slice coordinates, shifted to the center
+   * of the voxel
+   */
+  Vector3f GetCursorPositionInSliceCoordinates();
+
+  /**
+   * Get the slice index for this window
+   */
+  unsigned int GetSliceIndex();
+
+  /**
+   * Get the model that handles slice index information
+   */
+  irisGetMacro(SliceIndexModel, AbstractRangedIntProperty *)
+
+  /**
+   * Set the index of the slice in the current view. This method will
+   * update the cursor in the IRISApplication object
+   */
+  void UpdateSliceIndex(unsigned int newIndex);
+
+  /**
+   * Get the number of slices available in this view
+   */
+  unsigned int GetNumberOfSlices() const;
+
+  /** Return the image axis along which this window shows slices */
+  size_t GetSliceDirectionInImageSpace()
+    { return m_ImageAxes[2]; }
+
+  /** Reset the view position to center of the image */
+  void ResetViewPosition ();
+
+  /** Return the offset from the center of the viewport to the cursor position
+   * in slice units (#voxels * spacing). This is used to synchronize panning
+   * across SNAP sessions */
+  Vector2f GetViewPositionRelativeToCursor();
+
+  /** Set the offset from the center of the viewport to the cursor position */
+  void SetViewPositionRelativeToCursor(Vector2f offset);
+
+  /** Center the view on the image crosshairs */
+  void CenterViewOnCursor();
+
+  /** Set the zoom factor (number of pixels on the screen per millimeter in
+   * image space */
+  irisSetWithEventMacro(ViewZoom, float, SliceModelGeometryChangeEvent)
+
+  /**
+   * Zoom in/out by a specified factor. This method will 'stop' at the optimal
+   * zoom if it's between the old zoom and the new zoom
+   */
+  void ZoomInOrOut(float factor);
+
+  /** Get the zoom factor (number of pixels on the screen per millimeter in
+   * image space */
+  irisGetMacro(ViewZoom,float)
+
+  /** Computes the zoom that gives the best fit for the window */
+  void ComputeOptimalZoom();
+
+  /** Compute the optimal zoom (best fit) */
+  irisGetMacro(OptimalZoom,float)
+
+  /** Set the zoom management flag */
+  irisSetMacro(ManagedZoom,bool)
+
+  /** Set the view position **/
+  void SetViewPosition(Vector2f);
+
+  /** Get the view position **/
+  irisGetMacro(ViewPosition, Vector2f)
+
+  /** Get the slice spacing in the display space orientation */
+  irisGetMacro(SliceSpacing,Vector3f)
+
+  /** Get the slice spacing in the display space orientation */
+  irisGetMacro(SliceSize,Vector3i)
+
+  /** The id (slice direction) of this slice model */
+  irisGetMacro(Id, int)
+
+  /** Get the physical size of the window (updated from widget via events) */
+  Vector2ui GetSize();
+
+  /** Has the slice model been initialized with image data? */
+  irisIsMacro(SliceInitialized)
+
+  irisGetMacro(ParentUI, GlobalUIModel *)
+  irisGetMacro(Driver, IRISApplication *)
+
+  irisGetMacro(ImageData, GenericImageData *)
+
+  irisGetMacro(ThumbnailPosition, Vector2i)
+  irisGetMacro(ThumbnailSize, Vector2i)
+  irisGetMacro(ThumbnailZoom, float)
+
+  irisGetMacro(ImageToDisplayTransform, const ImageCoordinateTransform &)
+  irisGetMacro(DisplayToAnatomyTransform, const ImageCoordinateTransform &)
+  irisGetMacro(DisplayToImageTransform, const ImageCoordinateTransform &)
+
+  /** Compute the canvas size needed to display slice at current zoom factor */
+  Vector2i GetOptimalCanvasSize();
+
+  /** This method computes the thumbnail properties (size, zoom) */
+  void ComputeThumbnailProperties();
+
+  // Check whether the thumbnail should be drawn or not
+  bool IsThumbnailOn();
+
+  /**
+    Merges a binary segmentation drawn on a slice into the main
+    segmentation in SNAP. Returns the number of voxels changed.
+
+    This method might be better placed in IRISApplication
+   */
+  unsigned int MergeSliceSegmentation(
+        itk::Image<unsigned char, 2> *drawing);
+
+protected:
+
+  GenericSliceModel();
+  ~GenericSliceModel();
+
+  // Parent (where the global UI state is stored)
+  GlobalUIModel *m_ParentUI;
+
+  // Top-level logic object
+  IRISApplication *m_Driver;
+
+  // Pointer to the image data
+  GenericImageData *m_ImageData;
+
+  // Viewport size reporter
+  ViewportSizeReporter *m_SizeReporter;
+
+  // Window id, equal to the direction in display space along which the
+  // window shows slices
+  int m_Id;
+
+  // The index of the image space axes corresponding to the u,v,w of the
+  // window (computed by applying a transform to the DisplayAxes)
+  int m_ImageAxes[3];
+
+  // The transform from image coordinates to display coordinates
+  ImageCoordinateTransform m_ImageToDisplayTransform;
+
+  // The transform from display coordinates to image coordinates
+  ImageCoordinateTransform m_DisplayToImageTransform;
+
+  // The transform from display coordinates to patient coordinates
+  ImageCoordinateTransform m_DisplayToAnatomyTransform;
+
+  // Dimensions of the current slice (the third component is the size
+  // of the image in the slice direction)
+  Vector3i m_SliceSize;
+
+  // Pixel dimensions for the slice.  (the third component is the pixel
+  // width in the slice direction)
+  Vector3f m_SliceSpacing;
+
+  // Position of visible window in slice space coordinates
+  Vector2f m_ViewPosition;
+
+  // The view position where the slice wants to be
+  Vector2f m_OptimalViewPosition;
+
+  // The number of screen pixels per mm of image
+  float m_ViewZoom;
+
+  // The zoom level at which the slice fits snugly into the window
+  float m_OptimalZoom;
+
+  // Flag indicating whether the window's zooming is managed externally
+  // by the SliceWindowCoordinator
+  bool m_ManagedZoom;
+
+  // The default screen margin (area into which we do not paint) at
+  // least in default zoom
+  unsigned int m_Margin;
+
+  // The position and size of the zoom thumbnail
+  Vector2i m_ThumbnailPosition, m_ThumbnailSize;
+
+  // The zoom level in the thumbnail
+  double m_ThumbnailZoom;
+
+  // State of the model (whether it's been initialized)
+  bool m_SliceInitialized;
+
+  /** Access the next window in the slice pipeline */
+  GenericSliceModel *GetNextSliceWindow();
+
+  SmartPtr<AbstractRangedIntProperty> m_SliceIndexModel;
+  bool GetSliceIndexValueAndDomain(int &value, NumericValueRange<int> *domain);
+  void SetSlideIndexValue(int value);
+
+};
+
+#endif // GENERICSLICEMODEL_H
diff --git a/GUI/Model/GlobalPreferencesModel.cxx b/GUI/Model/GlobalPreferencesModel.cxx
new file mode 100644
index 0000000..1bc3774
--- /dev/null
+++ b/GUI/Model/GlobalPreferencesModel.cxx
@@ -0,0 +1,203 @@
+
+#include "GlobalPreferencesModel.h"
+#include "MeshOptions.h"
+#include "GlobalUIModel.h"
+#include "GlobalState.h"
+#include "DefaultBehaviorSettings.h"
+
+GlobalPreferencesModel::GlobalPreferencesModel()
+{
+  // Create all the property containers owned by the model. These hold copies
+  // of the property containers stored in the system.
+  m_DefaultBehaviorSettings = DefaultBehaviorSettings::New();
+  m_GlobalDisplaySettings = GlobalDisplaySettings::New();
+  m_MeshOptions = MeshOptions::New();
+
+  m_CheckForUpdateModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetCheckForUpdateValue, &Self::SetCheckForUpdateValue);
+  m_CheckForUpdateModel->RebroadcastFromSourceProperty(
+        m_DefaultBehaviorSettings->GetCheckForUpdatesModel());
+
+  // Current appearance element
+  m_ActiveUIElement = SNAPAppearanceSettings::CROSSHAIRS;
+  m_ActiveUIElementModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetActiveUIElementValue, &Self::SetActiveUIElementValue);
+
+  // All appearance elements
+  m_ActiveUIElementAppearance = OpenGLAppearanceElement::New();
+  for(int i = 0; i < SNAPAppearanceSettings::ELEMENT_COUNT; i++)
+    m_ElementAppearance[i] = OpenGLAppearanceElement::New();
+
+  // Layout labels
+  for(int j = 0; j < 3; j++)
+    {
+    m_LayoutLabelModel[j] = wrapIndexedGetterSetterPairAsProperty(
+          this, j, &Self::GetLayoutLabelIndexedValue);
+
+    m_LayoutLabelModel[j]->RebroadcastFromSourceProperty(
+          m_GlobalDisplaySettings->GetSliceLayoutModel());
+    }
+
+}
+
+bool GlobalPreferencesModel::GetCheckForUpdateValue(bool &outValue)
+{
+  switch(m_DefaultBehaviorSettings->GetCheckForUpdates())
+    {
+    case DefaultBehaviorSettings::UPDATE_YES:
+      outValue = true; return true;
+    case DefaultBehaviorSettings::UPDATE_NO:
+      outValue = false; return true;
+    case DefaultBehaviorSettings::UPDATE_UNKNOWN:
+      return false;
+    }
+  return false;
+}
+
+void GlobalPreferencesModel::SetCheckForUpdateValue(bool inValue)
+{
+  m_DefaultBehaviorSettings->SetCheckForUpdates(
+        inValue ? DefaultBehaviorSettings::UPDATE_YES : DefaultBehaviorSettings::UPDATE_NO);
+}
+
+bool GlobalPreferencesModel::GetActiveUIElementValue(GlobalPreferencesModel::UIElement &value)
+{
+  value = m_ActiveUIElement;
+  return true;
+}
+
+void GlobalPreferencesModel::SetActiveUIElementValue(GlobalPreferencesModel::UIElement value)
+{
+  if(m_ActiveUIElement != value)
+    {
+    // Locally store the current settings edited by the user
+    if(m_ActiveUIElement != SNAPAppearanceSettings::ELEMENT_COUNT)
+      m_ElementAppearance[m_ActiveUIElement]->DeepCopy(m_ActiveUIElementAppearance);
+
+    // Update the element
+    m_ActiveUIElement = value;
+
+    // Update the apperance shown to the user (unless this is a bad value)
+    if(m_ActiveUIElement != SNAPAppearanceSettings::ELEMENT_COUNT)
+      m_ActiveUIElementAppearance->DeepCopy(m_ElementAppearance[m_ActiveUIElement]);
+
+    // The state has changed
+    this->InvokeEvent(StateMachineChangeEvent());
+    }
+}
+
+bool GlobalPreferencesModel::GetLayoutLabelIndexedValue(int index, std::string &value)
+{
+  static std::map<GlobalDisplaySettings::UISliceLayout, std::string> idxmap;
+  if(!idxmap.size())
+    {
+    idxmap[GlobalDisplaySettings::LAYOUT_ACS] = "ACS";
+    idxmap[GlobalDisplaySettings::LAYOUT_ASC] = "ASC";
+    idxmap[GlobalDisplaySettings::LAYOUT_CAS] = "CAS";
+    idxmap[GlobalDisplaySettings::LAYOUT_CSA] = "CSA";
+    idxmap[GlobalDisplaySettings::LAYOUT_SAC] = "SAC";
+    idxmap[GlobalDisplaySettings::LAYOUT_SCA] = "SCA";
+    }
+
+  GlobalDisplaySettings::UISliceLayout lo = m_GlobalDisplaySettings->GetSliceLayout();
+  char letter = idxmap[lo][index];
+
+  switch(letter)
+    {
+    case 'A' : value = "Axial"; break;
+    case 'S' : value = "Sagittal"; break;
+    case 'C' : value = "Coronal"; break;
+    }
+
+  return true;
+}
+
+bool GlobalPreferencesModel::CheckState(GlobalPreferencesModel::UIState state)
+{
+  switch(state)
+    {
+    case GlobalPreferencesModel::UIF_VALID_UI_ELEMENT_SELECTED:
+      return m_ActiveUIElement != SNAPAppearanceSettings::ELEMENT_COUNT;
+    }
+  return false;
+}
+
+void GlobalPreferencesModel::SetParentModel(GlobalUIModel *parent)
+{
+  m_ParentModel = parent;
+}
+
+void GlobalPreferencesModel::InitializePreferences()
+{
+  // Pull the preferences from the system
+  GlobalState *gs = m_ParentModel->GetGlobalState();
+  SNAPAppearanceSettings *as = m_ParentModel->GetAppearanceSettings();
+
+  // Default behaviors
+  m_DefaultBehaviorSettings->DeepCopy(gs->GetDefaultBehaviorSettings());
+
+  // Global display prefs
+  m_GlobalDisplaySettings->DeepCopy(m_ParentModel->GetGlobalDisplaySettings());
+
+  // Mesh options
+  m_MeshOptions->DeepCopy(gs->GetMeshOptions());
+
+  // Appearance of all the elements
+  for(int i = 0; i < SNAPAppearanceSettings::ELEMENT_COUNT; i++)
+    m_ElementAppearance[i]->DeepCopy(as->GetUIElement(i));
+
+  // Apperance of selected element
+  if(m_ActiveUIElement != SNAPAppearanceSettings::ELEMENT_COUNT)
+    m_ActiveUIElementAppearance->DeepCopy(as->GetUIElement(m_ActiveUIElement));
+
+}
+
+void GlobalPreferencesModel::ApplyPreferences()
+{
+  // Pull the preferences from the system
+  GlobalState *gs = m_ParentModel->GetGlobalState();
+  SNAPAppearanceSettings *as = m_ParentModel->GetAppearanceSettings();
+
+  // Default behaviors
+  gs->GetDefaultBehaviorSettings()->DeepCopy(m_DefaultBehaviorSettings);
+
+  // Global display prefs
+  m_ParentModel->SetGlobalDisplaySettings(m_GlobalDisplaySettings);
+
+  // Mesh options
+  gs->GetMeshOptions()->DeepCopy(m_MeshOptions);
+
+  // If the current element is valid, accept it
+  if(m_ActiveUIElement != SNAPAppearanceSettings::ELEMENT_COUNT)
+    m_ElementAppearance[m_ActiveUIElement]->DeepCopy(m_ActiveUIElementAppearance);
+
+  // Appearance of all the elements
+  for(int i = 0; i < SNAPAppearanceSettings::ELEMENT_COUNT; i++)
+    as->GetUIElement(i)->DeepCopy(m_ElementAppearance[i]);
+}
+
+void GlobalPreferencesModel::ResetCurrentElement()
+{
+  assert(m_ActiveUIElement != SNAPAppearanceSettings::ELEMENT_COUNT);
+
+  SNAPAppearanceSettings *as = m_ParentModel->GetAppearanceSettings();
+  m_ActiveUIElementAppearance->DeepCopy(
+        as->GetUIElementDefaultSettings(m_ActiveUIElement));
+}
+
+void GlobalPreferencesModel::ResetAllElements()
+{
+  assert(m_ActiveUIElement != SNAPAppearanceSettings::ELEMENT_COUNT);
+
+  SNAPAppearanceSettings *as = m_ParentModel->GetAppearanceSettings();
+  for(int i = 0; i < SNAPAppearanceSettings::ELEMENT_COUNT; i++)
+    {
+    m_ElementAppearance[i]->DeepCopy(as->GetUIElementDefaultSettings(i));
+    }
+
+  if(m_ActiveUIElement != SNAPAppearanceSettings::ELEMENT_COUNT)
+    m_ActiveUIElementAppearance->DeepCopy(m_ElementAppearance[m_ActiveUIElement]);
+}
+
+
+
diff --git a/GUI/Model/GlobalPreferencesModel.h b/GUI/Model/GlobalPreferencesModel.h
new file mode 100644
index 0000000..3031de7
--- /dev/null
+++ b/GUI/Model/GlobalPreferencesModel.h
@@ -0,0 +1,134 @@
+#ifndef GLOBALPREFERENCESMODEL_H
+#define GLOBALPREFERENCESMODEL_H
+
+#include "PropertyModel.h"
+#include "ColorMap.h"
+#include "SNAPAppearanceSettings.h"
+
+class MeshOptions;
+class GlobalUIModel;
+class DefaultBehaviorSettings;
+
+/**
+ * This model exposes the different global preferences to the GUI. It is set
+ * up for a dialog in which the user must press Apply for the changes to
+ * be propagated to the GUI. So this model caches the values the preferences
+ * until the apply function is called
+ */
+class GlobalPreferencesModel : public AbstractModel
+{
+public:
+  irisITKObjectMacro(GlobalPreferencesModel, AbstractModel)
+
+  // Typedefs for interpolation mode
+  enum InterpolationMode { NEAREST = 0, LINEAR };
+  typedef SimpleItemSetDomain<InterpolationMode, std::string> InterpolationDomain;
+
+  // Typedefs for appearance
+  typedef SNAPAppearanceSettings::UIElements UIElement;
+
+  // State flags
+  enum UIState {
+    UIF_VALID_UI_ELEMENT_SELECTED
+  };
+
+  bool CheckState(UIState state);
+
+
+  // Default behaviors and permissions
+  irisGetMacro(DefaultBehaviorSettings, DefaultBehaviorSettings *)
+
+  // The model controlling whether updates are enabled or disabled must
+  // be exposed to the GUI as a boolean model, whereas internally it is
+  // of an ENUM type
+  irisSimplePropertyAccessMacro(CheckForUpdate, bool)
+
+  // Screen layout
+  irisGetMacro(GlobalDisplaySettings, GlobalDisplaySettings *)
+
+  // Other slice display properties
+  irisSimplePropertyAccessMacro(DefaultColorMapPreset, std::string)
+
+  // Current UI element whose apperance is being edited
+  irisSimplePropertyAccessMacro(ActiveUIElement, UIElement)
+
+  // Apperance of the current element
+  irisGetMacro(ActiveUIElementAppearance, OpenGLAppearanceElement *)
+
+  // Mesh options
+  irisGetMacro(MeshOptions, MeshOptions *)
+
+  // Screen layout labels
+  AbstractSimpleStringProperty *GetLayoutLabelModel(int i)
+    { return m_LayoutLabelModel[i]; }
+
+  /**
+   * Set the parent model
+   */
+  void SetParentModel(GlobalUIModel *parent);
+
+  irisGetMacro(ParentModel, GlobalUIModel *)
+
+  /**
+   * Initialize the internal cached properties based on current system state.
+   * This method should be called when opening the properties dialog, or on revert
+   */
+  void InitializePreferences();
+
+  /**
+   * Update the system state with the current cached preferences
+   */
+  void ApplyPreferences();
+
+  /** Reset visual element to default */
+  void ResetCurrentElement();
+
+  /** Reset all visual elements to default */
+  void ResetAllElements();
+
+protected:
+
+  GlobalPreferencesModel();
+
+  // Default behaviors and permissions (copy of the system's settings)
+  SmartPtr<DefaultBehaviorSettings> m_DefaultBehaviorSettings;
+
+  // Updates model
+  SmartPtr<AbstractSimpleBooleanProperty> m_CheckForUpdateModel;
+  bool GetCheckForUpdateValue(bool &outValue);
+  void SetCheckForUpdateValue(bool inValue);
+
+  // Color map preset model (tricky)
+  SmartPtr<ConcreteSimpleStringProperty> m_DefaultColorMapPresetModel;
+
+  // Current appearance element
+  UIElement m_ActiveUIElement;
+
+  // The model for the appearance element. This is a model that wraps around the
+  // getter and setter below, since changes to the active element require additional
+  // changes to this class.
+  SmartPtr<AbstractPropertyModel<UIElement, TrivialDomain> > m_ActiveUIElementModel;
+  bool GetActiveUIElementValue(UIElement &value);
+  void SetActiveUIElementValue(UIElement value);
+
+  // The cached apperance settings for the active element
+  SmartPtr<OpenGLAppearanceElement> m_ActiveUIElementAppearance;
+
+  // The apperance settings for all elements (held until user presses apply)
+  SmartPtr<OpenGLAppearanceElement> m_ElementAppearance[SNAPAppearanceSettings::ELEMENT_COUNT];
+
+  // Mesh options (we keep a copy)
+  SmartPtr<MeshOptions> m_MeshOptions;
+
+  // Copy of the system's global display preferences (thumbnail, etc)
+  SmartPtr<GlobalDisplaySettings> m_GlobalDisplaySettings;
+
+  // Layout label
+  SmartPtr<AbstractSimpleStringProperty> m_LayoutLabelModel[3];
+  bool GetLayoutLabelIndexedValue(int index, std::string &value);
+
+  // Parent model
+  GlobalUIModel *m_ParentModel;
+};
+
+#endif // GLOBALPREFERENCESMODEL_H
diff --git a/GUI/Model/GlobalUIModel.cxx b/GUI/Model/GlobalUIModel.cxx
new file mode 100644
index 0000000..feb7629
--- /dev/null
+++ b/GUI/Model/GlobalUIModel.cxx
@@ -0,0 +1,873 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "GlobalUIModel.h"
+
+#include <IRISException.h>
+#include <IRISApplication.h>
+#include <SNAPAppearanceSettings.h>
+#include <GenericSliceModel.h>
+#include <OrthogonalSliceCursorNavigationModel.h>
+#include <PolygonDrawingModel.h>
+#include <SnakeROIModel.h>
+#include <SliceWindowCoordinator.h>
+#include <GenericImageData.h>
+#include <GuidedNativeImageIO.h>
+#include <ImageIODelegates.h>
+#include <IntensityCurveModel.h>
+#include <LayerSelectionModel.h>
+#include <ColorMapModel.h>
+#include <ImageInfoModel.h>
+#include <LayerGeneralPropertiesModel.h>
+#include <Generic3DModel.h>
+#include <LabelEditorModel.h>
+#include <CursorInspectionModel.h>
+#include <SnakeWizardModel.h>
+#include <RandomAccessCollectionModel.h>
+#include <UIReporterDelegates.h>
+#include <ReorientImageModel.h>
+#include <DisplayLayoutModel.h>
+#include <PaintbrushModel.h>
+#include <PaintbrushSettingsModel.h>
+#include <SynchronizationModel.h>
+#include <SnakeParameterModel.h>
+#include <SnakeROIResampleModel.h>
+#include "NumericPropertyToggleAdaptor.h"
+#include "HistoryManager.h"
+#include "MeshExportModel.h"
+#include "GlobalPreferencesModel.h"
+#include "MeshOptions.h"
+#include "DefaultBehaviorSettings.h"
+#include "SNAPAppearanceSettings.h"
+#include "ImageIOWizardModel.h"
+#include "IntensityCurveInterface.h"
+#include "ColorLabelQuickListModel.h"
+
+#include <itksys/SystemTools.hxx>
+
+#include <SNAPUIFlag.h>
+#include <SNAPUIFlag.txx>
+
+// Enable this model to be used with the flag engine
+template class SNAPUIFlag<GlobalUIModel, UIState>;
+
+
+GlobalUIModel::GlobalUIModel()
+  : AbstractModel()
+{
+  // Create the appearance settings objects
+  m_AppearanceSettings = SNAPAppearanceSettings::New();
+
+  // Global display settings
+  m_GlobalDisplaySettings = GlobalDisplaySettings::New();
+
+  // Create the IRIS application login
+  m_Driver = IRISApplication::New();
+
+  // Display layout model
+  m_DisplayLayoutModel = DisplayLayoutModel::New();
+  m_DisplayLayoutModel->SetParentModel(this);
+
+  // Paintbrush settings
+  m_PaintbrushSettingsModel = PaintbrushSettingsModel::New();
+  m_PaintbrushSettingsModel->SetParentModel(this);
+
+  // Create the slice models
+  for (unsigned int i = 0; i < 3; i++)
+    {
+    m_SliceModel[i] = GenericSliceModel::New();
+    m_SliceModel[i]->Initialize(this, i);
+    m_CursorNavigationModel[i] =
+        OrthogonalSliceCursorNavigationModel::New();
+    m_CursorNavigationModel[i]->SetParent(m_SliceModel[i]);
+
+    m_PolygonDrawingModel[i] = PolygonDrawingModel::New();
+    m_PolygonDrawingModel[i]->SetParent(m_SliceModel[i]);
+
+    m_SnakeROIModel[i] = SnakeROIModel::New();
+    m_SnakeROIModel[i]->SetParent(m_SliceModel[i]);
+
+    m_PaintbrushModel[i] = PaintbrushModel::New();
+    m_PaintbrushModel[i]->SetParent(m_SliceModel[i]);
+    }
+
+  // Connect them together with the coordinator
+  m_SliceCoordinator = SliceWindowCoordinator::New();
+  m_SliceCoordinator->SetParentModel(this);
+
+  // Intensity curve model
+  m_IntensityCurveModel = IntensityCurveModel::New();
+  m_IntensityCurveModel->SetParentModel(this);
+
+  // Color map model
+  m_ColorMapModel = ColorMapModel::New();
+  m_ColorMapModel->SetParentModel(this);
+
+  // Image info model
+  m_ImageInfoModel = ImageInfoModel::New();
+  m_ImageInfoModel->SetParentModel(this);
+
+  // Component selection
+  m_LayerGeneralPropertiesModel = LayerGeneralPropertiesModel::New();
+  m_LayerGeneralPropertiesModel->SetParentModel(this);
+
+  // Layer selections
+  m_LoadedLayersSelectionModel = LayerSelectionModel::New();
+  m_LoadedLayersSelectionModel->SetParentModel(this);
+  m_LoadedLayersSelectionModel->SetRoleFilter(
+        MAIN_ROLE | OVERLAY_ROLE |
+        SNAP_ROLE);
+
+  // 3D model
+  m_Model3D = Generic3DModel::New();
+  m_Model3D->Initialize(this);
+
+  // Label editor model
+  m_LabelEditorModel = LabelEditorModel::New();
+  m_LabelEditorModel->SetParentModel(this);
+
+  // Reorient image model
+  m_ReorientImageModel = ReorientImageModel::New();
+  m_ReorientImageModel->SetParentModel(this);
+
+  // Cursor inspection
+  m_CursorInspectionModel = CursorInspectionModel::New();
+  m_CursorInspectionModel->SetParentModel(this);
+
+  // Snake model
+  m_SnakeWizardModel = SnakeWizardModel::New();
+  m_SnakeWizardModel->SetParentModel(this);
+
+  // Snake ROI resampling model
+  m_SnakeROIResampleModel = SnakeROIResampleModel::New();
+  m_SnakeROIResampleModel->SetParentModel(this);
+
+  // Synchronization model
+  m_SynchronizationModel = SynchronizationModel::New();
+  m_SynchronizationModel->SetParentModel(this);
+
+  // Snake parameter model
+  m_SnakeParameterModel = SnakeParameterModel::New();
+  m_SnakeParameterModel->SetParentModel(this);
+
+  // Mesh export model
+  m_MeshExportModel = MeshExportModel::New();
+  m_MeshExportModel->SetParentModel(this);
+
+  // Global prefs model
+  m_GlobalPreferencesModel = GlobalPreferencesModel::New();
+  m_GlobalPreferencesModel->SetParentModel(this);
+
+  // Quick list of color labels
+  m_ColorLabelQuickListModel = ColorLabelQuickListModel::New();
+  m_ColorLabelQuickListModel->SetParentModel(this);
+
+  // Set up the cursor position model
+  m_CursorPositionModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetCursorPositionValueAndRange,
+        &Self::SetCursorPosition);
+
+  // The model needs to rebroadcast cusror change events as value changes. This
+  // is because unlike other more specific models, GlobalUIModel does not fire
+  // ModelUpdateEvent objects.
+  m_CursorPositionModel->Rebroadcast(
+        this, CursorUpdateEvent(), ValueChangedEvent());
+  m_CursorPositionModel->Rebroadcast(
+        m_Driver, MainImageDimensionsChangeEvent(), DomainChangedEvent());
+
+  // ROI size and index models
+  m_SnakeROIIndexModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetSnakeROIIndexValueAndRange,
+        &Self::SetSnakeROIIndexValue);
+
+  m_SnakeROIIndexModel->Rebroadcast(
+        m_Driver->GetGlobalState()->GetSegmentationROISettingsModel(),
+        ValueChangedEvent(), ValueChangedEvent());
+
+  m_SnakeROIIndexModel->Rebroadcast(
+        m_Driver, MainImageDimensionsChangeEvent(), DomainChangedEvent());
+
+  m_SnakeROISizeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetSnakeROISizeValueAndRange,
+        &Self::SetSnakeROISizeValue);
+
+  m_SnakeROISizeModel->Rebroadcast(
+        m_Driver->GetGlobalState()->GetSegmentationROISettingsModel(),
+        ValueChangedEvent(), ValueChangedEvent());
+
+  m_SnakeROISizeModel->Rebroadcast(
+        m_Driver, MainImageDimensionsChangeEvent(), DomainChangedEvent());
+
+
+  // Segmentation opacity models
+  m_SegmentationOpacityModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetSegmentationOpacityValueAndRange,
+        &Self::SetSegmentationOpacityValue);
+
+  m_SegmentationOpacityModel->RebroadcastFromSourceProperty(
+        m_Driver->GetGlobalState()->GetSegmentationAlphaModel());
+
+  m_SegmentationVisibilityModel =
+      NewNumericPropertyToggleAdaptor(m_SegmentationOpacityModel.GetPointer(), 0, 50);
+
+  // Simple toggle for whether controls for layer visibility and reorder are shown
+  m_LayerVisibilityEditableModel = NewSimpleConcreteProperty(false);
+
+  // Listen to state changes from the slice coordinator
+  Rebroadcast(m_SliceCoordinator, LinkedZoomUpdateEvent(), LinkedZoomUpdateEvent());
+  Rebroadcast(m_SliceCoordinator, LinkedZoomUpdateEvent(), StateMachineChangeEvent());
+
+  // Rebroadcast cursor change events
+  Rebroadcast(m_Driver, CursorUpdateEvent(), CursorUpdateEvent());
+
+  // Rebroadcast image layer change events
+  Rebroadcast(m_Driver, LayerChangeEvent(), LayerChangeEvent());
+  Rebroadcast(m_Driver, LayerChangeEvent(), StateMachineChangeEvent());
+
+  // Rebroadcast toolbar model change events (TODO: needed?)
+  Rebroadcast(m_Driver->GetGlobalState()->GetToolbarModeModel(),
+              ValueChangedEvent(), ToolbarModeChangeEvent());
+
+  // All the events that result in the voxel under the cursor changing
+  Rebroadcast(this, CursorUpdateEvent(), LabelUnderCursorChangedEvent());
+  Rebroadcast(m_Driver->GetColorLabelTable(), SegmentationLabelChangeEvent(),
+              LabelUnderCursorChangedEvent());
+
+  Rebroadcast(m_Driver, SegmentationChangeEvent(), LabelUnderCursorChangedEvent());
+  Rebroadcast(m_Driver, SegmentationChangeEvent(), StateMachineChangeEvent());
+
+  // Segmentation ROI event
+  Rebroadcast(m_Driver->GetGlobalState()->GetSegmentationROISettingsModel(),
+              ValueChangedEvent(), SegmentationROIChangedEvent());
+
+  // The initial reporter delegate is NULL
+  m_ProgressReporterDelegate = NULL;
+
+  // Initialize the progress reporting command
+  SmartPtr<itk::MemberCommand<Self> > progcmd = itk::MemberCommand<Self>::New();
+  progcmd->SetCallbackFunction(this, &GlobalUIModel::ProgressCallback);
+  m_ProgressCommand = progcmd.GetPointer();
+
+}
+
+GlobalUIModel::~GlobalUIModel()
+{
+}
+
+bool GlobalUIModel::CheckState(UIState state)
+{
+  // TODO: implement all the other cases
+
+  // TODO: the flag values need to be cached and updated in response to incoming
+  // events. Otherwise, there are just too many of these calls happening. Alternatively,
+  // each state could be handled as a separate model.
+  switch(state)
+    {
+    case UIF_BASEIMG_LOADED:
+      return m_Driver->IsMainImageLoaded();
+    case UIF_IRIS_WITH_BASEIMG_LOADED:
+      return m_Driver->IsMainImageLoaded() && !m_Driver->IsSnakeModeActive();
+    case UIF_IRIS_MODE:
+      return !m_Driver->IsSnakeModeActive();
+    case UIF_IRIS_WITH_OVERLAY_LOADED:
+      return m_Driver->IsMainImageLoaded() && !m_Driver->IsSnakeModeActive()
+          && m_Driver->GetCurrentImageData()->GetNumberOfOverlays() > 0;
+    case UIF_ROI_VALID:
+      break;
+    case UIF_LINKED_ZOOM:
+      return m_SliceCoordinator->GetLinkedZoom();
+    case UIF_UNDO_POSSIBLE:
+      return m_Driver->IsUndoPossible();
+    case UIF_REDO_POSSIBLE:
+      return m_Driver->IsRedoPossible();
+    case UIF_UNSAVED_CHANGES:
+      break;
+    case UIF_MESH_SAVEABLE:
+      break;
+    case UIF_OVERLAY_LOADED:
+      return m_Driver->GetCurrentImageData()->IsOverlayLoaded();
+    case UIF_SNAKE_MODE:
+      return m_Driver->IsSnakeModeActive();
+    case UIF_LEVEL_SET_ACTIVE:
+      return m_Driver->IsSnakeModeLevelSetActive();
+    }
+
+  return false;
+}
+
+void GlobalUIModel::AutoContrastAllLayers()
+{
+  GenericImageData *id = m_Driver->GetCurrentImageData();
+  for(LayerIterator it = id->GetLayers(MAIN_ROLE | OVERLAY_ROLE); !it.IsAtEnd(); ++it)
+    {
+    ImageWrapperBase *layer = it.GetLayer();
+    AbstractContinuousImageDisplayMappingPolicy *policy =
+        dynamic_cast<AbstractContinuousImageDisplayMappingPolicy *>(layer->GetDisplayMapping());
+    if(policy)
+      policy->AutoFitContrast();
+    }
+}
+
+void GlobalUIModel::ResetContrastAllLayers()
+{
+  GenericImageData *id = m_Driver->GetCurrentImageData();
+  for(LayerIterator it = id->GetLayers(MAIN_ROLE | OVERLAY_ROLE); !it.IsAtEnd(); ++it)
+    {
+    ImageWrapperBase *layer = it.GetLayer();
+    AbstractContinuousImageDisplayMappingPolicy *policy =
+        dynamic_cast<AbstractContinuousImageDisplayMappingPolicy *>(layer->GetDisplayMapping());
+    if(policy && policy->GetIntensityCurve())
+      policy->GetIntensityCurve()->Reset();
+    }
+}
+
+void GlobalUIModel::ToggleOverlayVisibility()
+{
+  // Are we in tiled mode or in stack mode?
+  GenericImageData *id = m_Driver->GetCurrentImageData();
+  bool stack =
+      (m_DisplayLayoutModel->GetSliceViewLayerLayoutModel()->GetValue()
+       == LAYOUT_STACKED);
+
+  // Remember what layer is current in the general properties model
+  ImageWrapperBase *curr_layer = m_LayerGeneralPropertiesModel->GetLayer();
+
+  // Apply the toggle for all overlays
+  for(LayerIterator it = id->GetLayers(OVERLAY_ROLE); !it.IsAtEnd(); ++it)
+    {
+    // In stack mode, every overlay is affected. In tile mode, only stickly layers
+    // are affected
+    if(stack || it.GetLayer()->IsSticky())
+      {
+      m_LayerGeneralPropertiesModel->SetLayer(it.GetLayer());
+      m_LayerGeneralPropertiesModel->GetLayerVisibilityModel()->SetValue(
+            !m_LayerGeneralPropertiesModel->GetLayerVisibilityModel()->GetValue());
+      }
+    }
+
+  // Restore the active layer
+  m_LayerGeneralPropertiesModel->SetLayer(curr_layer);
+}
+
+void GlobalUIModel::AdjustOverlayOpacity(int delta)
+{
+  // Are we in tiled mode or in stack mode?
+  GenericImageData *id = m_Driver->GetCurrentImageData();
+  bool stack =
+      (m_DisplayLayoutModel->GetSliceViewLayerLayoutModel()->GetValue()
+       == LAYOUT_STACKED);
+
+  // Remember what layer is current in the general properties model
+  ImageWrapperBase *curr_layer = m_LayerGeneralPropertiesModel->GetLayer();
+
+  // Apply the toggle for all overlays
+  for(LayerIterator it = id->GetLayers(OVERLAY_ROLE); !it.IsAtEnd(); ++it)
+    {
+    // In stack mode, every overlay is affected. In tile mode, only stickly layers
+    // are affected
+    if(stack || it.GetLayer()->IsSticky())
+      {
+      m_LayerGeneralPropertiesModel->SetLayer(it.GetLayer());
+      int op = m_LayerGeneralPropertiesModel->GetLayerOpacityModel()->GetValue();
+      int op_new = std::min(100, std::max(0, op + delta));
+      m_LayerGeneralPropertiesModel->GetLayerOpacityModel()->SetValue(op_new);
+      }
+    }
+
+  // Restore the active layer
+  m_LayerGeneralPropertiesModel->SetLayer(curr_layer);
+}
+
+
+void GlobalUIModel::SetGlobalDisplaySettings(
+    const GlobalDisplaySettings *settings)
+{
+  // Check if the settings affecting the slice RAI codes have changed
+  std::string raiOld[3], raiNew[3];
+  m_GlobalDisplaySettings->GetAnatomyToDisplayTransforms(raiOld[0], raiOld[1], raiOld[2]);
+  settings->GetAnatomyToDisplayTransforms(raiNew[0], raiNew[1], raiNew[2]);
+
+  // Update the global display settings
+  m_GlobalDisplaySettings->DeepCopy(settings);
+
+  // React to the change in RAI codes
+  if(raiOld[0] != raiNew[0] || raiOld[1] != raiNew[1] || raiOld[2] != raiNew[2])
+    {
+    // Update the RAI codes in all slice views
+    m_Driver->SetDisplayGeometry(IRISDisplayGeometry(raiNew[0], raiNew[1], raiNew[2]));
+
+    // Update the cursor location
+    if(m_Driver->IsMainImageLoaded())
+      {
+      // Update the cursor position (forced)
+      m_Driver->SetCursorPosition(m_Driver->GetCursorPosition(), true);
+
+      // Reinitialize all the slice views
+      for(int i = 0; i < 3; i++)
+        m_SliceModel[i]->InitializeSlice(m_Driver->GetCurrentImageData());
+
+      // Recenter all views
+      m_SliceCoordinator->ResetViewToFitInAllWindows();
+      }
+    }
+}
+
+SystemInterface * GlobalUIModel::GetSystemInterface() const
+{
+  return m_Driver->GetSystemInterface();
+}
+
+GlobalState * GlobalUIModel::GetGlobalState() const
+{
+  return m_Driver->GetGlobalState();
+}
+
+#include "SynchronizationModel.h"
+
+void GlobalUIModel::LoadUserPreferences()
+{
+  SystemInterface *si = m_Driver->GetSystemInterface();
+
+  DefaultBehaviorSettings *dbs =
+      m_Driver->GetGlobalState()->GetDefaultBehaviorSettings();
+
+  // Load the user preferences from the file system
+  si->LoadUserPreferences();
+
+  // Read the appearance settings
+  m_AppearanceSettings->LoadFromRegistry(
+        si->Folder("UserInterface.Appearance"));
+
+  // Read the default behaviors
+  dbs->ReadFromRegistry(
+        si->Folder("UserInterface.DefaultBehavior"));
+
+  // Read the global display properties
+  m_GlobalDisplaySettings->ReadFromRegistry(
+        si->Folder("SliceView.DisplaySettings"));
+
+  // Read the 3D mesh options
+  m_Driver->GetGlobalState()->GetMeshOptions()->ReadFromRegistry(
+        si->Folder("View3D.MeshOptions"));
+
+  // At this point we should check if the color map preset in the prefs
+  // is still a valid preset, and if it isn't, replace it with a default
+  if(!m_Driver->GetColorMapPresetManager()->IsValidPreset(
+       dbs->GetOverlayColorMapPreset()))
+    {
+    dbs->SetOverlayColorMapPreset(ColorMap::GetPresetName(ColorMap::COLORMAP_GREY));
+    }
+
+  // Apply the default startup behaviors
+  m_SliceCoordinator->SetLinkedZoom(dbs->GetLinkedZoom());
+  m_SynchronizationModel->SetSyncEnabled(dbs->GetSynchronization());
+  m_SynchronizationModel->SetSyncCursor(dbs->GetSyncCursor());
+  m_SynchronizationModel->SetSyncZoom(dbs->GetSyncZoom());
+  m_SynchronizationModel->SetSyncPan(dbs->GetSyncPan());
+  m_Model3D->SetContinuousUpdate(dbs->GetContinuousMeshUpdate());
+  m_Driver->GetGlobalState()->SetSliceViewLayerLayout(dbs->GetOverlayLayout());
+}
+
+void GlobalUIModel::SaveUserPreferences()
+{
+  SystemInterface *si = m_Driver->GetSystemInterface();
+
+  // Read the appearance settings
+  m_AppearanceSettings->SaveToRegistry(
+        si->Folder("UserInterface.Appearance"));
+
+  // Read the default behaviors
+  m_Driver->GetGlobalState()->GetDefaultBehaviorSettings()->WriteToRegistry(
+        si->Folder("UserInterface.DefaultBehavior"));
+
+  // Read the global display properties
+  m_GlobalDisplaySettings->WriteToRegistry(
+        si->Folder("SliceView.DisplaySettings"));
+
+  // Read the 3D mesh options
+  m_Driver->GetGlobalState()->GetMeshOptions()->WriteToRegistry(
+        si->Folder("View3D.MeshOptions"));
+
+  // Save the preferences
+  si->SaveUserPreferences();
+}
+
+bool GlobalUIModel::GetCursorPositionValueAndRange(
+    Vector3ui &value, NumericValueRange<Vector3ui> *range)
+{
+  if(m_Driver->IsMainImageLoaded())
+    {
+    value = m_Driver->GetCursorPosition() + 1u;
+    if(range)
+      {
+      range->Set(Vector3ui(1u),
+                 m_Driver->GetCurrentImageData()->GetMain()->GetSize(),
+                 Vector3ui(1u));
+      }
+    return true;
+    }
+
+  return false;
+}
+
+void GlobalUIModel::SetCursorPosition(Vector3ui value)
+{
+  m_Driver->SetCursorPosition(value - 1u);
+}
+
+bool GlobalUIModel::GetSnakeROIIndexValueAndRange(
+    Vector3ui &value, NumericValueRange<Vector3ui> *range)
+{
+  // There has to be an image
+  if(!m_Driver->IsMainImageLoaded())
+    return false;
+
+  // Get the image size
+  Vector3ui imsize =
+      m_Driver->GetCurrentImageData()->GetImageRegion().GetSize();
+
+  // Get the system's region of interest
+  GlobalState::RegionType roiSystem =
+      m_Driver->GetGlobalState()->GetSegmentationROI();
+
+  // Populate the return value
+  for(int i = 0; i < 3; i++)
+    {
+    value[i] = roiSystem.GetIndex()[i] + 1;
+    if(range)
+      {
+      range->Minimum[i] = 1;
+      range->Maximum[i] = imsize[i] - 1;
+      range->StepSize[i] = 1;
+      }
+    }
+
+  return true;
+}
+
+void GlobalUIModel::SetSnakeROIIndexValue(Vector3ui value)
+{
+  // Get the image size
+  Vector3ui imsize =
+      m_Driver->GetCurrentImageData()->GetImageRegion().GetSize();
+
+  // Get the system's region of interest
+  GlobalState::RegionType roi =
+      m_Driver->GetGlobalState()->GetSegmentationROI();
+
+  // Index changed, clamp the size
+  for(int i = 0; i < 3; i++)
+    {
+    roi.SetIndex(i, value[i] - 1);
+    roi.SetSize(i, std::min(value[i], imsize[i] - value[i]));
+    }
+
+  m_Driver->GetGlobalState()->SetSegmentationROI(roi);
+}
+
+bool GlobalUIModel::GetSnakeROISizeValueAndRange(
+    Vector3ui &value, NumericValueRange<Vector3ui> *range)
+{
+  // There has to be an image
+  if(!m_Driver->IsMainImageLoaded())
+    return false;
+
+  // Get the image size
+  Vector3ui imsize =
+      m_Driver->GetCurrentImageData()->GetImageRegion().GetSize();
+
+  // Get the system's region of interest
+  GlobalState::RegionType roiSystem =
+      m_Driver->GetGlobalState()->GetSegmentationROI();
+
+  // Populate the return value
+  for(int i = 0; i < 3; i++)
+    {
+    value[i] = roiSystem.GetSize()[i];
+    if(range)
+      {
+      range->Minimum[i] = 1;
+      range->Maximum[i] = imsize[i];
+      range->StepSize[i] = 1;
+      }
+    }
+
+  return true;
+}
+
+void GlobalUIModel::SetSnakeROISizeValue(Vector3ui value)
+{
+  // Get the image size
+  Vector3ui imsize =
+      m_Driver->GetCurrentImageData()->GetImageRegion().GetSize();
+
+  // Get the system's region of interest
+  GlobalState::RegionType roi =
+      m_Driver->GetGlobalState()->GetSegmentationROI();
+
+  // Size changed, clamp the index
+  for(int i = 0; i < 3; i++)
+    {
+    roi.SetSize(i, value[i]);
+    if(value[i] + roi.GetIndex(i) > imsize[i])
+      roi.SetIndex(i, imsize[i] - value[1]);
+    }
+
+  m_Driver->GetGlobalState()->SetSegmentationROI(roi);
+}
+
+bool
+GlobalUIModel::GetSegmentationOpacityValueAndRange(
+    int &value, NumericValueRange<int> *domain)
+{
+  // Round the current alpha value to the nearest integer
+  double alpha = m_Driver->GetGlobalState()->GetSegmentationAlpha();
+  value = (int)(alpha * 100 + 0.5);
+
+  // Set the domain
+  if(domain)
+    domain->Set(0, 100, 5);
+
+  return true;
+}
+
+void GlobalUIModel::SetSegmentationOpacityValue(int value)
+{
+  m_Driver->GetGlobalState()->SetSegmentationAlpha(value / 100.0);
+}
+
+
+std::vector<std::string>
+GlobalUIModel::GetRecentHistoryItems(const char *historyCategory, unsigned int k)
+{
+  // Load the list of recent files from the history file
+  const HistoryManager::HistoryListType &history =
+      this->GetSystemInterface()->GetHistoryManager()->GetGlobalHistory(historyCategory);
+
+  std::vector<std::string> recent;
+
+  // Take the five most recent items and create menu items
+  for(unsigned int i = 0; i < k; i++)
+    {
+    if(i < history.size())
+      {
+      recent.push_back(history[history.size() - (i+1)]);
+      }
+    }
+
+  return recent;
+}
+
+bool GlobalUIModel::IsHistoryEmpty(const char *historyCategory)
+{
+  // Load the list of recent files from the history file
+  const HistoryManager::HistoryListType &history =
+      this->GetSystemInterface()->GetHistoryManager()->GetGlobalHistory(historyCategory);
+
+  return history.size() == 0;
+}
+
+GlobalUIModel::AbstractHistoryModel *
+GlobalUIModel::GetHistoryModel(const std::string &category)
+{
+  return m_Driver->GetHistoryManager()->GetGlobalHistoryModel(category);
+}
+
+std::string GlobalUIModel::GenerateScreenshotFilename()
+{
+  // Get the last screen shot filename used
+  std::string last = m_LastScreenshotFileName;
+  if(last.length() == 0)
+    return "snapshot0001.png";
+
+  // Count how many digits there are at the end of the filename
+  std::string noext =
+    itksys::SystemTools::GetFilenameWithoutExtension(last);
+  unsigned int digits = 0;
+  for(int i = noext.length() - 1; i >= 0; i--)
+    {
+    if(isdigit(noext[i]))
+      digits++;
+    else break;
+    }
+
+  // If there are no digits, return the filename
+  if(digits == 0) return last;
+
+  // Get the number at the end of the string
+  std::string snum = noext.substr(noext.length() - digits);
+  std::istringstream iss(snum);
+  unsigned long num = 0;
+  iss >> num;
+
+  // Increment the number by one and convert to another string, padding with zeros
+  std::ostringstream oss;
+  oss << itksys::SystemTools::GetFilenamePath(last);
+  oss << "/";
+  oss << noext.substr(0, noext.length() - digits);
+  oss << std::setw(digits) << std::setfill('0') << (num + 1);
+  oss << itksys::SystemTools::GetFilenameExtension(last);
+  return oss.str();
+}
+
+SmartPtr<ImageIOWizardModel>
+GlobalUIModel::CreateIOWizardModelForSave(ImageWrapperBase *layer, LayerRole role)
+{
+  // Create save delegate for this layer
+  SmartPtr<AbstractSaveImageDelegate> delegate =
+      m_Driver->CreateSaveDelegateForLayer(layer, role);
+
+  // Figure out the category name
+  std::string category;
+  switch(role)
+    {
+    case MAIN_ROLE:
+      category = "Main Image";
+      break;
+    case OVERLAY_ROLE:
+      category = "Overlay Image";
+      break;
+    case SNAP_ROLE:
+      if(dynamic_cast<SpeedImageWrapper *>(layer))
+        category = "Speed Image";
+      else if(dynamic_cast<LevelSetImageWrapper *>(layer))
+        category = "Level Set Image";
+      break;
+    case LABEL_ROLE:
+      category = "Segmentation Image";
+      break;
+    case NO_ROLE:
+    case ALL_ROLES:
+      break;
+    }
+
+  // Create a model for IO
+  SmartPtr<ImageIOWizardModel> modelIO = ImageIOWizardModel::New();
+  modelIO->InitializeForSave(this, delegate, category.c_str());
+
+  return modelIO;
+}
+
+void GlobalUIModel::AnimateLayerComponents()
+{
+  // TODO: For now all the layers tagged as animating animate. This is the
+  // dumbest possible way to do animation, but it's fine for one layer or
+  // multiple layers with the same number of components.
+  for(LayerIterator it = m_Driver->GetCurrentImageData()->GetLayers();
+      !it.IsAtEnd(); ++it)
+    {
+    if(it.GetLayer()->GetNumberOfComponents() > 1)
+      {
+      AbstractMultiChannelDisplayMappingPolicy *dp = dynamic_cast<
+          AbstractMultiChannelDisplayMappingPolicy *>(
+            it.GetLayer()->GetDisplayMapping());
+
+      if(dp && dp->GetAnimate())
+        {
+        MultiChannelDisplayMode mode = dp->GetDisplayMode();
+        if(mode.SelectedScalarRep == SCALAR_REP_COMPONENT)
+          {
+          mode.SelectedComponent =
+              (mode.SelectedComponent + 1) % it.GetLayer()->GetNumberOfComponents();
+          dp->SetDisplayMode(mode);
+          }
+        }
+      }
+    }
+}
+
+void GlobalUIModel::IncrementDrawingColorLabel(int delta)
+{
+  ColorLabelTable *clt = m_Driver->GetColorLabelTable();
+  LabelType current = m_Driver->GetGlobalState()->GetDrawingColorLabel();
+  ColorLabelTable::ValidLabelConstIterator pos =
+      clt->GetValidLabels().find(current);
+  if(delta == 1)
+    ++pos;
+  else if(delta == -1)
+    --pos;
+
+  if(pos != clt->GetValidLabels().end())
+    m_Driver->GetGlobalState()->SetDrawingColorLabel(pos->first);
+}
+
+void GlobalUIModel::IncrementDrawOverColorLabel(int delta)
+{
+  // Handle basic cases
+  DrawOverFilter dof = m_Driver->GetGlobalState()->GetDrawOverFilter();
+  if(dof.CoverageMode == PAINT_OVER_ALL && delta == 1)
+    {
+    dof.CoverageMode = PAINT_OVER_VISIBLE;
+    }
+  else if(dof.CoverageMode == PAINT_OVER_VISIBLE && delta == 1)
+    {
+    dof.CoverageMode = PAINT_OVER_ONE;
+    dof.DrawOverLabel = 0;
+    }
+  else if(dof.CoverageMode == PAINT_OVER_VISIBLE && delta == -1)
+    {
+    dof.CoverageMode = PAINT_OVER_ALL;
+    }
+  else if(dof.CoverageMode == PAINT_OVER_ONE && delta == -1 && dof.DrawOverLabel == 0)
+    {
+    dof.CoverageMode = PAINT_OVER_VISIBLE;
+    dof.DrawOverLabel = 0;
+    }
+  else if(dof.CoverageMode == PAINT_OVER_ONE)
+    {
+    ColorLabelTable *clt = m_Driver->GetColorLabelTable();
+    ColorLabelTable::ValidLabelConstIterator pos =
+        clt->GetValidLabels().find(dof.DrawOverLabel);
+    if(delta == 1)
+      ++pos;
+    else if(delta == -1)
+      --pos;
+
+    if(pos != clt->GetValidLabels().end())
+      dof.DrawOverLabel = pos->first;
+    }
+  else
+    {
+    return;
+    }
+
+  m_Driver->GetGlobalState()->SetDrawOverFilter(dof);
+}
+
+void
+GlobalUIModel
+::ProgressCallback(itk::Object *source, const itk::EventObject &event)
+{
+  if(m_ProgressReporterDelegate)
+    {
+    itk::ProcessObject *po = static_cast<itk::ProcessObject *>(source);
+    m_ProgressReporterDelegate->SetProgressValue(po->GetProgress());
+    }
+}
diff --git a/GUI/Model/GlobalUIModel.h b/GUI/Model/GlobalUIModel.h
new file mode 100644
index 0000000..249630b
--- /dev/null
+++ b/GUI/Model/GlobalUIModel.h
@@ -0,0 +1,428 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef GLOBALUIMODEL_H
+#define GLOBALUIMODEL_H
+
+#include <SNAPCommon.h>
+#include <SNAPEvents.h>
+#include <AbstractModel.h>
+#include <UIState.h>
+#include <PropertyModel.h>
+#include <ColorLabelPropertyModel.h>
+
+class IRISApplication;
+class SNAPAppearanceSettings;
+class GenericSliceModel;
+class OrthogonalSliceCursorNavigationModel;
+class PolygonDrawingModel;
+class SliceWindowCoordinator;
+class GuidedNativeImageIO;
+class SystemInterface;
+class GlobalState;
+class AbstractLoadImageDelegate;
+class IRISWarningList;
+class IntensityCurveModel;
+class LayerSelectionModel;
+class ColorMapModel;
+class ImageInfoModel;
+class Generic3DModel;
+class LabelEditorModel;
+class ConcreteColorLabelPropertyModel;
+class CursorInspectionModel;
+class SnakeROIModel;
+class SnakeWizardModel;
+class SnakeROIResampleModel;
+class ProgressReporterDelegate;
+class ReorientImageModel;
+class DisplayLayoutModel;
+class PaintbrushModel;
+class PaintbrushSettingsModel;
+class LayerGeneralPropertiesModel;
+class SynchronizationModel;
+class SnakeParameterModel;
+class MeshExportModel;
+class GlobalPreferencesModel;
+class GlobalDisplaySettings;
+class ImageIOWizardModel;
+class ImageWrapperBase;
+class ColorLabelQuickListModel;
+
+namespace itk
+{
+class Command;
+}
+
+
+class SystemInfoDelegate;
+
+
+/**
+
+
+  */
+class GlobalUIModel : public AbstractModel
+{
+
+public:
+
+  typedef AbstractModel Superclass;
+  typedef GlobalUIModel Self;
+  typedef SmartPtr<Self> Pointer;
+  typedef SmartPtr<const Self> ConstPointer;
+
+  itkNewMacro(Self)
+  itkTypeMacro(GlobalUIModel, AbstractModel)
+
+
+  // Events fired by this object
+  FIRES(CursorUpdateEvent)
+  FIRES(LayerChangeEvent)
+  FIRES(LinkedZoomUpdateEvent)
+  FIRES(LabelUnderCursorChangedEvent)
+  FIRES(ToolbarModeChangedEvent)
+
+
+
+  irisGetMacro(Driver, IRISApplication *)
+
+  irisGetMacro(AppearanceSettings, SNAPAppearanceSettings *)
+
+  /** Get the global display settings (thumbnail properties, etc.) */
+  irisGetMacro(GlobalDisplaySettings, const GlobalDisplaySettings *)
+
+  /** Update the global display settings (thumbnail properties, etc.) */
+  void SetGlobalDisplaySettings(const GlobalDisplaySettings *settings);
+
+  irisGetMacro(SliceCoordinator, SliceWindowCoordinator *)
+
+  // Convenience access to the SystemInfterface
+  SystemInterface *GetSystemInterface() const;
+
+  // I don't know why this is in a separate class
+  GlobalState *GetGlobalState() const;
+
+  /**
+   * Load the global user preferences at startup. This high-level method
+   * loads the preference file into m_SystemInterface and then pulls out
+   * of the registry folders various settings.
+   *
+   * TODO: this is coded badly. SystemInterface is a poorly designed class
+   * that combines low-level and high-level functionality. It needs to be
+   * recoded
+   */
+  void LoadUserPreferences();
+
+  /**
+   * Save user preferences to disk before quitting the application
+   */
+  void SaveUserPreferences();
+
+  GenericSliceModel *GetSliceModel(unsigned int i) const
+    { return m_SliceModel[i]; }
+
+  /** Get the slice navigation model for each slice */
+  OrthogonalSliceCursorNavigationModel *
+  GetCursorNavigationModel(unsigned int i) const
+    { return m_CursorNavigationModel[i]; }
+
+  /** Get the polygon drawing model for each slice */
+  PolygonDrawingModel *GetPolygonDrawingModel(unsigned int i) const
+  {
+    return m_PolygonDrawingModel[i];
+  }
+
+  /** Get the polygon drawing model for each slice */
+  SnakeROIModel *GetSnakeROIModel(unsigned int i) const
+  {
+    return m_SnakeROIModel[i];
+  }
+
+  PaintbrushModel *GetPaintbrushModel(unsigned int i) const
+  {
+    return m_PaintbrushModel[i];
+  }
+
+  /** Get the model for intensity curve navigation */
+  irisGetMacro(IntensityCurveModel, IntensityCurveModel *)
+
+  /** Get the model for color map interation */
+  irisGetMacro(ColorMapModel, ColorMapModel *)
+
+  /** Get the model for obtaining image info for layers */
+  irisGetMacro(ImageInfoModel, ImageInfoModel *)
+
+  /** Get the model for selecting channels in a multi-channel image */
+  irisGetMacro(LayerGeneralPropertiesModel, LayerGeneralPropertiesModel *)
+
+  /** Get the model encapsulating the main images and all overlays */
+  irisGetMacro(LoadedLayersSelectionModel, LayerSelectionModel *)
+
+  /** Get the model for 3D window interaction */
+  irisGetMacro(Model3D, Generic3DModel *)
+
+  /** Get the model for the label editor */
+  irisGetMacro(LabelEditorModel, LabelEditorModel *)
+
+  /** Get the model for image reorientation */
+  irisGetMacro(ReorientImageModel, ReorientImageModel *)
+
+  /** Get the model that handles UI for the cursor inspector */
+  irisGetMacro(CursorInspectionModel, CursorInspectionModel *)
+
+  /** The model that handles snake wizard interaction */
+  irisGetMacro(SnakeWizardModel, SnakeWizardModel *)
+
+  /** The model handling display layout properties */
+  irisGetMacro(DisplayLayoutModel, DisplayLayoutModel *)
+
+  /** Model for managing paintbrush settings */
+  irisGetMacro(PaintbrushSettingsModel, PaintbrushSettingsModel *)
+
+  /** Model for multi-session sync */
+  irisGetMacro(SynchronizationModel, SynchronizationModel *)
+
+  /** Model for snake parameter editing */
+  irisGetMacro(SnakeParameterModel, SnakeParameterModel *)
+
+  /** Model for the snake ROI resampling */
+  irisGetMacro(SnakeROIResampleModel, SnakeROIResampleModel *)
+
+  /** Model for the mesh export wizard */
+  irisGetMacro(MeshExportModel, MeshExportModel *)
+
+  /** Model for the preferences dialog */
+  irisGetMacro(GlobalPreferencesModel, GlobalPreferencesModel *)
+
+  /** Model for the list of recently used color labels */
+  irisGetMacro(ColorLabelQuickListModel, ColorLabelQuickListModel *)
+
+  /**
+    Check the state of the system. This class will issue StateChangeEvent()
+    when one of the flags has changed. This method can be used together with
+    the SNAPUIFlag object to construct listeners to complex state changes.
+   */
+  bool CheckState(UIState state);
+
+  /** Get the model for the cursor coordinates */
+  irisGetMacro(CursorPositionModel, AbstractRangedUIntVec3Property *)
+
+  /** Get the models for the snake ROI */
+  irisGetMacro(SnakeROIIndexModel, AbstractRangedUIntVec3Property *)
+  irisGetMacro(SnakeROISizeModel, AbstractRangedUIntVec3Property *)
+
+  /** A model for overall segmentation opacity (int, range 0..100) */
+  irisRangedPropertyAccessMacro(SegmentationOpacity, int)
+
+  /** A model for the segmentation visibility on/off state */
+  irisSimplePropertyAccessMacro(SegmentationVisibility, bool)
+
+  /** Whether layer visibility and organization properties are editable */
+  irisSimplePropertyAccessMacro(LayerVisibilityEditable, bool)
+
+  /** Method to toggle overlay visibility (all or selected overlays) */
+  void ToggleOverlayVisibility();
+
+  /** Method to adjust overlay opacity (all or selected overlays) */
+  void AdjustOverlayOpacity(int delta);
+
+  /** Get a list of k recent "things" that are tracked in history */
+  std::vector<std::string> GetRecentHistoryItems(
+      const char *historyCategory, unsigned int k = 5);
+
+  /** Check if a particular history is empty */
+  bool IsHistoryEmpty(const char *historyCategory);
+
+  typedef AbstractPropertyModel< std::vector<std::string> > AbstractHistoryModel;
+
+  /** A quick-access method to the global history models, same as calling the
+   * GetGlobalHistoryModel() in the HistoryManager() */
+  AbstractHistoryModel *GetHistoryModel(const std::string &category);
+
+  /** Get the progress command */
+  irisGetMacro(ProgressCommand, itk::Command *)
+
+  /** Get and set the progress reporter delegate */
+  irisGetSetMacro(ProgressReporterDelegate, ProgressReporterDelegate *)
+
+  /** Get and set the last screenshot filename */
+  irisGetSetMacro(LastScreenshotFileName, std::string)
+
+  /** Generate a suggested filename for saving screenshots, by incrementing
+   *  from thelast saved screenshot filename */
+  std::string GenerateScreenshotFilename();
+
+  /**
+   * Create a temporary model for saving an image layer to a file, to use in
+   * conjunction with an IO wizard. We pass in the Layer and the LayerRole
+   */
+  SmartPtr<ImageIOWizardModel> CreateIOWizardModelForSave(
+      ImageWrapperBase *layer, LayerRole role);
+
+  /**
+   * Perform an animation step
+   */
+  void AnimateLayerComponents();
+
+  /** Increment the current color label (delta = 1 or -1) */
+  void IncrementDrawingColorLabel(int delta);
+
+  /** Increment the draw over color label (delta = 1 or -1) */
+  void IncrementDrawOverColorLabel(int delta);
+
+  /** Auto-adjust contrast in all image layers */
+  void AutoContrastAllLayers();
+
+  /** Auto-adjust contrast in all image layers */
+  void ResetContrastAllLayers();
+
+protected:
+
+  GlobalUIModel();
+  ~GlobalUIModel();
+
+  // Callback for reporting progress
+  void ProgressCallback(itk::Object *source, const itk::EventObject &event);
+
+  SmartPtr<IRISApplication> m_Driver;
+
+  SmartPtr<SNAPAppearanceSettings> m_AppearanceSettings;
+
+  SmartPtr<GlobalDisplaySettings> m_GlobalDisplaySettings;
+
+  // A set of three slice models, representing the UI state of each
+  // of the 2D slice panels the user interacts with
+  SmartPtr<GenericSliceModel> m_SliceModel[3];
+
+  // A set of models that support cursor navigation
+  SmartPtr<OrthogonalSliceCursorNavigationModel> m_CursorNavigationModel[3];
+
+  // Models for polygon drawing
+  SmartPtr<PolygonDrawingModel> m_PolygonDrawingModel[3];
+
+  // Models for snake ROI drawing
+  SmartPtr<SnakeROIModel> m_SnakeROIModel[3];
+
+  // Models for paintbrush drawing
+  SmartPtr<PaintbrushModel> m_PaintbrushModel[3];
+
+  // Window coordinator
+  SmartPtr<SliceWindowCoordinator> m_SliceCoordinator;
+
+  // Model for intensity curve manipulation
+  SmartPtr<IntensityCurveModel> m_IntensityCurveModel;
+
+  // Model for color map manipulation
+  SmartPtr<ColorMapModel> m_ColorMapModel;
+
+  // Model for image info interaction
+  SmartPtr<ImageInfoModel> m_ImageInfoModel;
+
+  // Model for multi-channel image component selection
+  SmartPtr<LayerGeneralPropertiesModel> m_LayerGeneralPropertiesModel;
+
+  // Layer selection model encapsulating the main image and overlays
+  SmartPtr<LayerSelectionModel> m_LoadedLayersSelectionModel;
+
+  // Label editor model
+  SmartPtr<LabelEditorModel> m_LabelEditorModel;
+
+  // Reorient image model
+  SmartPtr<ReorientImageModel> m_ReorientImageModel;
+
+  // Cursor interaction model
+  SmartPtr<CursorInspectionModel> m_CursorInspectionModel;
+
+  // 3D Model
+  SmartPtr<Generic3DModel> m_Model3D;
+
+  // The snake wizard model
+  SmartPtr<SnakeWizardModel> m_SnakeWizardModel;
+
+  // Display layout model
+  SmartPtr<DisplayLayoutModel> m_DisplayLayoutModel;
+
+  // Paintbrush settings
+  SmartPtr<PaintbrushSettingsModel> m_PaintbrushSettingsModel;
+
+  // Synchronization
+  SmartPtr<SynchronizationModel> m_SynchronizationModel;
+
+  // Snake parameters
+  SmartPtr<SnakeParameterModel> m_SnakeParameterModel;
+
+  // Snake resampling model
+  SmartPtr<SnakeROIResampleModel> m_SnakeROIResampleModel;
+
+  // Model for the quick list of recently used labels
+  SmartPtr<ColorLabelQuickListModel> m_ColorLabelQuickListModel;
+
+  // Current coordinates of the cursor
+  SmartPtr<AbstractRangedUIntVec3Property> m_CursorPositionModel;
+  bool GetCursorPositionValueAndRange(
+      Vector3ui &value, NumericValueRange<Vector3ui> *range);
+  void SetCursorPosition(Vector3ui value);
+
+  // Current ROI for snake mode
+  SmartPtr<AbstractRangedUIntVec3Property> m_SnakeROIIndexModel;
+  bool GetSnakeROIIndexValueAndRange(
+      Vector3ui &value, NumericValueRange<Vector3ui> *range);
+  void SetSnakeROIIndexValue(Vector3ui value);
+
+  SmartPtr<AbstractRangedUIntVec3Property> m_SnakeROISizeModel;
+  bool GetSnakeROISizeValueAndRange(
+      Vector3ui &value, NumericValueRange<Vector3ui> *range);
+  void SetSnakeROISizeValue(Vector3ui value);
+
+  // The model for the mesh export wizard
+  SmartPtr<MeshExportModel> m_MeshExportModel;
+
+  // Global preferences model
+  SmartPtr<GlobalPreferencesModel> m_GlobalPreferencesModel;
+
+  // A pointer to the progress reporter delegate object
+  ProgressReporterDelegate *m_ProgressReporterDelegate;
+
+  // An ITK command used to handle progress
+  SmartPtr<itk::Command> m_ProgressCommand;
+
+  // Screenshot filename
+  std::string m_LastScreenshotFileName;
+
+  // Segmentation opacity and visibility models
+  SmartPtr<AbstractRangedIntProperty> m_SegmentationOpacityModel;
+  SmartPtr<AbstractSimpleBooleanProperty> m_SegmentationVisibilityModel;
+
+  // Whether layer visibility and order are editable in the layer inspector
+  SmartPtr<ConcreteSimpleBooleanProperty> m_LayerVisibilityEditableModel;
+
+  // Callbacks for the opacity model
+  bool GetSegmentationOpacityValueAndRange(int &value, NumericValueRange<int> *domain);
+  void SetSegmentationOpacityValue(int value);
+
+};
+
+#endif // GLOBALUIMODEL_H
diff --git a/GUI/Model/ImageIOWizardModel.cxx b/GUI/Model/ImageIOWizardModel.cxx
new file mode 100644
index 0000000..b71e7eb
--- /dev/null
+++ b/GUI/Model/ImageIOWizardModel.cxx
@@ -0,0 +1,405 @@
+#include "ImageIOWizardModel.h"
+#include "GuidedNativeImageIO.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "SystemInterface.h"
+#include "ImageCoordinateGeometry.h"
+#include <itksys/SystemTools.hxx>
+#include "HistoryManager.h"
+
+#include "IRISException.h"
+#include <sstream>
+
+#include "ImageIODelegates.h"
+
+ImageIOWizardModel::ImageIOWizardModel()
+{
+  m_Parent = NULL;
+  m_GuidedIO = NULL;
+  m_LoadDelegate = NULL;
+  m_SaveDelegate = NULL;
+}
+
+
+void
+ImageIOWizardModel
+::InitializeForSave(GlobalUIModel *parent,
+                    AbstractSaveImageDelegate *delegate,
+                    const char *dispName)
+{
+  m_Parent = parent;
+  m_Mode = SAVE;
+  m_HistoryName = delegate->GetHistoryName();
+  m_DisplayName = dispName;
+  m_GuidedIO = GuidedNativeImageIO::New();
+  m_LoadDelegate = NULL;
+  m_SaveDelegate = delegate;
+  m_SuggestedFilename = delegate->GetCurrentFilename();
+}
+
+void
+ImageIOWizardModel
+::InitializeForLoad(GlobalUIModel *parent,
+                    AbstractLoadImageDelegate *delegate,
+                    const char *name,
+                    const char *dispName)
+{
+  m_Parent = parent;
+  m_Mode = LOAD;
+  m_HistoryName = name;
+  m_DisplayName = dispName;
+  m_GuidedIO = GuidedNativeImageIO::New();
+  m_LoadDelegate = delegate;
+  m_SaveDelegate = NULL;
+}
+
+ImageIOWizardModel::~ImageIOWizardModel()
+{
+}
+
+std::string
+ImageIOWizardModel
+::GetFilter(const char *lineEntry,
+            const char *extEntry,
+            const char *extSeparator,
+            const char *rowSeparator)
+{
+  std::ostringstream ossMain;
+  char buffer[1024];
+
+  // Go through all supported formats
+  for(unsigned int i=0;i < GuidedNativeImageIO::FORMAT_COUNT;i++)
+    {
+    FileFormat fmt = static_cast<FileFormat>(i);
+    GuidedNativeImageIO::FileFormatDescriptor fd =
+      GuidedNativeImageIO::GetFileFormatDescriptor(fmt);
+
+    // Check if the file format is supported
+    if(this->CanHandleFileFormat(fmt))
+      {
+      std::ostringstream ossLine;
+
+      // Scan all of the separators
+      size_t pos = 0;
+      while(pos < fd.pattern.size())
+        {
+        if(pos)
+          ossLine << extSeparator;
+        size_t pend = fd.pattern.find(',', pos);
+        std::string ext = fd.pattern.substr(pos, pend-pos);
+        sprintf(buffer, extEntry, ext.c_str());
+        ossLine << buffer;
+        pos = (pend == std::string::npos) ? pend : pend+1;
+        }
+
+      // Append a row to the format list
+      sprintf(buffer, lineEntry, fd.name.c_str(), ossLine.str().c_str());
+      ossMain << buffer;
+      ossMain << rowSeparator;
+      }
+    }
+
+  return ossMain.str();
+}
+
+ImageIOWizardModel::FileFormat
+ImageIOWizardModel::GuessFileFormat(
+    const std::string &fname, bool &fileExists)
+{
+  // For files that don't exist, format can not be reported
+  if(m_Mode == LOAD)
+    {
+    fileExists = itksys::SystemTools::FileExists(fname.c_str(), true);
+    if(!fileExists)
+      return GuidedNativeImageIO::FORMAT_COUNT;
+    }
+
+  // Look if there is prior knowledge of this image. This overrides
+  // everything else
+  Registry reg;
+  m_Parent->GetDriver()->GetSystemInterface()->
+      FindRegistryAssociatedWithFile(fname.c_str(), reg);
+
+  // If the registry contains a file format, override with that
+  FileFormat fmt =
+    m_GuidedIO->GetFileFormat(reg, GuidedNativeImageIO::FORMAT_COUNT);
+
+  // Try to select a file format accoring to the file name
+  if(fmt != GuidedNativeImageIO::FORMAT_COUNT)
+    return fmt;
+
+  // If there is no prior knowledge determine the format using magic
+  // numbers and extension information
+  return GuidedNativeImageIO::GuessFormatForFileName(fname, m_Mode==LOAD);
+}
+
+ImageIOWizardModel::FileFormat
+ImageIOWizardModel::GetFileFormatByName(const std::string &formatName) const
+{
+  for(int i = 0; i < GuidedNativeImageIO::FORMAT_COUNT; i++)
+    {
+    FileFormat fmt = (FileFormat) i;
+    if(GuidedNativeImageIO::GetFileFormatDescriptor(fmt).name == formatName)
+      return fmt;
+    }
+
+  return GuidedNativeImageIO::FORMAT_COUNT;
+}
+
+std::string ImageIOWizardModel::GetFileFormatName(ImageIOWizardModel::FileFormat fmt) const
+{
+  return GuidedNativeImageIO::GetFileFormatDescriptor(fmt).name;
+}
+
+bool ImageIOWizardModel
+::CanHandleFileFormat(ImageIOWizardModel::FileFormat fmt)
+{
+  GuidedNativeImageIO::FileFormatDescriptor fd =
+    GuidedNativeImageIO::GetFileFormatDescriptor(fmt);
+  return (m_Mode == LOAD) || (m_Mode == SAVE && fd.can_write);
+}
+
+std::string
+ImageIOWizardModel::GetBrowseDirectory(const std::string &file)
+{
+  // If empty return empty
+  if(file.length() == 0)
+    return file;
+
+  // If file is a directory, return it
+  std::string fn_expand = file;
+  itksys::SystemTools::ConvertToUnixSlashes(fn_expand);
+  if(itksys::SystemTools::FileIsDirectory(fn_expand.c_str()))
+    return fn_expand;
+
+  // Get the base name of the file
+  std::string path = itksys::SystemTools::GetFilenamePath(fn_expand);
+  if(itksys::SystemTools::FileIsDirectory(path.c_str()))
+    return path;
+
+  // By default, return empty string
+  return std::string("");
+}
+
+std::string ImageIOWizardModel::GetDisplayName() const
+{
+  return m_DisplayName;
+}
+
+template<class T>
+std::string triple2str(const T &triple)
+{
+  std::ostringstream oss;
+  oss << triple[0];
+  oss << " x ";
+  oss << triple[1];
+  oss << " x ";
+  oss << triple[2];
+  return oss.str();
+}
+
+std::string
+ImageIOWizardModel::GetSummaryItem(ImageIOWizardModel::SummaryItem item)
+{
+  std::ostringstream sout;
+  vnl_matrix<double> dir;
+  std::string rai;
+
+  switch(item)
+    {
+  case ImageIOWizardModel::SI_FILENAME:
+    return m_GuidedIO->GetFileNameOfNativeImage();
+
+  case ImageIOWizardModel::SI_DIMS:
+    return triple2str(m_GuidedIO->GetNativeImage()->GetBufferedRegion().GetSize());
+
+  case ImageIOWizardModel::SI_SPACING:
+    return triple2str(m_GuidedIO->GetNativeImage()->GetSpacing());
+
+  case ImageIOWizardModel::SI_ORIGIN:
+    return triple2str(m_GuidedIO->GetNativeImage()->GetOrigin());
+
+  case ImageIOWizardModel::SI_ORIENT:
+    dir = m_GuidedIO->GetNativeImage()->GetDirection().GetVnlMatrix();
+    rai = ImageCoordinateGeometry::ConvertDirectionMatrixToClosestRAICode(dir);
+    if(ImageCoordinateGeometry::IsDirectionMatrixOblique(dir))
+      sout << "Oblique (closest to " << rai << ")";
+    else
+      sout << rai;
+    return sout.str();
+
+  case ImageIOWizardModel::SI_ENDIAN:
+    return (m_GuidedIO->GetByteOrderInNativeImage()
+            == itk::ImageIOBase::BigEndian)
+        ? "Big Endian" : "Little Endian";
+
+  case ImageIOWizardModel::SI_DATATYPE:
+    if(m_GuidedIO->GetComponentTypeInNativeImage()
+       != itk::ImageIOBase::UNKNOWNCOMPONENTTYPE)
+      {
+      // There actually is a type in the IO object
+      return m_GuidedIO->GetComponentTypeAsStringInNativeImage();
+      }
+    else
+      {
+      // TODO: This is a workaround on an itk bug with RawImageIO
+      // TODO: fix this (get the text selected for the raw image)
+      return "Unknown";
+      }
+
+  case ImageIOWizardModel::SI_COMPONENTS:
+    sout << m_GuidedIO->GetNumberOfComponentsInNativeImage();
+    return sout.str();
+
+  case ImageIOWizardModel::SI_FILESIZE:
+    sout << (m_GuidedIO->GetFileSizeOfNativeImage() / 1024.0) << " Kb";
+    return sout.str();
+    }
+
+  return std::string("");
+}
+
+void ImageIOWizardModel::SetSelectedFormat(ImageIOWizardModel::FileFormat fmt)
+{
+  GuidedNativeImageIO::SetFileFormat(m_Registry, fmt);
+}
+
+
+ImageIOWizardModel::FileFormat ImageIOWizardModel::GetSelectedFormat()
+{
+  return GuidedNativeImageIO::GetFileFormat(m_Registry);
+}
+
+
+void ImageIOWizardModel::LoadImage(std::string filename)
+{
+  try
+  {
+    // Clear the warnings
+    m_Warnings.clear();
+
+    // Load the header
+    m_GuidedIO->ReadNativeImageHeader(filename.c_str(), m_Registry);
+
+    // Check if the header is valid
+    m_LoadDelegate->ValidateHeader(m_GuidedIO, m_Warnings);
+
+    // Remove current data
+    m_LoadDelegate->UnloadCurrentImage();
+
+    // Load the data from the image
+    m_GuidedIO->ReadNativeImageData();
+
+    // Validate the image data
+    m_LoadDelegate->ValidateImage(m_GuidedIO, m_Warnings);
+
+    // Update the application
+    m_LoadDelegate->UpdateApplicationWithImage(m_GuidedIO);
+
+    // Save the IO hints to the registry
+    Registry regAssoc;
+    SystemInterface *si = m_Parent->GetDriver()->GetSystemInterface();
+    si->FindRegistryAssociatedWithFile(
+          m_GuidedIO->GetFileNameOfNativeImage().c_str(), regAssoc);
+    regAssoc.Folder("Files.Grey").Update(m_Registry);
+    si->AssociateRegistryWithFile(
+          m_GuidedIO->GetFileNameOfNativeImage().c_str(), regAssoc);
+  }
+  catch(IRISException &excIRIS)
+  {
+    throw excIRIS;
+  }
+  catch(std::exception &exc)
+  {
+    throw IRISException("Error: exception occured during image IO. "
+                        "Exception: %s", exc.what());
+  }
+}
+
+void ImageIOWizardModel::SaveImage(std::string filename)
+{
+  try
+  {
+  m_SaveDelegate->SaveImage(filename, m_GuidedIO, m_Registry, m_Warnings);
+  }
+  catch(std::exception &exc)
+  {
+    throw IRISException("Error: exception occured during image IO. "
+                        "Exception: %s", exc.what());
+  }
+}
+
+bool ImageIOWizardModel::CheckImageValidity()
+{
+  IRISWarningList warn;
+  m_LoadDelegate->ValidateHeader(m_GuidedIO, warn);
+
+  return true;
+}
+
+void ImageIOWizardModel::Reset()
+{
+  m_Registry.Clear();
+}
+
+void ImageIOWizardModel::ProcessDicomDirectory(const std::string &filename)
+{
+  // Here is a request
+  GuidedNativeImageIO::DicomRequest req;
+  req.push_back(GuidedNativeImageIO::DicomRequestField(
+                  0x0020, 0x0011, "SeriesNumber"));
+
+  // Get the directory
+  std::string dir = GetBrowseDirectory(filename);
+
+  // Get the registry
+  try
+  {
+    m_GuidedIO->ParseDicomDirectory(dir, m_DicomContents, req);
+  }
+  catch (IRISException &ei)
+  {
+    throw ei;
+  }
+  catch (std::exception &e)
+  {
+    throw IRISException("Error: exception occured when parsing DICOM directory. "
+                        "Exception: %s", e.what());
+  }
+}
+
+void ImageIOWizardModel
+::LoadDicomSeries(const std::string &filename, int series)
+{
+  // Set up the registry for DICOM IO
+  m_Registry["DICOM.SeriesId"] << m_DicomContents[series]["SeriesId"][""];
+  m_Registry.Folder("DICOM.SeriesFiles").PutArray(
+        m_DicomContents[series].Folder("SeriesFiles").GetArray(std::string()));
+
+  // Set the format to DICOM
+  SetSelectedFormat(GuidedNativeImageIO::FORMAT_DICOM_DIR);
+
+  // Get the directory
+  std::string dir = GetBrowseDirectory(filename);
+
+  // Call the main load method
+  this->LoadImage(dir);
+}
+
+unsigned long ImageIOWizardModel::GetFileSizeInBytes(const std::string &file)
+{
+  return itksys::SystemTools::FileLength(file.c_str());
+}
+
+bool ImageIOWizardModel::IsImageLoaded() const
+{
+  // TODO: this may have to change based on validity checks
+  return m_GuidedIO->IsNativeImageLoaded();
+}
+
+void ImageIOWizardModel::Finalize()
+{
+}
+
+
+
diff --git a/GUI/Model/ImageIOWizardModel.h b/GUI/Model/ImageIOWizardModel.h
new file mode 100644
index 0000000..3e04620
--- /dev/null
+++ b/GUI/Model/ImageIOWizardModel.h
@@ -0,0 +1,229 @@
+#ifndef IMAGEIOWIZARDMODEL_H
+#define IMAGEIOWIZARDMODEL_H
+
+#include <string>
+
+#include "AbstractModel.h"
+#include "GuidedNativeImageIO.h"
+#include "Registry.h"
+#include "ImageIODelegates.h"
+
+class GlobalUIModel;
+
+namespace itk {
+  class GDCMSeriesFileNames;
+}
+
+/**
+ This class provides a model for the ImageIO wizards. This allows the wizard
+ to be distanced from the program logic. The wizard is just a collection of
+ buttons and callbacks, but very little state
+
+ This class is subclassed by specific dialogs, to allow customization. For
+ example, save/load dialog behavior is handled this way.
+ */
+class ImageIOWizardModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(ImageIOWizardModel, AbstractModel)
+
+  typedef GuidedNativeImageIO::FileFormat FileFormat;
+  enum Mode { LOAD, SAVE };
+
+  enum SummaryItem {
+    SI_FILENAME, SI_DIMS, SI_SPACING, SI_ORIGIN, SI_ORIENT,
+    SI_ENDIAN, SI_COMPONENTS, SI_DATATYPE, SI_FILESIZE
+  };
+
+  // Initialize the wizard for load operations. Note that the delegate,
+  // which specializes the behavior of this class, is stored internally
+  // using a smart pointer, so its ownership can be relinquished to the
+  // wizard.
+  void InitializeForLoad(GlobalUIModel *parent,
+                         AbstractLoadImageDelegate *delegate,
+                         const char *name, const char *dispName);
+
+  void InitializeForSave(GlobalUIModel *parent,
+                         AbstractSaveImageDelegate *delegate,
+                         const char *dispName);
+
+  irisGetMacro(Parent, GlobalUIModel *)
+  irisGetMacro(GuidedIO, GuidedNativeImageIO *)
+
+  // Does the model support loading
+  bool IsLoadMode() const { return m_Mode == LOAD; }
+
+  // Does the model support loading
+  bool IsSaveMode() const { return m_Mode == SAVE; }
+
+  /** Access the IO delegate used for loading */
+  irisGetMacro(LoadDelegate, AbstractLoadImageDelegate *)
+
+  /** Access the IO delegate used for saving */
+  irisGetMacro(SaveDelegate, AbstractSaveImageDelegate *)
+
+  // Whether we can save or load a file format
+  virtual bool CanHandleFileFormat(FileFormat fmt);
+
+  // This another method that checks if a loaded image is valid
+  virtual bool CheckImageValidity();
+
+  // Default extension for saving files
+  virtual std::string GetDefaultFormatForSave() const
+    { return std::string("NiFTI"); }
+
+  /**
+    Create a filter string for file IO dialogs. The lineEntry is in the
+    printf format, with first %s being the title of the format, and the
+    second being the list of extensions. extEntry is similar, used to print
+    each extension. The examples for Qt are "%s (%s)" for lineEntry and
+    "*.%s" for extEntry. For FLTK it would be "%s *.{%s}" for lineEntry
+    and "%s" for extEntry. The separators are used to separate extensions
+    per entry and rows in the filter string.
+   */
+  std::string GetFilter(const char *lineEntry,
+                        const char *extEntry,
+                        const char *extSeparator,
+                        const char *rowSeparator);
+
+  /**
+    Guess the format for the file. In load mode, if the file does not exist,
+    this will return FORMAT_COUNT, i.e., failure to determine format. If it
+    exists, the format will be determined using registry information (if open
+    before), magic number, and extension, in turn. If in save mode, format
+    is detected using registry and extension only. The last parameter is only
+    considered in Load mode.
+    */
+  FileFormat GuessFileFormat(const std::string &fname, bool &fileExists);
+
+  /** Get the file format from file format name */
+  FileFormat GetFileFormatByName(const std::string &formatName) const;
+
+  /** Get the name of a file format */
+  std::string GetFileFormatName(FileFormat fmt) const;
+
+  /**
+    Get the directory where to browse, given a currently entered file
+    */
+  std::string GetBrowseDirectory(const std::string &file);
+
+  /**
+    Get the size of the file in bytes
+    */
+  unsigned long GetFileSizeInBytes(const std::string &file);
+
+  /**
+    Get the history of filenames
+    */
+  irisGetMacro(HistoryName, std::string)
+
+  /**
+    Get the display name to show in the dialog
+    */
+  std::string GetDisplayName() const;
+
+  /**
+    * Reset the state of the model
+    */
+  void Reset();
+
+  /**
+    Set the format selected by the user
+    */
+  void SetSelectedFormat(FileFormat fmt);
+
+  FileFormat GetSelectedFormat();
+
+  /**
+    Load the image from filename, putting warnings into a warning list. This
+    may also fire an exception (e.g., if validation failed)
+    */
+  void LoadImage(std::string filename);
+
+  /**
+   Save the image to a filename
+   */
+  void SaveImage(std::string filename);
+
+  /**
+    Get the warnings generated by LoadImage
+    */
+  irisGetMacro(Warnings, IRISWarningList)
+
+  /**
+    Whether an image was loaded
+    */
+  bool IsImageLoaded() const;
+
+  /**
+    Get summary items to display for the user
+    */
+  std::string GetSummaryItem(SummaryItem item);
+
+  /**
+    Load relevant information from DICOM directory
+    */
+  void ProcessDicomDirectory(const std::string &filename);
+
+  /**
+    Get the DICOM directory contents
+    */
+  irisGetMacro(DicomContents, const GuidedNativeImageIO::RegistryArray &)
+
+  /**
+    Load n-th series from DICOM directory
+    */
+  void LoadDicomSeries(const std::string &filename, int series);
+
+
+  irisGetSetMacro(SuggestedFilename, std::string)
+
+  /**
+    Access the registry stored in the model and used for providing hints to
+    the image IO.
+    */
+  Registry &GetHints()
+    { return m_Registry; }
+
+  /**
+    Called just before exiting the wizard. Should update history, etc.
+    */
+  virtual void Finalize();
+
+protected:
+
+  // Standard ITK protected constructors
+  ImageIOWizardModel();
+  virtual ~ImageIOWizardModel();
+
+  // State of the model
+  Mode m_Mode;
+
+  // Delegate that does the actual loading or saving
+  SmartPtr<AbstractLoadImageDelegate> m_LoadDelegate;
+
+  // Delegate than handles saving
+  SmartPtr<AbstractSaveImageDelegate> m_SaveDelegate;
+
+  // The history list associated with the model
+  std::string m_HistoryName, m_DisplayName;
+
+  // Parent model
+  GlobalUIModel *m_Parent;
+  SmartPtr<GuidedNativeImageIO> m_GuidedIO;
+
+  // Warnings generated during IO
+  IRISWarningList m_Warnings;
+
+  // Registry containing auxiliary info
+  Registry m_Registry;
+
+  // Suggested filename
+  std::string m_SuggestedFilename;
+
+  // DICOM support
+  GuidedNativeImageIO::RegistryArray m_DicomContents;
+};
+
+#endif // IMAGEIOWIZARDMODEL_H
diff --git a/GUI/Model/ImageInfoModel.cxx b/GUI/Model/ImageInfoModel.cxx
new file mode 100644
index 0000000..5786f06
--- /dev/null
+++ b/GUI/Model/ImageInfoModel.cxx
@@ -0,0 +1,204 @@
+#include "ImageInfoModel.h"
+#include "LayerAssociation.txx"
+#include "MetaDataAccess.h"
+#include <cctype>
+#include <algorithm>
+
+
+// This compiles the LayerAssociation for the color map
+template class LayerAssociation<ImageInfoLayerProperties,
+                                ImageWrapperBase,
+                                ImageInfoModelBase::PropertiesFactory>;
+
+ImageInfoModel::ImageInfoModel()
+{
+  m_ImageDimensionsModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetImageDimensions);
+
+  m_ImageSpacingModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetImageSpacing);
+
+  m_ImageOriginModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetImageOrigin);
+
+  m_ImageItkCoordinatesModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetImageItkCoordinates);
+
+  m_ImageNiftiCoordinatesModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetImageNiftiCoordinates);
+
+  m_ImageMinMaxModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetImageMinMax);
+
+  m_ImageOrientationModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetImageOrientation);
+
+  // Create the property model for the filter
+  m_MetadataFilterModel = ConcreteSimpleStringProperty::New();
+
+  // Listen to events on the filter, so we can update the metadata
+  Rebroadcast(m_MetadataFilterModel, ValueChangedEvent(), MetadataChangeEvent());
+
+  // Also rebroadcast active layer change events as both ModelChange and Metadata
+  // change events
+  Rebroadcast(this, ActiveLayerChangedEvent(), MetadataChangeEvent());
+}
+
+void ImageInfoModel::SetParentModel(GlobalUIModel *parent)
+{
+  Superclass::SetParentModel(parent);
+
+  // Cursor update events are mapped to model update events
+  Rebroadcast(m_ParentModel, CursorUpdateEvent(), ModelUpdateEvent());
+}
+
+bool ImageInfoModel
+::GetImageDimensions(Vector3ui &value)
+{
+  if(!this->GetLayer()) return false;
+  value = GetLayer()->GetSize();
+  return true;
+}
+
+bool ImageInfoModel
+::GetImageOrigin(Vector3d &value)
+{
+  if(!this->GetLayer()) return false;
+  value = GetLayer()->GetImageBase()->GetOrigin();
+  return true;
+}
+
+bool ImageInfoModel
+::GetImageSpacing(Vector3d &value)
+{
+  if(!this->GetLayer()) return false;
+  value = GetLayer()->GetImageBase()->GetSpacing();
+  return true;
+}
+
+bool ImageInfoModel
+::GetImageItkCoordinates(Vector3d &value)
+{
+  if(!this->GetLayer()) return false;
+  Vector3ui cursor = m_ParentModel->GetDriver()->GetCursorPosition();
+  value = GetLayer()->TransformVoxelIndexToPosition(cursor);
+  return true;
+}
+
+bool ImageInfoModel
+::GetImageNiftiCoordinates(Vector3d &value)
+{
+  if(!this->GetLayer()) return false;
+  Vector3ui cursor = m_ParentModel->GetDriver()->GetCursorPosition();
+  value = GetLayer()->TransformVoxelIndexToNIFTICoordinates(to_double(cursor));
+  return true;
+}
+
+bool ImageInfoModel
+::GetImageMinMax(Vector2d &value)
+{
+  ImageWrapperBase *layer = this->GetLayer();
+
+  // TODO: figure out how to handle this conistently throughout
+  if(layer)
+    {
+    value = Vector2d(layer->GetImageMinNative(), layer->GetImageMaxNative());
+    return true;
+    }
+
+  return false;
+}
+
+bool ImageInfoModel
+::GetImageOrientation(std::string &value)
+{
+  if(!this->GetLayer()) return false;
+
+  const ImageCoordinateGeometry &geo =
+      m_ParentModel->GetDriver()->GetCurrentImageData()->GetImageGeometry();
+  ImageCoordinateGeometry::DirectionMatrix dmat =
+      geo.GetImageDirectionCosineMatrix();
+
+  std::string raicode =
+    ImageCoordinateGeometry::ConvertDirectionMatrixToClosestRAICode(dmat);
+
+  if (ImageCoordinateGeometry::IsDirectionMatrixOblique(dmat))
+    value = std::string("Oblique (closest to ") + raicode + string(")");
+  else
+    value = raicode;
+
+  return true;
+}
+
+void ImageInfoModel::OnUpdate()
+{
+  Superclass::OnUpdate();
+
+  // Is there a change to the metadata?
+  if(this->m_EventBucket->HasEvent(ActiveLayerChangedEvent()) ||
+     this->m_EventBucket->HasEvent(ValueChangedEvent(),m_MetadataFilterModel))
+    {
+    // Recompute the metadata index
+    this->UpdateMetadataIndex();
+    }
+}
+
+// #include <itksys/RegularExpression.hxx>
+
+bool case_insensitive_predicate(char a, char b)
+{
+  return std::tolower(a) == std::tolower(b);
+}
+
+bool case_insensitive_find(std::string &a, std::string &b)
+{
+  std::string::iterator it = std::search(
+        a.begin(), a.end(), b.begin(), b.end(), case_insensitive_predicate);
+  return it != a.end();
+}
+
+void ImageInfoModel::UpdateMetadataIndex()
+{
+  // Clear the list of selected keys
+  m_MetadataKeys.clear();
+
+  // Search keys and values that meet the filter
+  if(GetLayer())
+    {
+    MetaDataAccess mda(GetLayer()->GetImageBase());
+    std::vector<std::string> keys = mda.GetKeysAsArray();
+    std::string filter = m_MetadataFilterModel->GetValue();
+    for(size_t i = 0; i < keys.size(); i++)
+      {
+      std::string key = keys[i];
+      std::string dcm = mda.MapKeyToDICOM(key);
+      std::string value = mda.GetValueAsString(key);
+
+      if(filter.size() == 0 ||
+         case_insensitive_find(dcm, filter) ||
+         case_insensitive_find(value, filter))
+        {
+        m_MetadataKeys.push_back(key);
+        }
+      }
+    }
+}
+
+int ImageInfoModel::GetMetadataRows()
+{
+  return m_MetadataKeys.size();
+}
+
+std::string ImageInfoModel::GetMetadataCell(int row, int col)
+{
+  assert(GetLayer());
+  assert(row >= 0 && row < (int) m_MetadataKeys.size());
+  std::string key = m_MetadataKeys[row];
+  MetaDataAccess mda(GetLayer()->GetImageBase());
+
+  return (col == 0) ? mda.MapKeyToDICOM(key) : mda.GetValueAsString(key);
+}
+
+
+
+
diff --git a/GUI/Model/ImageInfoModel.h b/GUI/Model/ImageInfoModel.h
new file mode 100644
index 0000000..5cf3250
--- /dev/null
+++ b/GUI/Model/ImageInfoModel.h
@@ -0,0 +1,97 @@
+#ifndef IMAGEINFOMODEL_H
+#define IMAGEINFOMODEL_H
+
+#include "AbstractLayerAssociatedModel.h"
+#include "PropertyModel.h"
+
+class ImageInfoLayerProperties
+{
+public:
+  irisGetSetMacro(ObserverTag, unsigned long)
+
+  virtual ~ImageInfoLayerProperties() {}
+
+protected:
+
+  // Whether or not we are already listening to events from this layer
+  unsigned long m_ObserverTag;
+};
+
+typedef AbstractLayerAssociatedModel<
+    ImageInfoLayerProperties,
+    ImageWrapperBase> ImageInfoModelBase;
+
+class ImageInfoModel : public ImageInfoModelBase
+{
+public:
+  irisITKObjectMacro(ImageInfoModel, ImageInfoModelBase)
+
+  // An event fired when some aspect of the metadata has changed
+  itkEventMacro(MetadataChangeEvent, IRISEvent)
+  FIRES(MetadataChangeEvent)
+
+  // Implementation of virtual functions from parent class
+  void RegisterWithLayer(ImageWrapperBase *layer) {}
+  void UnRegisterFromLayer(ImageWrapperBase *layer, bool being_deleted) {}
+
+  // Parent model assignment override
+  virtual void SetParentModel(GlobalUIModel *parent);
+
+  // Function called in response to events
+  virtual void OnUpdate();
+
+  // Access the individual models
+  irisGetMacro(ImageDimensionsModel, AbstractSimpleUIntVec3Property *)
+  irisGetMacro(ImageSpacingModel, AbstractSimpleDoubleVec3Property *)
+  irisGetMacro(ImageOriginModel, AbstractSimpleDoubleVec3Property *)
+  irisGetMacro(ImageItkCoordinatesModel, AbstractSimpleDoubleVec3Property *)
+  irisGetMacro(ImageNiftiCoordinatesModel, AbstractSimpleDoubleVec3Property *)
+  irisGetMacro(ImageMinMaxModel, AbstractSimpleDoubleVec2Property *)
+  irisGetMacro(ImageOrientationModel, AbstractSimpleStringProperty *)
+
+  // Access the internally stored filter
+  irisSimplePropertyAccessMacro(MetadataFilter, std::string)
+
+  // The voxel coordinate model just refers to the parent mode
+  AbstractRangedUIntVec3Property *GetImageVoxelCoordinatesModel() const
+  {
+    return m_ParentModel->GetCursorPositionModel();
+  }
+
+
+  /** Number of rows in the metadata table */
+  int GetMetadataRows();
+
+  /** Get and entry in the metadata table */
+  std::string GetMetadataCell(int row, int col);
+
+protected:
+
+  SmartPtr<AbstractSimpleDoubleVec3Property> m_ImageSpacingModel;
+  SmartPtr<AbstractSimpleDoubleVec3Property> m_ImageOriginModel;
+  SmartPtr<AbstractSimpleDoubleVec3Property> m_ImageItkCoordinatesModel;
+  SmartPtr<AbstractSimpleDoubleVec3Property> m_ImageNiftiCoordinatesModel;
+  SmartPtr<AbstractSimpleUIntVec3Property> m_ImageDimensionsModel;
+  SmartPtr<AbstractSimpleDoubleVec2Property> m_ImageMinMaxModel;
+  SmartPtr<AbstractSimpleStringProperty> m_ImageOrientationModel;
+  SmartPtr<ConcreteSimpleStringProperty> m_MetadataFilterModel;
+
+  bool GetImageDimensions(Vector3ui &value);
+  bool GetImageOrigin(Vector3d &value);
+  bool GetImageSpacing(Vector3d &value);
+  bool GetImageItkCoordinates(Vector3d &value);
+  bool GetImageNiftiCoordinates(Vector3d &value);
+  bool GetImageMinMax(Vector2d &value);
+  bool GetImageOrientation(std::string &value);
+
+  // Update the list of keys managed by the metadata
+  void UpdateMetadataIndex();
+
+  // A list of metadata keys obeying the current filter
+  std::vector<std::string> m_MetadataKeys;
+
+  ImageInfoModel();
+  virtual ~ImageInfoModel() {}
+};
+
+#endif // IMAGEINFOMODEL_H
diff --git a/GUI/Model/IntensityCurveModel.cxx b/GUI/Model/IntensityCurveModel.cxx
new file mode 100644
index 0000000..5345c9d
--- /dev/null
+++ b/GUI/Model/IntensityCurveModel.cxx
@@ -0,0 +1,748 @@
+#include "IntensityCurveModel.h"
+#include "ImageWrapperBase.h"
+#include "IRISApplication.h"
+#include "itkImageBase.h"
+#include "ScalarImageHistogram.h"
+#include "GlobalUIModel.h"
+#include "IntensityCurveInterface.h"
+#include "DisplayMappingPolicy.h"
+#include "LayerAssociation.txx"
+
+template class LayerAssociation<IntensityCurveLayerProperties,
+                                ImageWrapperBase,
+                                IntensityCurveModelBase::PropertiesFactory>;
+
+
+IntensityCurveModel::IntensityCurveModel()
+  : IntensityCurveModelBase()
+{
+  // Create the child model for the moving control point id
+  m_MovingControlIdModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetMovingControlPointIdValueAndRange,
+        &Self::SetMovingControlPointId);
+
+  // Create the child model for the control point coordinates
+  m_MovingControlXYModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetMovingControlPointPositionAndRange,
+        &Self::SetMovingControlPointPosition);
+
+  // Min/max/level/window models
+  for(int i = 0; i < 4; i++)
+    m_IntensityRangeModel[i] = wrapIndexedGetterSetterPairAsProperty(
+          this, i,
+          &Self::GetIntensityRangeIndexedValueAndRange,
+          &Self::SetIntensityRangeIndexedValue);
+
+  // Histogram bin size and other controls
+  m_HistogramBinSizeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetHistogramBinSizeValueAndRange,
+        &Self::SetHistogramBinSize);
+
+  m_HistogramCutoffModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetHistogramCutoffValueAndRange,
+        &Self::SetHistogramCutoff);
+
+  m_HistogramScaleModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetHistogramScale,
+        &Self::SetHistogramScale);
+
+  // Model events are also state changes for GUI activation
+  Rebroadcast(this, ModelUpdateEvent(), StateMachineChangeEvent());
+}
+
+
+
+IntensityCurveModel::~IntensityCurveModel()
+{
+
+}
+
+AbstractContinuousImageDisplayMappingPolicy *
+IntensityCurveModel
+::GetDisplayPolicy()
+{
+  ImageWrapperBase *layer = this->GetLayer();
+  if(layer)
+    return dynamic_cast<AbstractContinuousImageDisplayMappingPolicy *>
+        (layer->GetDisplayMapping());
+  return NULL;
+}
+
+void
+IntensityCurveModel
+::RegisterWithLayer(ImageWrapperBase *layer)
+{
+  IntensityCurveLayerProperties &p = GetProperties();
+
+  // Listen to changes in the layer's intensity curve
+  unsigned long tag =
+      Rebroadcast(layer, WrapperDisplayMappingChangeEvent(), ModelUpdateEvent());
+
+  // Set a flag so we don't register a listener again
+  p.SetObserverTag(tag);
+
+  // If this is the first time we are registered with this layer, we are going
+  // to set the histogram cutoff optimally. The user may change this later so
+  // we only do this for the first-time registration.
+  //
+  // TODO: it may make more sense for this to be a property that's associated
+  // with the image for future times that it is loaded. Then the cutoff would
+  // have to be stored in the ImageWrapper.
+  if(p.IsFirstTime())
+    {
+    // Set the cutoff automatically
+    const ScalarImageHistogram *hist = layer->GetHistogram(0);
+    p.SetHistogramCutoff(hist->GetReasonableDisplayCutoff(0.95, 0.6));
+    p.SetFirstTime(false);
+    }
+}
+
+void
+IntensityCurveModel
+::UnRegisterFromLayer(ImageWrapperBase *layer, bool being_deleted)
+{
+  if(!being_deleted)
+    {
+    // It's safe to call GetProperties()
+    unsigned long tag = GetProperties().GetObserverTag();
+    if(tag)
+      {
+      layer->GetDisplayMapping()->RemoveObserver(tag);
+      }
+    }
+}
+
+
+const ScalarImageHistogram *
+IntensityCurveModel
+::GetHistogram()
+{
+  AbstractContinuousImageDisplayMappingPolicy *dmp = this->GetDisplayPolicy();
+  assert(dmp);
+
+  // Get the properties for the layer
+  IntensityCurveLayerProperties *p = m_LayerProperties[m_Layer];
+
+  // Figure out the number of bins that we want
+  unsigned int nBins = DEFAULT_HISTOGRAM_BINS;
+  if(m_ViewportReporter && m_ViewportReporter->CanReportSize())
+    {
+    unsigned int width = m_ViewportReporter->GetViewportSize()[0];
+    nBins = width / p->GetHistogramBinSize();
+    }
+
+  // Get the histogram
+  return dmp->GetHistogram(nBins);
+}
+
+IntensityCurveLayerProperties::IntensityCurveLayerProperties()
+{
+  m_ObserverTag = 0;
+  m_HistogramLog = false;
+  m_MovingControlPoint = false;
+  m_HistogramBinSize = 10;
+  m_HistogramCutoff = 1;
+  m_FirstTime = true;
+}
+
+IntensityCurveLayerProperties::~IntensityCurveLayerProperties()
+{
+}
+
+IntensityCurveInterface * IntensityCurveModel::GetCurve()
+{
+  return (this->GetDisplayPolicy())
+      ? this->GetDisplayPolicy()->GetIntensityCurve()
+      : NULL;
+}
+
+Vector2d IntensityCurveModel::GetNativeImageRangeForCurve()
+{
+  assert(this->GetDisplayPolicy());
+  return this->GetDisplayPolicy()->GetNativeImageRangeForCurve();
+}
+
+Vector2d IntensityCurveModel::GetCurveRange()
+{
+  IntensityCurveInterface *curve = this->GetCurve();
+  assert(curve);
+
+  // Get the control point range
+  float t0, y0, t1, y1;
+  curve->GetControlPoint(0, t0, y0);
+  curve->GetControlPoint(curve->GetControlPointCount() - 1, t1, y1);
+
+  // Get the reference intensity range
+  Vector2d range = this->GetNativeImageRangeForCurve();
+
+  // Map the extents of the control points to image units
+  Vector2d outRange;
+  outRange[0] = range[0] * (1 - t0) + range[1] * t0;
+  outRange[1] = range[0] * (1 - t1) + range[1] * t1;
+  return outRange;
+}
+
+Vector2d IntensityCurveModel::GetVisibleImageRange()
+{
+  IntensityCurveInterface *curve = this->GetCurve();
+  assert(curve);
+
+  // Get the control point range
+  float t0, y0, t1, y1;
+  curve->GetControlPoint(0, t0, y0);
+  curve->GetControlPoint(curve->GetControlPointCount() - 1, t1, y1);
+
+  // Get the reference intensity range
+  Vector2d range = this->GetNativeImageRangeForCurve();
+
+  // Compute the range over which the curve is plotted, where [0 1] is the
+  // image intensity range
+  float z0 = std::min(t0, 0.0f);
+  float z1 = std::max(t1, 1.0f);
+
+  // Compute the range over which the curve is plotted, in intensity units
+  Vector2d outRange;
+  outRange[0] = range[0] * (1 - z0) + range[1] * z0;
+  outRange[1] = range[0] * (1 - z1) + range[1] * z1;
+  return outRange;
+}
+
+bool
+IntensityCurveModel
+::UpdateControlPoint(size_t i, float t, float x)
+{
+  IntensityCurveInterface *curve = this->GetCurve();
+
+  // Must be in range
+  assert(i < curve->GetControlPointCount());
+
+  // Get the current values
+  float told, xold;
+  curve->GetControlPoint(i, told, xold);
+
+  // The control value should be in range
+  // if(t < 0.0 || t > 1.0)
+  //  return false;
+
+  // First and last control points are treated specially because they
+  // provide windowing style behavior
+  int last = curve->GetControlPointCount()-1;
+  if (i == 0 || i == (size_t) last)
+    {
+    // Get the current domain
+    float tMin,tMax,x;
+    curve->GetControlPoint(0,   tMin, x);
+    curve->GetControlPoint(last,tMax, x);
+
+    // Check if the new domain is valid
+    float epsilon = 0.02;
+    if (i == 0 && t < tMax - epsilon)
+      tMin = t;
+    else if (i == (size_t) last && t > tMin + epsilon)
+      tMax = t;
+    else
+      // One of the conditions failed; the window has size <= 0
+      return false;
+
+    // Change the domain of the curve
+    curve->ScaleControlPointsToWindow(tMin, tMax);
+    }
+  else
+    {
+    // Check whether the X coordinate is in range
+    if (x < 0.0 || x > 1.0)
+      return false;
+
+    // Update the control point
+    curve->UpdateControlPoint(i, t, x);
+
+    // Check the curve for monotonicity
+    if(!curve->IsMonotonic())
+      {
+      curve->UpdateControlPoint(i, told, xold);
+      return false;
+      }
+    }
+  return true;
+}
+
+int
+IntensityCurveModel
+::GetControlPointInVicinity(float x, float y, int pixelRadius)
+{
+  assert(m_ViewportReporter && m_ViewportReporter->CanReportSize());
+  Vector2ui vp = m_ViewportReporter->GetViewportSize();
+  IntensityCurveInterface *curve = GetCurve();
+
+  float rx = pixelRadius * 1.0f / vp[0];
+  float ry = pixelRadius * 1.0f / vp[1];
+  float fx = 1.0f / (rx * rx);
+  float fy = 1.0f / (ry * ry);
+
+  float minDistance = 1.0f;
+  int nearestPoint = -1;
+
+  for (unsigned int c=0;c<curve->GetControlPointCount();c++) {
+
+    // Get the next control point
+    float cx,cy;
+    curve->GetControlPoint(c,cx,cy);
+
+    // Check the distance to the control point
+    float d = (cx - x) * (cx - x) * fx + (cy - y) * (cy - y) * fy;
+    if (minDistance >= d) {
+      minDistance = d;
+      nearestPoint = c;
+    }
+  }
+
+  // Negative: return -1
+  return nearestPoint;
+}
+
+Vector3d IntensityCurveModel::GetEventCurveCoordiantes(const Vector3d &x)
+{
+  float t0, t1, xDummy;
+  GetCurve()->GetControlPoint(0, t0, xDummy);
+  GetCurve()->GetControlPoint(
+        GetCurve()->GetControlPointCount() - 1, t1, xDummy);
+  float z0 = std::min(t0, 0.0f);
+  float z1 = std::max(t1, 1.0f);
+
+  // Scale the display so that leftmost point to plot maps to 0, rightmost to 1
+  return Vector3d(x[0] * (z1 - z0) + z0, x[1], x[2]);
+}
+
+
+bool IntensityCurveModel::ProcessMousePressEvent(const Vector3d &x)
+{
+  // Check the control point affected by the event
+  Vector3d xCurve = this->GetEventCurveCoordiantes(x);
+  GetProperties().SetMovingControlPoint(
+      GetControlPointInVicinity(xCurve[0], xCurve[1], 5));
+
+  // SetCursor(m_MovingControlPoint);
+
+  // Clear the dragged flag
+  m_FlagDraggedControlPoint = false;
+
+  return true;
+}
+
+bool IntensityCurveModel::ProcessMouseDragEvent(const Vector3d &x)
+{
+  Vector3d xCurve = this->GetEventCurveCoordiantes(x);
+  if (GetProperties().GetMovingControlPoint() >= 0)
+    {
+    // Update the moving control point
+    if(UpdateControlPoint(GetProperties().GetMovingControlPoint(),
+                           xCurve[0], xCurve[1]))
+      {
+      InvokeEvent(ModelUpdateEvent());
+      }
+
+    // Set the dragged flag
+    m_FlagDraggedControlPoint = true;
+    return true;
+    }
+
+  return false;
+}
+
+bool IntensityCurveModel::ProcessMouseReleaseEvent(const Vector3d &x)
+{
+  Vector3d xCurve = this->GetEventCurveCoordiantes(x);
+  if (GetProperties().GetMovingControlPoint() >= 0)
+    {
+    // Update the moving control point
+    if (UpdateControlPoint(GetProperties().GetMovingControlPoint(),
+                           xCurve[0], xCurve[1]))
+      {
+      InvokeEvent(ModelUpdateEvent());
+      }
+
+    // Set the dragged flag
+    m_FlagDraggedControlPoint = true;
+    return true;
+    }
+  return false;
+}
+
+
+
+bool
+IntensityCurveModel
+::GetMovingControlPointIdValueAndRange(int &value,
+                                       NumericValueRange<int> *range)
+{
+  if(!m_Layer)
+    return false;
+
+  if(range)
+    {
+    range->Minimum = 1;
+    range->Maximum = GetCurve()->GetControlPointCount();
+    range->StepSize = 1;
+    }
+  value = GetProperties().GetMovingControlPoint() + 1;
+  return value >= 1;
+}
+
+void
+IntensityCurveModel
+::SetMovingControlPointId(int value)
+{
+  GetProperties().SetMovingControlPoint(value - 1);
+  InvokeEvent(ModelUpdateEvent());
+}
+
+bool
+IntensityCurveModel
+::GetIntensityRangeIndexedValueAndRange(
+    int index,
+    double &value,
+    NumericValueRange<double> *range)
+{
+  if(!this->GetCurve())
+    return false;
+
+  // Get the range of the curve in image units
+  Vector2d crange = this->GetCurveRange();
+
+  // Level and window
+  switch(index)
+    {
+    case 0 : value = crange[0]; break;
+    case 1 : value = crange[1]; break;
+    case 2 : value = (crange[0] + crange[1]) / 2; break;
+    case 3 : value = (crange[1] - crange[0]); break;
+    }
+
+  // Compute range and step if needed
+  if(range)
+    {
+    // The range for the window and level are basically unlimited. To be safe, we
+    // set it to be two orders of magnitude greater than the largest absolute
+    // value in the image.
+    Vector2d irange = this->GetNativeImageRangeForCurve();
+    double step = pow(10, floor(0.5 + log10(irange[1] - irange[0]) - 3));
+    double order = log10(std::max(fabs(irange[0]), fabs(irange[1])));
+    double maxabsval = pow(10, ceil(order)+2);
+
+    // Set the ranges for each of the four properties
+    switch(index)
+      {
+      case 0 :
+      case 1 :
+      case 2 :
+        range->Minimum = -maxabsval;
+        range->Maximum = maxabsval;
+        break;
+      case 3 :
+        range->Minimum = 0.0;
+        range->Maximum = maxabsval;
+        break;
+      }
+    range->StepSize = step;
+    }
+
+  // Value is valid
+  return true;
+}
+
+void IntensityCurveModel::SetIntensityRangeIndexedValue(int index, double value)
+{
+  // Get the curve
+  IntensityCurveInterface *curve = this->GetCurve();
+
+  // Get the intensity range and curve range in image units
+  Vector2d irange = this->GetNativeImageRangeForCurve();
+  Vector2d crange = this->GetCurveRange();
+
+  // Get the current window and level
+  double win = crange[1] - crange[0];
+  double level = (crange[0] + crange[1]) / 2;
+  double step = pow(10, floor(0.5 + log10(irange[1] - irange[0]) - 3));
+
+  // How we set the output range depends on what property was changed
+  switch(index)
+    {
+    case 0:         // min
+      crange[0] = value;
+      if(crange[0] >= crange[1])
+        crange[1] = crange[0] + step;
+      break;
+    case 1:         // max
+      crange[1] = value;
+      if(crange[1] <= crange[0])
+        crange[0] = crange[1] - step;
+      break;
+    case 2:         // level (mid-range)
+      crange[0] = value - win / 2;
+      crange[1] = value + win / 2;
+      break;
+    case 3:         // window
+      if(value <= 0)
+        value = step;
+      crange[0] = level - value / 2;
+      crange[1] = level + value / 2;
+      break;
+    }
+
+  // Map the range into curve units
+  double t0 = (crange[0] - irange[0]) / (irange[1] - irange[0]);
+  double t1 = (crange[1] - irange[0]) / (irange[1] - irange[0]);
+
+  curve->ScaleControlPointsToWindow(t0, t1);
+}
+
+
+
+bool
+IntensityCurveModel
+::GetMovingControlPointPositionAndRange(
+    Vector2d &pos,
+    NumericValueRange<Vector2d> *range)
+{
+  AbstractContinuousImageDisplayMappingPolicy *dmp = this->GetDisplayPolicy();
+  if(!dmp)
+    return false;
+
+  // If no control point selected, the value is invalid
+  if(GetProperties().GetMovingControlPoint() < 0)
+    return false;
+
+  IntensityCurveInterface *curve = dmp->GetIntensityCurve();
+  int cp = GetProperties().GetMovingControlPoint();
+
+  // Get the absolute range
+  Vector2d iAbsRange = dmp->GetNativeImageRangeForCurve();
+
+  // Compute the position
+  float x, t;
+  curve->GetControlPoint(cp, t, x);
+  double intensity = iAbsRange[0] * (1-t) + iAbsRange[1] * t;
+
+  pos = Vector2d(intensity,x);
+
+  // Compute the range
+  if(range)
+    {
+    float t0, x0, t1, x1;
+
+    double iAbsSpan = iAbsRange[1] - iAbsRange[0];
+
+    double xStep = pow(10, floor(0.5 + log10(iAbsSpan) - 3));
+    double order = log10(std::max(fabs(iAbsRange[0]), fabs(iAbsRange[1])));
+    double maxabsval = pow(10, ceil(order)+2);
+
+    if(cp == 0)
+      {
+      range->Minimum[0] = -maxabsval;
+      }
+    else
+      {
+      curve->GetControlPoint(cp - 1, t0, x0);
+      range->Minimum[0] = iAbsRange[0] + iAbsSpan * t0 + xStep;
+      }
+
+    if(cp == (int)(curve->GetControlPointCount() - 1))
+      {
+      range->Maximum[0] = maxabsval;
+      }
+    else
+      {
+      curve->GetControlPoint(cp + 1, t1, x1);
+      range->Maximum[0] = iAbsRange[0] + iAbsSpan * t1 - xStep;
+      }
+
+    if(cp == 0)
+      {
+      range->Minimum[1] = range->Maximum[1] = 0;
+      }
+    else if(cp == (int)(curve->GetControlPointCount() - 1))
+      {
+      range->Minimum[1] = range->Maximum[1] = 1;
+      }
+    else
+      {
+      range->Minimum[1] = x0 + 0.01;
+      range->Maximum[1] = x1 - 0.01;
+      }
+
+    range->StepSize[0] = xStep;
+    range->StepSize[1] = 0.01;
+    }
+
+  return true;
+}
+
+void IntensityCurveModel::SetMovingControlPointPosition(Vector2d p)
+{
+  AbstractContinuousImageDisplayMappingPolicy *dmp = this->GetDisplayPolicy();
+  assert(dmp);
+
+  IntensityCurveInterface *curve = dmp->GetIntensityCurve();
+  Vector2d iAbsRange = dmp->GetNativeImageRangeForCurve();
+
+  double t = (p[0] - iAbsRange[0]) / (iAbsRange[1] - iAbsRange[0]);
+  curve->UpdateControlPoint(GetProperties().GetMovingControlPoint(), t, p[1]);
+}
+
+
+void
+IntensityCurveModel
+::OnControlPointNumberDecreaseAction()
+{
+  IntensityCurveInterface *curve = this->GetCurve();
+
+  if (curve->GetControlPointCount() > 3)
+    {
+    curve->Initialize(curve->GetControlPointCount() - 1);
+    GetProperties().SetMovingControlPoint(0);
+
+    // m_BoxCurve->GetInteractor()->SetMovingControlPoint(0);
+    // OnWindowLevelChange();
+    InvokeEvent(ModelUpdateEvent());
+    }
+
+  // if (m_Curve->GetControlPointCount() == 3)
+  //  m_BtnCurveLessControlPoint->deactivate();
+}
+
+void
+IntensityCurveModel
+::OnControlPointNumberIncreaseAction()
+{
+  this->GetCurve()->Initialize(this->GetCurve()->GetControlPointCount() + 1);
+  InvokeEvent(ModelUpdateEvent());
+}
+
+void IntensityCurveModel::OnResetCurveAction()
+{
+  this->GetCurve()->Reset();
+  InvokeEvent(ModelUpdateEvent());
+}
+
+void IntensityCurveModel::OnUpdate()
+{
+  Superclass::OnUpdate();
+}
+
+AbstractRangedDoubleProperty *
+IntensityCurveModel::GetIntensityRangeModel(
+    IntensityRangePropertyType index) const
+{
+  return m_IntensityRangeModel[index];
+}
+
+void IntensityCurveModel::OnAutoFitWindow()
+{
+  // There must be a layer
+  AbstractContinuousImageDisplayMappingPolicy *dmp = this->GetDisplayPolicy();
+  assert(dmp);
+
+  // Get the histogram
+  dmp->AutoFitContrast();
+}
+
+bool
+IntensityCurveModel
+::GetHistogramBinSizeValueAndRange(
+    int &value, NumericValueRange<int> *range)
+{
+  if(m_Layer)
+    {
+    value = (int) GetProperties().GetHistogramBinSize();
+    if(range)
+      {
+      range->Minimum = 1;
+      range->Maximum = m_Layer->GetNumberOfVoxels() / 10;
+      range->StepSize = 1;
+      }
+    return true;
+    }
+  return false;
+}
+
+void
+IntensityCurveModel
+::SetHistogramBinSize(int value)
+{
+  assert(m_Layer);
+  GetProperties().SetHistogramBinSize((unsigned int) value);
+  InvokeEvent(ModelUpdateEvent());
+}
+
+bool
+IntensityCurveModel
+::GetHistogramCutoffValueAndRange(
+    double &value, NumericValueRange<double> *range)
+{
+  if(m_Layer)
+    {
+    value = GetProperties().GetHistogramCutoff() * 100.0;
+    if(range)
+      *range = NumericValueRange<double>(0.1, 100, 1);
+    return true;
+    }
+  return false;
+}
+
+void
+IntensityCurveModel
+::SetHistogramCutoff(double value)
+{
+  assert(m_Layer);
+  GetProperties().SetHistogramCutoff(value / 100.0);
+  InvokeEvent(ModelUpdateEvent());
+}
+
+bool
+IntensityCurveModel
+::GetHistogramScale(bool &value)
+{
+  if(m_Layer)
+    {
+    value = GetProperties().IsHistogramLog();
+    return true;
+    }
+  return false;
+}
+
+void
+IntensityCurveModel
+::SetHistogramScale(bool value)
+{
+  assert(m_Layer);
+  GetProperties().SetHistogramLog(value);
+  InvokeEvent(ModelUpdateEvent());
+}
+
+bool IntensityCurveModel::CheckState(IntensityCurveModel::UIState state)
+{
+  // All flags are false if no layer is loaded
+  if(this->GetLayer() == NULL)
+    return false;
+
+  // Otherwise get the properties
+  IntensityCurveLayerProperties &p = this->GetProperties();
+  int cp = p.GetMovingControlPoint();
+
+  switch(state)
+    {
+    case UIF_LAYER_ACTIVE:
+      return true;
+    case UIF_CONTROL_SELECTED:
+      return cp >= 0;
+    }
+  return false;
+}
+
+
+
diff --git a/GUI/Model/IntensityCurveModel.h b/GUI/Model/IntensityCurveModel.h
new file mode 100644
index 0000000..1629285
--- /dev/null
+++ b/GUI/Model/IntensityCurveModel.h
@@ -0,0 +1,242 @@
+#ifndef INTENSITYCURVEMODEL_H
+#define INTENSITYCURVEMODEL_H
+
+#include <AbstractLayerAssociatedModel.h>
+#include <ImageWrapperBase.h>
+#include <UIReporterDelegates.h>
+
+#include "GenericImageData.h"
+#include <LayerAssociation.h>
+
+#include "PropertyModel.h"
+
+class GlobalUIModel;
+class IntensityCurveModel;
+class AbstractContinuousImageDisplayMappingPolicy;
+
+
+/**
+  A set of properties associated with a specific layer
+  */
+class IntensityCurveLayerProperties
+{
+public:
+  /** Desired histogram bin size, in pixels */
+  irisGetSetMacro(HistogramBinSize, unsigned int)
+
+  irisIsMacro(HistogramLog)
+  irisSetMacro(HistogramLog, bool)
+
+  /** How much of the height of the histogram is shown */
+  irisGetSetMacro(HistogramCutoff, double)
+
+  /** The control point currently moving */
+  irisGetSetMacro(MovingControlPoint, int)
+
+  /** Is this the first time we are registered with the layer? */
+  irisIsMacro(FirstTime)
+  irisSetMacro(FirstTime, bool)
+
+  irisGetSetMacro(ObserverTag, unsigned long)
+
+  IntensityCurveLayerProperties();
+  virtual ~IntensityCurveLayerProperties();
+
+
+protected:
+
+  unsigned int m_HistogramBinSize;
+  bool m_HistogramLog;
+  double m_HistogramCutoff;
+
+  int m_MovingControlPoint;
+
+  // Whether or not we have been registered with this layer before.
+  // By default, this is set to true. This flag allows us to perform
+  // some one-off initialization stuff (like set the histogram cutoff)
+  // in RegisterWithLayer
+  bool m_FirstTime;
+
+  // Whether or not we are already listening to events from this layer
+  unsigned long m_ObserverTag;
+};
+
+typedef AbstractLayerAssociatedModel<
+    IntensityCurveLayerProperties,
+    ImageWrapperBase> IntensityCurveModelBase;
+
+/**
+  The intensity curve model is used to interact with the intensity curve in
+  the adjust contrast user interface. The model is associated with a single
+  layer, or no layer at all. There is a one-to-one relationship between the
+  model and the view, and a one-to-many relationship between the model and
+  the image layers. For each layer, the model maintains a properties object
+  of type IntensityCurveLayerProperties.
+
+  To change the layer with which the model is associated, call SetLayer. The
+  model will fire an event, to which the UI should listen, refreshing the UI
+  in response.
+  */
+class IntensityCurveModel : public IntensityCurveModelBase
+{
+public:
+
+  irisITKObjectMacro(IntensityCurveModel, IntensityCurveModelBase)
+
+
+  /** Before using the model, it must be coupled with a size reporter */
+  irisGetSetMacro(ViewportReporter, ViewportSizeReporter *)
+
+  // Implementation of virtual functions from parent class
+  void RegisterWithLayer(ImageWrapperBase *layer);
+  void UnRegisterFromLayer(ImageWrapperBase *layer, bool being_deleted);
+
+
+  /**
+    States in which the model can be, which allow the activation and
+    deactivation of various widgets in the interface
+    */
+  enum UIState {
+    UIF_LAYER_ACTIVE,
+    UIF_CONTROL_SELECTED
+    };
+
+  /**
+    Get the curve stored in the current layer
+    */
+  IntensityCurveInterface *GetCurve();
+
+  /** Get the input intensity range for the curve (native) */
+  Vector2d GetNativeImageRangeForCurve();
+
+  /**
+   * Get the current min and max of the curve in native image units
+   */
+  Vector2d GetCurveRange();
+
+  /**
+   * Get the visibile intensity range (in native image intensity units).
+   * The lower bound of this range is the minimum of the first control point's
+   * intensity and the minimum of the image intensity. The upper bound is the
+   * maximum of the last control point's intensity and the maximum image value.
+   */
+  Vector2d GetVisibleImageRange();
+
+  /**
+    Check the state flags above
+    */
+  bool CheckState(UIState state);
+
+  /**
+    Get the histogram of the current layer
+    */
+  const ScalarImageHistogram *GetHistogram();
+
+  /**
+    Process curve interaction event
+    */
+  bool ProcessMousePressEvent(const Vector3d &x);
+  bool ProcessMouseDragEvent(const Vector3d &x);
+  bool ProcessMouseReleaseEvent(const Vector3d &x);
+
+  /** Reduce number of control points */
+  void OnControlPointNumberDecreaseAction();
+
+  /** Increase number of control points */
+  void OnControlPointNumberIncreaseAction();
+
+  /** Reset the curve */
+  void OnResetCurveAction();
+
+  /** Try changing the control point to new values */
+  bool UpdateControlPoint(size_t i, float t, float x);
+
+
+  /** Update the model in response to upstream events */
+  virtual void OnUpdate();
+
+  // Access the models
+  irisGetMacro(MovingControlXYModel, AbstractRangedDoubleVec2Property *)
+  irisGetMacro(MovingControlIdModel, AbstractRangedIntProperty *)
+  irisGetMacro(HistogramBinSizeModel, AbstractRangedIntProperty *)
+  irisGetMacro(HistogramCutoffModel, AbstractRangedDoubleProperty *)
+  irisGetMacro(HistogramScaleModel, AbstractSimpleBooleanProperty *)
+
+  // This enum lists the types of global intensity range properties for which
+  // separate models are defined
+  enum IntensityRangePropertyType { MINIMUM = 0, MAXIMUM, LEVEL, WINDOW };
+
+  // Access the models for the intensity min, max, level and window. These
+  // models are specified by an index
+  AbstractRangedDoubleProperty *GetIntensityRangeModel(
+      IntensityRangePropertyType index) const;
+
+  void OnAutoFitWindow();
+protected:
+
+  IntensityCurveModel();
+  virtual ~IntensityCurveModel();
+
+  AbstractContinuousImageDisplayMappingPolicy *GetDisplayPolicy();
+
+  // A size reporter delegate
+  ViewportSizeReporter *m_ViewportReporter;
+
+  // Whether the control point is being dragged
+  bool m_FlagDraggedControlPoint;
+
+
+  Vector3d GetEventCurveCoordiantes(const Vector3d &x);
+  int GetControlPointInVicinity(float x, float y, int pixelRadius);
+
+  // Model for the control point index
+  SmartPtr<AbstractRangedIntProperty> m_MovingControlIdModel;
+
+  // Moving control point Id access methods
+  bool GetMovingControlPointIdValueAndRange(int &value,
+                                            NumericValueRange<int> *range);
+  void SetMovingControlPointId(int value);
+
+  // The child models for control point X and Y coordinates
+  SmartPtr<AbstractRangedDoubleVec2Property> m_MovingControlXYModel;
+
+  // Moving control point position access methods
+  bool GetMovingControlPointPositionAndRange(Vector2d &lw,
+                                             NumericValueRange<Vector2d> *range);
+  void SetMovingControlPointPosition(Vector2d p);
+
+  // Child models for min, max, window and level
+  SmartPtr<AbstractRangedDoubleProperty> m_IntensityRangeModel[4];
+
+  // Window and level access methods
+  bool GetIntensityRangeIndexedValueAndRange(int index,
+                                      double &value,
+                                      NumericValueRange<double> *range);
+  void SetIntensityRangeIndexedValue(int index, double value);
+
+  // Child model for histogram bin size
+  SmartPtr<AbstractRangedIntProperty> m_HistogramBinSizeModel;
+
+  // Histogram bin size access methods
+  bool GetHistogramBinSizeValueAndRange(int &value,
+                                        NumericValueRange<int> *range);
+  void SetHistogramBinSize(int value);
+
+  // Child model for histogram cutoff
+  SmartPtr<AbstractRangedDoubleProperty> m_HistogramCutoffModel;
+
+  // Histogram bin size access methods
+  bool GetHistogramCutoffValueAndRange(double &value,
+                                       NumericValueRange<double> *range);
+  void SetHistogramCutoff(double value);
+
+  // Child model for histogram scale
+  SmartPtr<AbstractSimpleBooleanProperty> m_HistogramScaleModel;
+
+  // Histogram bin size access methods
+  bool GetHistogramScale(bool &value);
+  void SetHistogramScale(bool value);
+
+};
+
+#endif // INTENSITYCURVEMODEL_H
diff --git a/GUI/Model/LabelEditorModel.cxx b/GUI/Model/LabelEditorModel.cxx
new file mode 100644
index 0000000..8cae938
--- /dev/null
+++ b/GUI/Model/LabelEditorModel.cxx
@@ -0,0 +1,374 @@
+#include "LabelEditorModel.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "IRISException.h"
+
+LabelEditorModel::LabelEditorModel()
+{
+  // Create a new instance of the model
+  m_CurrentLabelModel = ConcreteColorLabelPropertyModel::New();
+
+  // When the value in the model changes, we need to rebroadcast this
+  // as a change in the model, so the GUI can update itself
+  Rebroadcast(m_CurrentLabelModel, ValueChangedEvent(), ModelUpdateEvent());
+
+  // The model update events should also be rebroadcast as state changes
+  Rebroadcast(this, ModelUpdateEvent(), StateMachineChangeEvent());
+
+  // Initialize the wrapper models
+
+  m_CurrentLabelDescriptionModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetCurrentLabelDescription,
+        &Self::SetCurrentLabelDescription);
+
+  m_CurrentLabelIdModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetCurrentLabelIdValueAndRange,
+        &Self::SetCurrentLabelId);
+
+  m_CurrentLabelOpacityModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetCurrentLabelOpacityValueAndRange,
+        &Self::SetCurrentLabelOpacity);
+
+  m_CurrentLabelHiddenStateModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetCurrentLabelHiddenState,
+        &Self::SetCurrentLabelHiddenState);
+
+  m_CurrentLabelColorModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetCurrentLabelColor,
+        &Self::SetCurrentLabelColor);
+
+  m_IsForegroundBackgroundModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetIsForegroundBackground,
+        &Self::SetIsForegroundBackground);
+}
+
+void LabelEditorModel::SetParentModel(GlobalUIModel *parent)
+{
+  // Set the parent model
+  m_Parent = parent;
+  m_LabelTable = parent->GetDriver()->GetColorLabelTable();
+
+  // Stick the color label information into the domain object
+  m_CurrentLabelModel->Initialize(m_LabelTable);
+  m_CurrentLabelModel->SetValue(
+        parent->GetDriver()->GetGlobalState()->GetDrawingColorLabel());
+
+  // Listen to events
+  Rebroadcast(m_LabelTable, SegmentationLabelChangeEvent(), ModelUpdateEvent());
+
+  // Listen to changes in the active label event
+  m_IsForegroundBackgroundModel->RebroadcastFromSourceProperty(
+        m_Parent->GetGlobalState()->GetDrawingColorLabelModel());
+
+  m_IsForegroundBackgroundModel->RebroadcastFromSourceProperty(
+        m_Parent->GetGlobalState()->GetDrawOverFilterModel());
+}
+
+bool LabelEditorModel::GetCurrentLabelDescription(std::string &value)
+{
+  if(GetAndStoreCurrentLabel())
+    {
+    value = m_SelectedColorLabel.GetLabel();
+    return true;
+    }
+  return false;
+}
+
+void LabelEditorModel::SetCurrentLabelDescription(std::string value)
+{
+  if(GetAndStoreCurrentLabel())
+    {
+    m_SelectedColorLabel.SetLabel(value.c_str());
+    m_LabelTable->SetColorLabel(m_SelectedId, m_SelectedColorLabel);
+    }
+}
+
+bool LabelEditorModel::GetCurrentLabelIdValueAndRange(
+    int &value, NumericValueRange<int> *domain)
+{
+  // Get the numeric ID of the current label
+  if(GetAndStoreCurrentLabel())
+    {
+    value = m_SelectedId;
+    if(domain)
+      domain->Set(0, MAX_COLOR_LABELS, 1);
+    return true;
+    }
+  return false;
+}
+
+void LabelEditorModel::SetCurrentLabelId(int value)
+{
+  // This actually requires some funky stuff. Save it for later.
+}
+
+bool LabelEditorModel::GetCurrentLabelOpacityValueAndRange(
+    int &value, NumericValueRange<int> *domain)
+{
+  if(GetAndStoreCurrentLabel())
+    {
+    value = m_SelectedColorLabel.GetAlpha();
+    if(domain)
+      domain->Set(0, 255, 1);
+    return true;
+    }
+  return false;
+}
+
+void LabelEditorModel::SetCurrentLabelOpacity(int value)
+{
+  if(GetAndStoreCurrentLabel())
+    {
+    m_SelectedColorLabel.SetAlpha((unsigned char)(value));
+    m_LabelTable->SetColorLabel(m_SelectedId, m_SelectedColorLabel);
+    }
+}
+
+bool LabelEditorModel::GetCurrentLabelHiddenState(iris_vector_fixed<bool, 2> &value)
+{
+  if(GetAndStoreCurrentLabel())
+    {
+    value[0] = !m_SelectedColorLabel.IsVisible();
+    value[1] = !m_SelectedColorLabel.IsVisibleIn3D();
+    return true;
+    }
+  return false;
+}
+
+void LabelEditorModel::SetCurrentLabelHiddenState(iris_vector_fixed<bool, 2> value)
+{
+  if(GetAndStoreCurrentLabel())
+    {
+    m_SelectedColorLabel.SetVisible(!value[0]);
+    m_SelectedColorLabel.SetVisibleIn3D(!value[1]);
+    m_LabelTable->SetColorLabel(m_SelectedId, m_SelectedColorLabel);
+    }
+}
+
+bool LabelEditorModel::GetCurrentLabelColor(Vector3ui &value)
+{
+  if(GetAndStoreCurrentLabel())
+    {
+    value[0] = m_SelectedColorLabel.GetRGB(0);
+    value[1] = m_SelectedColorLabel.GetRGB(1);
+    value[2] = m_SelectedColorLabel.GetRGB(2);
+    return true;
+    }
+  return false;
+}
+
+void LabelEditorModel::SetCurrentLabelColor(Vector3ui value)
+{
+  if(GetAndStoreCurrentLabel())
+    {
+    m_SelectedColorLabel.SetRGB((unsigned char) value[0],
+                                (unsigned char) value[1],
+                                (unsigned char) value[2]);
+    m_LabelTable->SetColorLabel(m_SelectedId, m_SelectedColorLabel);
+    }
+}
+
+bool LabelEditorModel::GetIsForegroundBackground(Vector2b &value)
+{
+  if(GetAndStoreCurrentLabel())
+    {
+    LabelType fg = m_Parent->GetGlobalState()->GetDrawingColorLabel();
+    DrawOverFilter bg = m_Parent->GetGlobalState()->GetDrawOverFilter();
+
+    value[0] = (fg == m_SelectedId);
+    value[1] = (bg.CoverageMode == PAINT_OVER_ONE && bg.DrawOverLabel == m_SelectedId);
+    return true;
+    }
+  return false;
+}
+
+void LabelEditorModel::SetIsForegroundBackground(Vector2b value)
+{
+  GlobalState *gs = m_Parent->GetGlobalState();
+  if(GetAndStoreCurrentLabel())
+    {
+    DrawOverFilter bg = gs->GetDrawOverFilter();
+
+    if(value[0])
+      {
+      gs->SetDrawingColorLabel(m_SelectedId);
+      }
+    else
+      {
+      // Do nothing - there is no default label to switch to...
+      }
+
+    if(value[1])
+      {
+      bg.CoverageMode = PAINT_OVER_ONE;
+      bg.DrawOverLabel = m_SelectedId;
+      gs->SetDrawOverFilter(bg);
+      }
+    else
+      {
+      bg.CoverageMode = PAINT_OVER_ALL;
+      bg.DrawOverLabel = 0;
+      gs->SetDrawOverFilter(bg);
+      }
+    }
+}
+
+
+
+bool LabelEditorModel::GetAndStoreCurrentLabel()
+{
+  m_SelectedId = m_CurrentLabelModel->GetValue();
+  if(m_LabelTable->IsColorLabelValid(m_SelectedId))
+    {
+    m_SelectedColorLabel = m_LabelTable->GetColorLabel(m_SelectedId);
+    return true;
+    }
+  return false;
+}
+
+bool LabelEditorModel::CheckState(LabelEditorModel::UIState state)
+{
+  bool valid = GetAndStoreCurrentLabel();
+  switch(state)
+    {
+    case UIF_EDITABLE_LABEL_SELECTED:
+      return valid && m_SelectedId > 0;
+    }
+  return true;
+}
+
+bool LabelEditorModel::MakeNewLabel(bool copyCurrent)
+{
+  bool valid = GetAndStoreCurrentLabel();
+  if(valid)
+    {
+    // Find the next insertion spot after the current selection
+    LabelType insertpos = m_LabelTable->GetInsertionSpot(m_SelectedId);
+
+    // If the insertion spot returned is zero, throw an exception (no room)
+    if(insertpos == 0)
+      return false;
+
+    // Create a new label at this position and set the selection to it
+    m_LabelTable->SetColorLabelValid(insertpos, true);
+
+    // Duplicate current label if needed
+    if(copyCurrent)
+      {
+      // Append ' copy' to the text of the color label
+      std::string title = m_SelectedColorLabel.GetLabel();
+      if(title.substr(title.size() - 5) != " copy")
+        title += " copy";
+      m_SelectedColorLabel.SetLabel(title.c_str());
+      m_LabelTable->SetColorLabel(insertpos, m_SelectedColorLabel);
+      }
+
+    // Select the new label
+    m_CurrentLabelModel->SetValue(insertpos);
+
+    return true;
+    }
+  return false;
+}
+
+bool LabelEditorModel::IsLabelDeletionDestructive()
+{
+  if(GetAndStoreCurrentLabel())
+    return m_Parent->GetDriver()->GetNumberOfVoxelsWithLabel(m_SelectedId) > 0;
+  else
+    return false;
+}
+
+void LabelEditorModel::DeleteCurrentLabel()
+{
+  if(GetAndStoreCurrentLabel() && m_SelectedId > 0)
+    {
+    // Get the global state
+    GlobalState *gs = m_Parent->GetGlobalState();
+
+    // Compute the next available id that will be selected
+    LabelType lnext = m_LabelTable->FindNextValidLabel(m_SelectedId, false);
+
+    // Check if the drawing labe is pointing to the current id
+    if(gs->GetDrawingColorLabel() == m_SelectedId)
+      gs->SetDrawingColorLabel(lnext);
+
+    // Check for the draw over label as well. Here we use 0 as the replacement
+    DrawOverFilter dof = gs->GetDrawOverFilter();
+    if(dof.DrawOverLabel == m_SelectedId)
+      gs->SetDrawOverFilter(DrawOverFilter(dof.CoverageMode, 0));
+
+    // Replace all the voxels with the current label by zero
+    size_t nUpdated = m_Parent->GetDriver()->ReplaceLabel(0, m_SelectedId);
+
+    // If some voxels were removed, reset the undo state, because
+    // changes to the label metadata are not undoable operations (not yet)
+    if(nUpdated > 0)
+      {
+      // This operation can not be undone!
+      m_Parent->GetDriver()->ClearUndoPoints();
+      }
+
+    // Change the current selection
+    m_CurrentLabelModel->SetValue(lnext);
+
+    // Invalidate the current label
+    m_LabelTable->SetColorLabelValid(m_SelectedId, false);
+    }
+}
+
+void LabelEditorModel::ResetLabels()
+{
+  m_LabelTable->InitializeToDefaults();
+}
+
+bool LabelEditorModel::ReassignLabelId(LabelType newid)
+{
+  // Check if the ID is taken
+  if(m_LabelTable->IsColorLabelValid(newid))
+    return false;
+
+  // Do the relabeling
+  if(GetAndStoreCurrentLabel() && m_SelectedId > 0)
+    {
+    // Get the global state
+    GlobalState *gs = m_Parent->GetGlobalState();
+
+    // Create a new valid label and copy current label
+    m_LabelTable->SetColorLabelValid(newid, true);
+    m_LabelTable->SetColorLabel(newid, m_SelectedColorLabel);
+
+    // Check if the drawing label is pointing to the current id
+    if(gs->GetDrawingColorLabel() == m_SelectedId)
+      gs->SetDrawingColorLabel(newid);
+
+    // Check for the draw over label as well. Here we use 0 as the replacement
+    DrawOverFilter dof = gs->GetDrawOverFilter();
+    if(dof.DrawOverLabel == m_SelectedId)
+      gs->SetDrawOverFilter(DrawOverFilter(dof.CoverageMode, newid));
+
+    // Reassign the ID
+    size_t nUpdated = m_Parent->GetDriver()->ReplaceLabel(newid, m_SelectedId);
+
+    // There is no undo for this
+    if(nUpdated > 0)
+      {
+      // This operation can not be undone!
+      m_Parent->GetDriver()->ClearUndoPoints();
+      }
+
+    // Delete the old label
+    m_LabelTable->SetColorLabelValid(m_SelectedId, false);
+
+    // Select the new label
+    m_CurrentLabelModel->SetValue(newid);
+    }
+
+  return true;
+}
diff --git a/GUI/Model/LabelEditorModel.h b/GUI/Model/LabelEditorModel.h
new file mode 100644
index 0000000..6433518
--- /dev/null
+++ b/GUI/Model/LabelEditorModel.h
@@ -0,0 +1,126 @@
+#ifndef LABELEDITORMODEL_H
+#define LABELEDITORMODEL_H
+
+#include <AbstractModel.h>
+#include <PropertyModel.h>
+#include <ColorLabel.h>
+#include <ColorLabelTable.h>
+#include <GlobalUIModel.h>
+#include <ColorLabelPropertyModel.h>
+
+class LabelEditorModel : public AbstractModel
+{
+public:
+
+  // Standard ITK stuff
+  irisITKObjectMacro(LabelEditorModel, AbstractModel)
+
+  /** Initialize with the parent model */
+  void SetParentModel(GlobalUIModel *parent);
+
+  /** Get the model describing the current selected label (and its domain) */
+  irisGetMacro(CurrentLabelModel, ConcreteColorLabelPropertyModel *)
+
+  /** Get the model for the current label description */
+  irisGetMacro(CurrentLabelDescriptionModel, AbstractSimpleStringProperty *)
+
+  /** Get the model for the current label id */
+  irisGetMacro(CurrentLabelIdModel, AbstractRangedIntProperty *)
+
+  /** Get the model for the current label id */
+  irisGetMacro(CurrentLabelOpacityModel, AbstractRangedIntProperty *)
+
+  /** Get the model for the current label id */
+  irisGetMacro(CurrentLabelHiddenStateModel, AbstractSimpleBooleanVec2Property *)
+
+  /** Get the model for the current label id */
+  irisGetMacro(CurrentLabelColorModel, AbstractSimpleUIntVec3Property *)
+
+  /** Get the model that specifies whether the current label is background or
+   * foreground label */
+  irisGetMacro(IsForegroundBackgroundModel, AbstractSimpleBooleanVec2Property *)
+
+  /** Change the label id of the selected label */
+  bool ReassignLabelId(LabelType newid);
+
+  /**
+    States in which the model can be, which allow the activation and
+    deactivation of various widgets in the interface
+    */
+  enum UIState {
+    UIF_EDITABLE_LABEL_SELECTED
+  };
+
+  /**
+    Check the state flags above
+    */
+  bool CheckState(UIState state);
+
+  /** Create a new label */
+  bool MakeNewLabel(bool copyCurrent);
+
+  /** Will deleting the current label affect the segmentation? */
+  bool IsLabelDeletionDestructive();
+
+  /** Delete the selected label */
+  void DeleteCurrentLabel();
+
+  /** Reset labels to defaults */
+  void ResetLabels();
+
+protected:
+
+  // Hidden constructor/destructor
+  LabelEditorModel();
+  virtual ~LabelEditorModel() {}
+
+  // Helper method to retrieve current color label from the table
+  bool GetAndStoreCurrentLabel();
+
+  // Id of the current label
+  SmartPtr<AbstractRangedIntProperty> m_CurrentLabelIdModel;
+  bool GetCurrentLabelIdValueAndRange(
+      int &value, NumericValueRange<int> *domain);
+  void SetCurrentLabelId(int value);
+
+  // Opacity of the current label
+  SmartPtr<AbstractRangedIntProperty> m_CurrentLabelOpacityModel;
+  bool GetCurrentLabelOpacityValueAndRange(
+      int &value, NumericValueRange<int> *domain);
+  void SetCurrentLabelOpacity(int value);
+
+  // Description of the current label
+  SmartPtr<AbstractSimpleStringProperty> m_CurrentLabelDescriptionModel;
+  bool GetCurrentLabelDescription(std::string &value);
+  void SetCurrentLabelDescription(std::string value);
+
+  // Visibility of the current label
+  SmartPtr<AbstractSimpleBooleanVec2Property> m_CurrentLabelHiddenStateModel;
+  bool GetCurrentLabelHiddenState(iris_vector_fixed<bool, 2> &value);
+  void SetCurrentLabelHiddenState(iris_vector_fixed<bool, 2> value);
+
+  // Color of the current label
+  SmartPtr<AbstractSimpleUIntVec3Property> m_CurrentLabelColorModel;
+  bool GetCurrentLabelColor(Vector3ui &value);
+  void SetCurrentLabelColor(Vector3ui value);
+
+  // Foreground/background status
+  SmartPtr<AbstractSimpleBooleanVec2Property> m_IsForegroundBackgroundModel;
+  bool GetIsForegroundBackground(Vector2b &value);
+  void SetIsForegroundBackground(Vector2b value);
+
+  // The parent model
+  GlobalUIModel *m_Parent;
+
+  // A pointer to the color label table
+  ColorLabelTable *m_LabelTable;
+
+  // The label that is currently selected
+  SmartPtr<ConcreteColorLabelPropertyModel> m_CurrentLabelModel;
+
+  // The information about the current label (temporarily valid)
+  ColorLabel m_SelectedColorLabel;
+  LabelType m_SelectedId;
+};
+
+#endif // LABELEDITORMODEL_H
diff --git a/GUI/Model/LayerGeneralPropertiesModel.cxx b/GUI/Model/LayerGeneralPropertiesModel.cxx
new file mode 100644
index 0000000..cf8ea7c
--- /dev/null
+++ b/GUI/Model/LayerGeneralPropertiesModel.cxx
@@ -0,0 +1,357 @@
+#include "LayerGeneralPropertiesModel.h"
+#include "DisplayMappingPolicy.h"
+#include "LayerAssociation.txx"
+#include "NumericPropertyToggleAdaptor.h"
+#include "LayerTableRowModel.h"
+
+template class LayerAssociation<GeneralLayerProperties,
+                                ImageWrapperBase,
+                                LayerGeneralPropertiesModel::PropertiesFactory>;
+
+
+LayerGeneralPropertiesModel::LayerGeneralPropertiesModel()
+{
+  // Create the derived models
+  m_DisplayModeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetDisplayModeValueAndRange,
+        &Self::SetDisplayModeValue);
+
+  m_SelectedComponentModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetSelectedComponentValueAndRange,
+        &Self::SetSelectedComponentValue);
+
+  m_AnimateModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetAnimateValue,
+        &Self::SetAnimateValue);
+
+  m_LayerOpacityModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetLayerOpacityValueAndRange,
+        &Self::SetLayerOpacityValue);
+
+  m_LayerVisibilityModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetLayerVisibilityValue,
+        &Self::SetLayerVisibilityValue);
+
+  m_FilenameModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetFilenameValue);
+
+  m_NicknameModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetNicknameValue,
+        &Self::SetNicknameValue);
+
+}
+
+LayerGeneralPropertiesModel::~LayerGeneralPropertiesModel()
+{
+
+}
+
+
+void
+LayerGeneralPropertiesModel::SetParentModel(GlobalUIModel *parent)
+{
+  Superclass::SetParentModel(parent);
+
+  this->Rebroadcast(
+        parent->GetDriver(),
+        WrapperMetadataChangeEvent(), ModelUpdateEvent());
+
+  this->Rebroadcast(
+        parent->GetDriver(),
+        WrapperDisplayMappingChangeEvent(), ModelUpdateEvent());
+
+  this->Rebroadcast(
+        parent->GetDriver(),
+        MainImageDimensionsChangeEvent(), ModelUpdateEvent());
+
+  this->Rebroadcast(this, ModelUpdateEvent(), StateMachineChangeEvent());
+}
+
+void
+LayerGeneralPropertiesModel::RegisterWithLayer(ImageWrapperBase *layer)
+{
+  // Listen to changes in the layer's intensity curve
+  // TODO: maybe we need better event granularity here? This event will fire when
+  // the intensity curve or colormap is changed too
+  unsigned long tag =
+      Rebroadcast(layer->GetDisplayMapping(),
+                  itk::ModifiedEvent(), ModelUpdateEvent());
+
+  // Set a flag so we don't register a listener again
+  GetProperties().SetObserverTag(tag);  
+}
+
+void
+LayerGeneralPropertiesModel::UnRegisterFromLayer(ImageWrapperBase *layer, bool being_deleted)
+{
+  if(!being_deleted)
+    {
+    // It's safe to call GetProperties()
+    unsigned long tag = GetProperties().GetObserverTag();
+    if(tag)
+      {
+      layer->GetDisplayMapping()->RemoveObserver(tag);
+      }
+    }
+}
+
+void
+LayerGeneralPropertiesModel::OnUpdate()
+{
+  Superclass::OnUpdate();
+
+  // Do we need this method?
+}
+
+bool LayerGeneralPropertiesModel::CheckState(LayerGeneralPropertiesModel::UIState state)
+{
+  if(!m_Layer)
+    return false;
+
+  switch(state)
+    {
+    case UIF_CAN_SWITCH_COMPONENTS:
+      {
+        AbstractMultiChannelDisplayMappingPolicy *dp =
+            dynamic_cast<AbstractMultiChannelDisplayMappingPolicy *>(
+              m_Layer->GetDisplayMapping());
+        return dp && dp->GetDisplayMode().SelectedScalarRep == SCALAR_REP_COMPONENT;
+      }
+    case UIF_MULTICOMPONENT:
+      return m_Layer->GetNumberOfComponents() > 1;
+    }
+
+  return false;
+}
+
+bool LayerGeneralPropertiesModel
+::GetDisplayModeValueAndRange(DisplayMode &value, DisplayModeDomain *domain)
+{
+  VectorImageWrapperBase *layer = this->GetLayerAsVector();
+  if(!layer)
+    return false;
+
+  // Get the current display mode
+  MultiChannelDisplayMode mode = GetMultiChannelDisplayPolicy()->GetDisplayMode();
+  if(mode.UseRGB)
+    {
+    value = MODE_RGB;
+    }
+  else
+    {
+    switch(mode.SelectedScalarRep)
+      {
+      case SCALAR_REP_MAGNITUDE:
+        value = MODE_MAGNITUDE; break;
+      case SCALAR_REP_MAX:
+        value = MODE_MAX; break;
+      case SCALAR_REP_AVERAGE:
+        value = MODE_AVERAGE; break;
+      case SCALAR_REP_COMPONENT:
+        value = MODE_COMPONENT; break;
+      default:
+        return false;
+      }
+    }
+
+  // Fill out the domain
+  if(domain)
+    {
+    (*domain)[MODE_COMPONENT] = "Single Component";
+    (*domain)[MODE_MAGNITUDE] = "Magnitude of Components";
+    (*domain)[MODE_MAX] = "Maximum Component";
+    (*domain)[MODE_AVERAGE] = "Average of Components";
+
+    // RGB is available only if there are three components
+    if(layer->GetNumberOfComponents() == 3)
+      (*domain)[MODE_RGB] = "RGB Display";
+    }
+
+  return true;
+}
+
+void LayerGeneralPropertiesModel
+::SetDisplayModeValue(DisplayMode value)
+{
+  assert(this->GetLayerAsVector());
+
+  // Get the current display mode
+  MultiChannelDisplayMode mode = GetMultiChannelDisplayPolicy()->GetDisplayMode();
+
+  // Update the current display mode
+  switch(value)
+    {
+    case LayerGeneralPropertiesModel::MODE_COMPONENT:
+      mode.SelectedScalarRep = SCALAR_REP_COMPONENT;
+      mode.UseRGB = false;
+      break;
+    case LayerGeneralPropertiesModel::MODE_MAGNITUDE:
+      mode.SelectedScalarRep = SCALAR_REP_MAGNITUDE;
+      mode.SelectedComponent = 0;
+      mode.UseRGB = false;
+      break;
+    case LayerGeneralPropertiesModel::MODE_MAX:
+      mode.SelectedScalarRep = SCALAR_REP_MAX;
+      mode.SelectedComponent = 0;
+      mode.UseRGB = false;
+      break;
+    case LayerGeneralPropertiesModel::MODE_AVERAGE:
+      mode.SelectedScalarRep = SCALAR_REP_AVERAGE;
+      mode.SelectedComponent = 0;
+      mode.UseRGB = false;
+      break;
+    case LayerGeneralPropertiesModel::MODE_RGB:
+      mode.UseRGB = true;
+      mode.SelectedScalarRep = SCALAR_REP_COMPONENT;
+      mode.SelectedComponent = 0;
+      break;
+    }
+
+  GetMultiChannelDisplayPolicy()->SetDisplayMode(mode);
+}
+
+bool LayerGeneralPropertiesModel
+::GetSelectedComponentValueAndRange(int &value, NumericValueRange<int> *domain)
+{
+  VectorImageWrapperBase *layer = this->GetLayerAsVector();
+  if(!layer)
+    return false;
+
+  // Get the current display mode
+  MultiChannelDisplayMode mode = GetMultiChannelDisplayPolicy()->GetDisplayMode();
+
+  // Mode must be single component
+  if(mode.UseRGB ||
+     mode.SelectedScalarRep != SCALAR_REP_COMPONENT)
+    return false;
+
+  // Use 1-based indexing
+  value = mode.SelectedComponent + 1;
+
+  if(domain)
+    {
+    domain->Set(1, layer->GetNumberOfComponents(), 1);
+    }
+
+  return true;
+}
+
+void LayerGeneralPropertiesModel
+::SetSelectedComponentValue(int value)
+{
+  assert(this->GetLayerAsVector());
+
+  // Get the current display mode
+  MultiChannelDisplayMode mode = GetMultiChannelDisplayPolicy()->GetDisplayMode();
+  mode.SelectedComponent = value - 1;
+  GetMultiChannelDisplayPolicy()->SetDisplayMode(mode);
+}
+
+bool LayerGeneralPropertiesModel
+::GetAnimateValue(bool &value)
+{
+  if(!this->GetLayerAsVector())
+    return false;
+
+  // Get the current display mode
+  MultiChannelDisplayMode mode = GetMultiChannelDisplayPolicy()->GetDisplayMode();
+
+  // Animation is only possible when showing components
+  if(mode.UseRGB ||
+     mode.SelectedScalarRep != SCALAR_REP_COMPONENT)
+    return false;
+
+  value = GetMultiChannelDisplayPolicy()->GetAnimate();
+  return true;
+}
+
+void LayerGeneralPropertiesModel
+::SetAnimateValue(bool value)
+{
+  assert(this->GetLayerAsVector());
+
+  // Get the current display mode
+  GetMultiChannelDisplayPolicy()->SetAnimate(value);
+}
+
+bool LayerGeneralPropertiesModel
+::GetLayerOpacityValueAndRange(int &value, NumericValueRange<int> *domain)
+{
+  LayerTableRowModel *trm = GetSelectedLayerTableRowModel();
+  return trm ? trm->GetLayerOpacityModel()->GetValueAndDomain(value, domain) : false;
+}
+
+void LayerGeneralPropertiesModel::SetLayerOpacityValue(int value)
+{
+  LayerTableRowModel *trm = GetSelectedLayerTableRowModel();
+  trm->GetLayerOpacityModel()->SetValue(value);
+}
+
+bool LayerGeneralPropertiesModel::GetLayerVisibilityValue(bool &value)
+{
+  LayerTableRowModel *trm = GetSelectedLayerTableRowModel();
+  return trm ? trm->GetVisibilityToggleModel()->GetValueAndDomain(value, NULL) : false;
+}
+
+void LayerGeneralPropertiesModel::SetLayerVisibilityValue(bool value)
+{
+  LayerTableRowModel *trm = GetSelectedLayerTableRowModel();
+  trm->GetVisibilityToggleModel()->SetValue(value);
+}
+
+bool LayerGeneralPropertiesModel::GetFilenameValue(std::string &value)
+{
+  ImageWrapperBase *layer = this->GetLayer();
+  if(layer)
+    {
+    value = layer->GetFileName();
+    return true;
+    }
+  return false;
+}
+
+bool LayerGeneralPropertiesModel::GetNicknameValue(std::string &value)
+{
+  ImageWrapperBase *layer = this->GetLayer();
+  if(layer)
+    {
+    value = layer->GetCustomNickname();
+    return true;
+    }
+  return false;
+}
+
+void LayerGeneralPropertiesModel::SetNicknameValue(std::string value)
+{
+  ImageWrapperBase *layer = this->GetLayer();
+  layer->SetCustomNickname(value);
+}
+
+VectorImageWrapperBase *
+LayerGeneralPropertiesModel::GetLayerAsVector()
+{
+  return dynamic_cast<VectorImageWrapperBase *>(this->GetLayer());
+}
+
+
+AbstractMultiChannelDisplayMappingPolicy *
+LayerGeneralPropertiesModel::GetMultiChannelDisplayPolicy()
+{
+  AbstractMultiChannelDisplayMappingPolicy *dp = static_cast<
+      AbstractMultiChannelDisplayMappingPolicy *>(
+        this->GetLayer()->GetDisplayMapping());
+  return dp;
+}
+
+LayerTableRowModel *LayerGeneralPropertiesModel::GetSelectedLayerTableRowModel()
+{
+  if(m_Layer)
+    return dynamic_cast<LayerTableRowModel *>(m_Layer->GetUserData("LayerTableRowModel"));
+  else return NULL;
+}
diff --git a/GUI/Model/LayerGeneralPropertiesModel.h b/GUI/Model/LayerGeneralPropertiesModel.h
new file mode 100644
index 0000000..149c40d
--- /dev/null
+++ b/GUI/Model/LayerGeneralPropertiesModel.h
@@ -0,0 +1,142 @@
+#ifndef LAYERGENERALPROPERTIESMODEL_H
+#define LAYERGENERALPROPERTIESMODEL_H
+
+#include "AbstractLayerAssociatedModel.h"
+#include "PropertyModel.h"
+
+class AbstractMultiChannelDisplayMappingPolicy;
+class LayerTableRowModel;
+
+/**
+ * Properties maintained for each layer in the layer association
+ */
+class GeneralLayerProperties
+{
+public:
+  irisGetSetMacro(ObserverTag, unsigned long)
+  irisGetSetMacro(VisibilityToggleModel, AbstractSimpleBooleanProperty *)
+
+  GeneralLayerProperties()
+    : m_ObserverTag(0), m_VisibilityToggleModel(NULL) {}
+
+  virtual ~GeneralLayerProperties() {}
+
+protected:
+
+  // The visibility toggle model for this layer. This model must remember the
+  // previous opacity value (and restore it when toggled from off to on) so it
+  // has to be associated with each layer
+  SmartPtr<AbstractSimpleBooleanProperty> m_VisibilityToggleModel;
+
+  // Whether or not we are already listening to events from this layer
+  unsigned long m_ObserverTag;
+};
+
+typedef AbstractLayerAssociatedModel<
+    GeneralLayerProperties, ImageWrapperBase> LayerGeneralPropertiesModelBase;
+
+class LayerGeneralPropertiesModel : public LayerGeneralPropertiesModelBase
+{
+public:
+  irisITKObjectMacro(LayerGeneralPropertiesModel, LayerGeneralPropertiesModelBase)
+
+  /**
+   * This enum defines the selections that the user can make for display mode.
+   * These selections roughly map to the ScalarRepresentation
+   * but the RGB mode is handled differently here and there (because RGB mode does
+   * is not a scalar representation).
+   */
+  enum DisplayMode {
+    MODE_COMPONENT = 0, MODE_MAGNITUDE, MODE_MAX, MODE_AVERAGE, MODE_RGB
+  };
+
+  /** States for this model */
+  enum UIState {
+    UIF_MULTICOMPONENT,
+    UIF_CAN_SWITCH_COMPONENTS
+  };
+
+  // Implementation of virtual functions from parent class
+  void RegisterWithLayer(ImageWrapperBase *layer);
+  void UnRegisterFromLayer(ImageWrapperBase *layer, bool being_deleted);
+
+  // Parent model assignment override
+  virtual void SetParentModel(GlobalUIModel *parent);
+
+  // Function called in response to events
+  virtual void OnUpdate();
+
+  // State management
+  bool CheckState(UIState state);
+
+  // Typedefs for the model for component selection
+  typedef SimpleItemSetDomain<DisplayMode, std::string> DisplayModeDomain;
+  typedef AbstractPropertyModel<DisplayMode, DisplayModeDomain> AbstractDisplayModeModel;
+
+  // Models
+  irisGetMacro(DisplayModeModel, AbstractDisplayModeModel *)
+  irisGetMacro(SelectedComponentModel, AbstractRangedIntProperty *)
+  irisGetMacro(AnimateModel, AbstractSimpleBooleanProperty *)
+
+  /** A model for overall layer opacity (int, range 0..100) */
+  irisRangedPropertyAccessMacro(LayerOpacity, int)
+
+  /** A model for the layer visibility on/off state */
+  irisSimplePropertyAccessMacro(LayerVisibility, bool)
+
+  /** A model for the filename */
+  irisSimplePropertyAccessMacro(Filename, std::string)
+
+  /** A model for the nickname */
+  irisSimplePropertyAccessMacro(Nickname, std::string)
+
+protected:
+
+  LayerGeneralPropertiesModel();
+  virtual ~LayerGeneralPropertiesModel();
+
+  SmartPtr<AbstractDisplayModeModel> m_DisplayModeModel;
+  bool GetDisplayModeValueAndRange(DisplayMode &value, DisplayModeDomain *domain);
+  void SetDisplayModeValue(DisplayMode value);
+
+  SmartPtr<AbstractRangedIntProperty> m_SelectedComponentModel;
+  bool GetSelectedComponentValueAndRange(int &value, NumericValueRange<int> *domain);
+  void SetSelectedComponentValue(int value);
+
+  SmartPtr<AbstractSimpleBooleanProperty> m_AnimateModel;
+  bool GetAnimateValue(bool &value);
+  void SetAnimateValue(bool value);
+
+  // layer opacity and visibility models
+  SmartPtr<AbstractRangedIntProperty> m_LayerOpacityModel;
+  SmartPtr<AbstractSimpleBooleanProperty> m_LayerVisibilityModel;
+
+  // Callbacks for the opacity model
+  bool GetLayerOpacityValueAndRange(int &value, NumericValueRange<int> *domain);
+  void SetLayerOpacityValue(int value);
+
+  // Callbacks for the visibility model
+  bool GetLayerVisibilityValue(bool &value);
+  void SetLayerVisibilityValue(bool value);
+
+  // Filename and nickname
+  SmartPtr<AbstractSimpleStringProperty> m_FilenameModel;
+  SmartPtr<AbstractSimpleStringProperty> m_NicknameModel;
+
+  bool GetFilenameValue(std::string &value);
+
+  bool GetNicknameValue(std::string &value);
+  void SetNicknameValue(std::string value);
+
+  // Get the current display settings
+  VectorImageWrapperBase *GetLayerAsVector();
+  AbstractMultiChannelDisplayMappingPolicy *GetMultiChannelDisplayPolicy();
+
+  // Get the LayerTableRowModel corresponding to the selected layer, or
+  // NULL if no layer is selected. Some of the properties that this model
+  // exposes are already exposed in LayerTableRowModel, so we delegate to
+  // them.
+  LayerTableRowModel *GetSelectedLayerTableRowModel();
+};
+
+#endif // LAYERGENERALPROPERTIESMODEL_H
diff --git a/GUI/Model/LayerSelectionModel.cxx b/GUI/Model/LayerSelectionModel.cxx
new file mode 100644
index 0000000..667b7c7
--- /dev/null
+++ b/GUI/Model/LayerSelectionModel.cxx
@@ -0,0 +1,22 @@
+#include "LayerSelectionModel.h"
+
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+
+int LayerSelectionModel::GetNumberOfLayers()
+{
+  GenericImageData *id = m_Parent->GetDriver()->GetCurrentImageData();
+  return id->GetNumberOfLayers(m_RoleFilter);
+}
+
+LayerIterator
+LayerSelectionModel::GetNthLayer(int n)
+{
+  GenericImageData *id = m_Parent->GetDriver()->GetCurrentImageData();
+  LayerIterator it(id, m_RoleFilter);
+  it += n;
+  return it;
+}
+
+
+
diff --git a/GUI/Model/LayerSelectionModel.h b/GUI/Model/LayerSelectionModel.h
new file mode 100644
index 0000000..86c9649
--- /dev/null
+++ b/GUI/Model/LayerSelectionModel.h
@@ -0,0 +1,54 @@
+#ifndef LAYERSELECTIONMODEL_H
+#define LAYERSELECTIONMODEL_H
+
+#include "AbstractModel.h"
+#include "GenericImageData.h"
+
+class GlobalUIModel;
+class ImageWrapperBase;
+
+/**
+  This model encapsulates a dynamic selection of image layers based on a
+  filter. For example, it can be used to create a dynamic list consisting
+  of a main image and all overlays.
+
+  By default, all of the roles are included in the filter.
+  */
+class LayerSelectionModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(LayerSelectionModel, AbstractModel)
+
+  /** Set the parent model */
+  void SetParentModel(GlobalUIModel *parent)
+    { m_Parent = parent; }
+
+  /** Set the filter for this model. See GenericImageData::GetLayer for details */
+  void SetRoleFilter(int role_filter)
+    { m_RoleFilter = role_filter; }
+
+  /**
+    Get the number of layers satisfying the filter. This is updated dynamically,
+    so it is always correct
+    */
+  int GetNumberOfLayers();
+
+  /**
+    Get an iterator object pointing to the N-th layer
+    */
+  LayerIterator GetNthLayer(int n);
+
+protected:
+
+  LayerSelectionModel()
+    : AbstractModel(), m_Parent(NULL), m_RoleFilter(ALL_ROLES) {}
+
+  virtual ~LayerSelectionModel() {}
+
+  GlobalUIModel *m_Parent;
+  int m_RoleFilter;
+
+};
+
+#endif // LAYERSELECTIONMODEL_H
diff --git a/GUI/Model/LayerTableRowModel.cxx b/GUI/Model/LayerTableRowModel.cxx
new file mode 100644
index 0000000..0232490
--- /dev/null
+++ b/GUI/Model/LayerTableRowModel.cxx
@@ -0,0 +1,371 @@
+#include "LayerTableRowModel.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "ImageWrapperBase.h"
+#include "NumericPropertyToggleAdaptor.h"
+#include "DisplayMappingPolicy.h"
+#include "DisplayLayoutModel.h"
+#include "ImageIOWizardModel.h"
+#include "ColorMapModel.h"
+#include "IntensityCurveModel.h"
+#include "LayerGeneralPropertiesModel.h"
+#include "SNAPImageData.h"
+
+
+LayerTableRowModel::LayerTableRowModel()
+{
+  m_LayerOpacityModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetLayerOpacityValueAndRange,
+        &Self::SetLayerOpacityValue);
+
+  m_NicknameModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetNicknameValue,
+        &Self::SetNicknameValue);
+
+  m_ComponentNameModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetComponentNameValue);
+
+  m_ColorMapPresetModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetColorMapPresetValue,
+        &Self::SetColorMapPresetValue);
+
+  m_StickyModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetStickyValue,
+        &Self::SetSticklyValue);
+
+  m_DisplayModeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetDisplayModeValue,
+        &Self::SetDisplayModeValue);
+
+  m_VisibilityToggleModel = NewNumericPropertyToggleAdaptor(
+        m_LayerOpacityModel.GetPointer(), 0, 50);
+
+  m_LayerRole = NO_ROLE;
+  m_LayerPositionInRole = -1;
+  m_ImageData = NULL;
+}
+
+bool LayerTableRowModel::CheckState(UIState state)
+{
+  // Are we in tiling mode?
+  bool tiling = (
+        m_ParentModel->GetGlobalState()->GetSliceViewLayerLayout() ==
+        LAYOUT_TILED);
+
+  bool snapmode = m_ParentModel->GetDriver()->IsSnakeModeActive();
+
+  // Check the states
+  switch(state)
+    {
+    // Opacity can be edited for all layers except the main image layer
+    case LayerTableRowModel::UIF_OPACITY_EDITABLE:
+      return (m_LayerRole != MAIN_ROLE);
+
+    case LayerTableRowModel::UIF_PINNABLE:
+      return (m_LayerRole != MAIN_ROLE && tiling);
+
+    case LayerTableRowModel::UIF_MOVABLE_UP:
+      return (m_LayerRole == OVERLAY_ROLE
+              && m_LayerPositionInRole > 0);
+
+    case LayerTableRowModel::UIF_MOVABLE_DOWN:
+      return (m_LayerRole == OVERLAY_ROLE
+              && m_LayerPositionInRole < m_LayerNumberOfLayersInRole - 1);
+
+    case LayerTableRowModel::UIF_CLOSABLE:
+      return ((m_LayerRole == OVERLAY_ROLE
+               || m_LayerRole == MAIN_ROLE) && !snapmode);
+
+    case LayerTableRowModel::UIF_CONTRAST_ADJUSTABLE:
+      return (m_Layer && m_Layer->GetDisplayMapping()->GetIntensityCurve());
+
+    case LayerTableRowModel::UIF_COLORMAP_ADJUSTABLE:
+      return (m_Layer && m_Layer->GetDisplayMapping()->GetColorMap());
+
+    case LayerTableRowModel::UIF_MULTICOMPONENT:
+      return (m_Layer && m_Layer->GetNumberOfComponents() > 1);
+    }
+
+  return false;
+}
+
+void LayerTableRowModel::UpdateRoleInfo()
+{
+  LayerIterator it(m_ImageData);
+  it.Find(m_Layer);
+  m_LayerRole = it.GetRole();
+  m_LayerPositionInRole = it.GetPositionInRole();
+  m_LayerNumberOfLayersInRole = it.GetNumberOfLayersInRole();
+}
+
+void LayerTableRowModel::UpdateDisplayModeList()
+{
+  m_AvailableDisplayModes.clear();
+  if(m_Layer && m_Layer->GetNumberOfComponents() > 1)
+    {
+    for(int i = 0; i < m_Layer->GetNumberOfComponents(); i++)
+      m_AvailableDisplayModes.push_back(
+            MultiChannelDisplayMode(false, SCALAR_REP_COMPONENT, i));
+    m_AvailableDisplayModes.push_back(
+          MultiChannelDisplayMode(false, SCALAR_REP_MAGNITUDE, 0));
+    m_AvailableDisplayModes.push_back(
+          MultiChannelDisplayMode(false, SCALAR_REP_MAX, 0));
+    m_AvailableDisplayModes.push_back(
+          MultiChannelDisplayMode(false, SCALAR_REP_AVERAGE, 0));
+
+    if(m_Layer->GetNumberOfComponents() == 3)
+      m_AvailableDisplayModes.push_back(
+            MultiChannelDisplayMode::DefaultForRGB());
+    }
+}
+
+MultiChannelDisplayMode LayerTableRowModel::GetDisplayMode()
+{
+  AbstractMultiChannelDisplayMappingPolicy *dp = dynamic_cast<
+      AbstractMultiChannelDisplayMappingPolicy *>(m_Layer->GetDisplayMapping());
+  return dp->GetDisplayMode();
+}
+
+void LayerTableRowModel::Initialize(GlobalUIModel *parentModel, ImageWrapperBase *layer)
+{
+  m_ParentModel = parentModel;
+  m_Layer = layer;
+  m_ImageData = parentModel->GetDriver()->GetCurrentImageData();
+
+  // For some of the functions, it is useful to know the role and the index
+  // in the role of this layer. We shouldn't have to worry about this info
+  // changing, since the rows get rebuilt when LayerChangeEvent() is fired.
+  UpdateRoleInfo();
+
+  // Update the list of display modes (again, should not change during the
+  // lifetime of this object
+  UpdateDisplayModeList();
+
+  // Listen to cosmetic events from the layer
+  Rebroadcast(layer, WrapperMetadataChangeEvent(), ModelUpdateEvent());
+  Rebroadcast(layer, WrapperDisplayMappingChangeEvent(), ModelUpdateEvent());
+
+  // What happens if the layer is deleted? The model should be notified, and
+  // it should update its state to a NULL state before something bad happens
+  // in the GUI...
+  Rebroadcast(layer, itk::DeleteEvent(), ModelUpdateEvent());
+
+  // The state of this model only depends on wrapper's position in the list of
+  // layers, not on the wrapper metadata
+  Rebroadcast(m_ParentModel->GetDriver(), LayerChangeEvent(),
+              StateMachineChangeEvent());
+
+  // The state also depends on the current tiling mode
+  Rebroadcast(m_ParentModel->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel(),
+              ValueChangedEvent(),
+              StateMachineChangeEvent());
+
+}
+
+void LayerTableRowModel::MoveLayerUp()
+{
+  m_ParentModel->GetDriver()->ChangeOverlayPosition(m_Layer, -1);
+}
+
+void LayerTableRowModel::MoveLayerDown()
+{
+  m_ParentModel->GetDriver()->ChangeOverlayPosition(m_Layer, +1);
+}
+
+
+SmartPtr<ImageIOWizardModel> LayerTableRowModel::CreateIOWizardModelForSave()
+{
+  return m_ParentModel->CreateIOWizardModelForSave(m_Layer, m_LayerRole);
+}
+
+bool LayerTableRowModel::IsMainLayer()
+{
+  return m_LayerRole == MAIN_ROLE;
+}
+
+void LayerTableRowModel::CloseLayer()
+{
+  // If this is an overlay, we unload it like this
+  if(m_LayerRole == OVERLAY_ROLE)
+    {
+    m_ParentModel->GetDriver()->UnloadOverlay(m_Layer);
+    m_Layer = NULL;
+    }
+
+  // The main image can also be unloaded
+  else if(m_LayerRole == MAIN_ROLE)
+    {
+    m_ParentModel->GetDriver()->UnloadMainImage();
+    m_Layer = NULL;
+    }
+}
+
+void LayerTableRowModel::AutoAdjustContrast()
+{
+  if(m_Layer && m_Layer->GetDisplayMapping()->GetIntensityCurve())
+    {
+    // TODO: this is a bit of a hack, since we go through a different model
+    // and have to swap out that model's current layer, which adds some overhead
+    IntensityCurveModel *icm = m_ParentModel->GetIntensityCurveModel();
+    ImageWrapperBase *currentLayer = icm->GetLayer();
+    icm->SetLayer(m_Layer);
+    icm->OnAutoFitWindow();
+    icm->SetLayer(currentLayer);
+    }
+}
+
+std::string
+LayerTableRowModel::GetDisplayModeString(const MultiChannelDisplayMode &mode)
+{
+  if(mode.UseRGB)
+    {
+    return "RGB";
+    }
+
+  std::ostringstream oss;
+  switch(mode.SelectedScalarRep)
+    {
+    case SCALAR_REP_COMPONENT:
+      oss << "Component ";
+      oss << (1 + mode.SelectedComponent);
+      return oss.str();
+
+    case SCALAR_REP_MAGNITUDE:
+      return "Magnitude";
+
+    case SCALAR_REP_MAX:
+      return "Maximum";
+
+    case SCALAR_REP_AVERAGE:
+      return "Average";
+
+    case NUMBER_OF_SCALAR_REPS:
+      break;
+    };
+
+  return "";
+}
+
+
+bool LayerTableRowModel::GetNicknameValue(std::string &value)
+{
+  if(!m_Layer) return false;
+
+  value = m_Layer->GetNickname();
+  return true;
+}
+
+void LayerTableRowModel::SetNicknameValue(std::string value)
+{
+  m_Layer->SetCustomNickname(value);
+}
+
+bool LayerTableRowModel::GetComponentNameValue(std::string &value)
+{
+  // Get the name of the compomnent
+  if(m_Layer && m_Layer->GetNumberOfComponents() > 1)
+    {
+    value = this->GetDisplayModeString(this->GetDisplayMode());
+    return true;
+    }
+
+  return false;
+}
+
+bool LayerTableRowModel::GetColorMapPresetValue(std::string &value)
+{
+  if(m_Layer && m_Layer->GetDisplayMapping()->GetColorMap())
+    {
+    value = ColorMap::GetPresetName(
+          m_Layer->GetDisplayMapping()->GetColorMap()->GetSystemPreset());
+    return true;
+    }
+  return false;
+}
+
+void LayerTableRowModel::SetColorMapPresetValue(std::string value)
+{
+  // TODO: this is a cheat! The current way of handling color map presets in
+  // snap is hacky, and I really don't like it. We need a common class that
+  // can handle system and user presets for a variety of objects, one that
+  // can interface nicely with the GUI models. Here we are going through
+  // the functionality provided by the ColorMapModel class.
+  ColorMapModel *cmm = m_ParentModel->GetColorMapModel();
+  ImageWrapperBase *currentLayer = cmm->GetLayer();
+  cmm->SetLayer(m_Layer);
+  cmm->SelectPreset(value);
+  cmm->SetLayer(currentLayer);
+}
+
+bool LayerTableRowModel::GetDisplayModeValue(MultiChannelDisplayMode &value)
+{
+  if(m_Layer && m_Layer->GetNumberOfComponents() > 1)
+    {
+    AbstractMultiChannelDisplayMappingPolicy *dp = dynamic_cast<
+        AbstractMultiChannelDisplayMappingPolicy *>(m_Layer->GetDisplayMapping());
+    value = dp->GetDisplayMode();
+    return true;
+    }
+  return false;
+}
+
+void LayerTableRowModel::SetDisplayModeValue(MultiChannelDisplayMode value)
+{
+  AbstractMultiChannelDisplayMappingPolicy *dp = dynamic_cast<
+      AbstractMultiChannelDisplayMappingPolicy *>(m_Layer->GetDisplayMapping());
+  dp->SetDisplayMode(value);
+}
+
+void LayerTableRowModel::OnUpdate()
+{
+  // Has our layer been deleted?
+  if(this->m_EventBucket->HasEvent(itk::DeleteEvent(), m_Layer))
+    {
+    m_Layer = NULL;
+    m_LayerRole = NO_ROLE;
+    m_LayerPositionInRole = -1;
+    m_LayerNumberOfLayersInRole = -1;
+    }
+  else if(this->m_EventBucket->HasEvent(LayerChangeEvent()))
+    {
+    this->UpdateRoleInfo();
+    }
+}
+
+
+
+bool LayerTableRowModel::GetLayerOpacityValueAndRange(int &value, NumericValueRange<int> *domain)
+{
+  if(!m_Layer) return false;
+
+  value = (int)(100.0 * m_Layer->GetAlpha());
+  if(domain)
+    domain->Set(0, 100, 5);
+  return true;
+}
+
+void LayerTableRowModel::SetLayerOpacityValue(int value)
+{
+  m_Layer->SetAlpha(value / 100.0);
+}
+
+bool LayerTableRowModel::GetStickyValue(bool &value)
+{
+  if(!m_Layer) return false;
+
+  value = m_Layer->IsSticky();
+  return true;
+}
+
+void LayerTableRowModel::SetSticklyValue(bool value)
+{
+  m_Layer->SetSticky(value);
+}
+
diff --git a/GUI/Model/LayerTableRowModel.h b/GUI/Model/LayerTableRowModel.h
new file mode 100644
index 0000000..01f8b1b
--- /dev/null
+++ b/GUI/Model/LayerTableRowModel.h
@@ -0,0 +1,175 @@
+#ifndef LAYERTABLEROWMODEL_H
+#define LAYERTABLEROWMODEL_H
+
+#include "PropertyModel.h"
+
+class ImageWrapperBase;
+class GlobalUIModel;
+class ImageIOWizardModel;
+struct MultiChannelDisplayMode;
+class GenericImageData;
+
+/**
+ * @brief The LayerTableRowModel class
+ *
+ * This is a GUI model used to access image layer properties that can appear
+ * in a list/table of layers. These properties include opacity, visibility,
+ * nickname, etc.
+ *
+ * This model is different from models such as LayerGeneralPropertiesModel:
+ * it has a one-to-one association with the layers, whereas those other models
+ * have a 1-N association with the layers (just one model object, parameterized
+ * by a pointer to the 'active' layer).
+ */
+class LayerTableRowModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(LayerTableRowModel, AbstractModel)
+
+  irisGetMacro(Layer, ImageWrapperBase *)
+
+  irisGetMacro(ParentModel, GlobalUIModel *)
+
+  /** A model for overall layer opacity (int, range 0..100) */
+  irisRangedPropertyAccessMacro(LayerOpacity, int)
+
+  /** A model for layer visibility (on/off, interacts with opacity) */
+  irisSimplePropertyAccessMacro(VisibilityToggle, bool)
+
+  /** A model for layer stickiness */
+  irisSimplePropertyAccessMacro(Sticky, bool)
+
+  /** A model for the nickname */
+  irisSimplePropertyAccessMacro(Nickname, std::string)
+
+  /** A model for the component name */
+  irisSimplePropertyAccessMacro(ComponentName, std::string)
+
+  /** A model for the color map preset currently selected */
+  irisSimplePropertyAccessMacro(ColorMapPreset, std::string)
+
+  /** A model for the display mode */
+  typedef AbstractPropertyModel<MultiChannelDisplayMode, TrivialDomain> AbstractDisplayModeModel;
+  irisGetMacro(DisplayModeModel, AbstractDisplayModeModel *)
+
+  /**
+    States in which the model can be, which allow the activation and
+    deactivation of various widgets in the interface
+    */
+  enum UIState {
+    UIF_OPACITY_EDITABLE,
+    UIF_PINNABLE,
+    UIF_MOVABLE_UP,
+    UIF_MOVABLE_DOWN,
+    UIF_CLOSABLE,
+    UIF_COLORMAP_ADJUSTABLE,
+    UIF_CONTRAST_ADJUSTABLE,
+    UIF_MULTICOMPONENT
+    };
+
+  /** Check the state of the system */
+  bool CheckState(UIState state);
+
+
+  void Initialize(GlobalUIModel *parentModel, ImageWrapperBase *layer);
+
+  /** Move layer up or down in its role. */
+  void MoveLayerUp();
+  void MoveLayerDown();
+
+  /**
+   * Create a temporary model for saving this image to a file, to use in
+   * conjunction with an IO wizard
+   */
+  SmartPtr<ImageIOWizardModel> CreateIOWizardModelForSave();
+
+  /**
+   * Whether closing the layer requires prompting for changes
+   */
+  bool IsMainLayer();
+
+  /**
+   * Close the current layer
+   */
+  void CloseLayer();
+
+  /** Auto-adjust contrast (via the IntensityCurveModel) */
+  void AutoAdjustContrast();
+
+
+  typedef std::list<MultiChannelDisplayMode> DisplayModeList;
+
+  /** Get a mapping of available display modes to user-readable strings */
+  irisGetMacro(AvailableDisplayModes, const DisplayModeList &)
+
+  /** Get the printable name for a display mode */
+  std::string GetDisplayModeString(const MultiChannelDisplayMode &mode);
+
+protected:
+  LayerTableRowModel();
+  virtual ~LayerTableRowModel() {}
+
+  // Parent model
+  GlobalUIModel *m_ParentModel;
+
+  // Generic image data object in which this layer lives.
+  GenericImageData *m_ImageData;
+
+  // Layer
+  ImageWrapperBase *m_Layer;
+
+  // Role information (cached)
+  LayerRole m_LayerRole;
+
+  int m_LayerPositionInRole, m_LayerNumberOfLayersInRole;
+
+  // Cached list of display modes
+  DisplayModeList m_AvailableDisplayModes;
+
+  // Visibility model
+  SmartPtr<AbstractSimpleBooleanProperty> m_VisibilityToggleModel;
+
+  // Stickly model
+  SmartPtr<AbstractSimpleBooleanProperty> m_StickyModel;
+  bool GetStickyValue(bool &value);
+  void SetSticklyValue(bool value);
+
+  // Opacity model
+  SmartPtr<AbstractRangedIntProperty> m_LayerOpacityModel;
+  bool GetLayerOpacityValueAndRange(int &value, NumericValueRange<int> *domain);
+  void SetLayerOpacityValue(int value);
+
+  // Nickname model
+  SmartPtr<AbstractSimpleStringProperty> m_NicknameModel;
+  bool GetNicknameValue(std::string &value);
+  void SetNicknameValue(std::string value);
+
+  // Component name model
+  SmartPtr<AbstractSimpleStringProperty> m_ComponentNameModel;
+  bool GetComponentNameValue(std::string &value);
+
+  // Color map preset model
+  SmartPtr<AbstractSimpleStringProperty> m_ColorMapPresetModel;
+  bool GetColorMapPresetValue(std::string &value);
+  void SetColorMapPresetValue(std::string value);
+
+  // Display mode model
+  SmartPtr<AbstractDisplayModeModel> m_DisplayModeModel;
+  bool GetDisplayModeValue(MultiChannelDisplayMode &value);
+  void SetDisplayModeValue(MultiChannelDisplayMode value);
+
+  // Update our state in response to events from the layer
+  virtual void OnUpdate();
+
+  // Update cached role information
+  void UpdateRoleInfo();
+
+  // Update cached display modes list
+  void UpdateDisplayModeList();
+
+  // Get the display mode
+  MultiChannelDisplayMode GetDisplayMode();
+};
+
+#endif // LAYERTABLEROWMODEL_H
diff --git a/GUI/Model/MeshExportModel.cxx b/GUI/Model/MeshExportModel.cxx
new file mode 100644
index 0000000..d35c426
--- /dev/null
+++ b/GUI/Model/MeshExportModel.cxx
@@ -0,0 +1,179 @@
+#include "MeshExportModel.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "MeshExportSettings.h"
+#include "Registry.h"
+#include "GuidedMeshIO.h"
+#include "Generic3DModel.h"
+#include "itksys/RegularExpression.hxx"
+#include "HistoryManager.h"
+
+MeshExportModel::MeshExportModel()
+  : AbstractModel()
+{
+  m_SaveMode = SAVE_SINGLE_LABEL;
+  m_SaveModeModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetSaveModeValue, &Self::SetSaveModeValue);
+
+  m_ExportFileNameModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetExportFileNameValue, &Self::SetExportFileNameValue);
+
+  m_ExportedLabelModel = ConcreteColorLabelPropertyModel::New();
+
+  // Configure the export model
+  m_ExportFormatModel = ConcreteFileFormatModel::New();
+  m_ExportFormatModel->SetValue(GuidedMeshIO::FORMAT_VTK);
+
+  // Configure the format regular expressions
+  m_FormatRegExp[GuidedMeshIO::FORMAT_VTK] = ".*\\.vtk$";
+  m_FormatRegExp[GuidedMeshIO::FORMAT_STL] = ".*\\.stl$";
+  m_FormatRegExp[GuidedMeshIO::FORMAT_BYU] = ".*\\.(byu|y)$";
+  m_FormatRegExp[GuidedMeshIO::FORMAT_VRML] = ".*\\.vrml$";
+}
+
+
+void MeshExportModel::SetParentModel(GlobalUIModel *parent)
+{
+  // Store the parent model
+  m_ParentModel = parent;
+
+  // Initialize the label property
+  m_ExportedLabelModel->Initialize(parent->GetDriver()->GetColorLabelTable());
+
+
+
+}
+
+bool MeshExportModel::CheckState(MeshExportModel::UIState flag)
+{
+  switch(flag)
+    {
+    case MeshExportModel::UIF_LABEL_SELECTION_ACTIVE:
+      return this->GetSaveMode() == SAVE_SINGLE_LABEL;
+    }
+  return false;
+}
+
+
+
+void MeshExportModel::OnDialogOpen()
+{
+  // Use the drawing label as the default
+  LabelType label = m_ParentModel->GetGlobalState()->GetDrawingColorLabel();
+  if(label == 0)
+    label = m_ParentModel->GetDriver()->GetColorLabelTable()->FindNextValidLabel(0, false);
+  m_ExportedLabelModel->SetValue(label);
+
+  // Get the default filename for the currently loaded image
+  m_ExportFileNameModel->SetValue("");
+
+  // Update the file formats list
+  UpdateFormatDomain();
+}
+
+void MeshExportModel::SaveMesh()
+{
+  IRISApplication *app = m_ParentModel->GetDriver();
+  MeshExportSettings settings;
+  settings.SetMeshFileName(m_ExportFileName);
+  switch(this->GetSaveMode())
+    {
+    case MeshExportModel::SAVE_SINGLE_LABEL:
+      settings.SetFlagSingleLabel(true);
+      settings.SetFlagSingleScene(false);
+      settings.SetExportLabel(this->GetExportedLabel());
+      break;
+    case MeshExportModel::SAVE_MULTIPLE_FILES:
+      settings.SetFlagSingleLabel(false);
+      settings.SetFlagSingleScene(false);
+      break;
+    case MeshExportModel::SAVE_SCENE:
+      settings.SetFlagSingleLabel(false);
+      settings.SetFlagSingleScene(true);
+      break;
+    }
+
+  // Handle the format (in a round-about way)
+  Registry registry;
+  GuidedMeshIO io;
+  io.SetFileFormat(registry, this->GetExportFormat());
+  settings.SetMeshFormat(registry);
+
+  // The actual export should use the Generic3DModel, which will take care of
+  // thread safety (make sure the meshes are not being updated during export
+  m_ParentModel->GetModel3D()->ExportMesh(settings);
+
+  // Update the history
+  m_ParentModel->GetSystemInterface()->GetHistoryManager()->UpdateHistory(
+        this->GetHistoryName(), m_ExportFileName, true);
+}
+
+MeshExportModel::FileFormat MeshExportModel::GetFileFormatByName(const std::string &name) const
+{
+  FileFormatDomain dom;
+  FileFormat dummy;
+  m_ExportFormatModel->GetValueAndDomain(dummy, &dom);
+
+  for(int i = 0; i < GuidedMeshIO::FORMAT_COUNT; i++)
+    {
+    FileFormat fmt = (FileFormat) i;
+    if(dom[fmt] == name)
+      return fmt;
+    }
+
+  return GuidedMeshIO::FORMAT_COUNT;
+}
+
+void MeshExportModel::UpdateFormatDomain()
+{
+  FileFormatDomain format_domain;
+  if(GetSaveMode() == SAVE_SCENE)
+    {
+    format_domain[GuidedMeshIO::FORMAT_VTK] = "VTK PolyData File";
+    format_domain[GuidedMeshIO::FORMAT_VRML] = "VRML 2.0 File";
+    }
+  else
+    {
+    format_domain[GuidedMeshIO::FORMAT_VTK] = "VTK PolyData File";
+    format_domain[GuidedMeshIO::FORMAT_STL] = "STL Mesh File";
+    format_domain[GuidedMeshIO::FORMAT_BYU] = "BYU Mesh File";
+    }
+
+  m_ExportFormatModel->SetDomain(format_domain);
+}
+
+bool MeshExportModel::GetSaveModeValue(SaveMode &value)
+{
+  value = m_SaveMode;
+  return true;
+}
+
+void MeshExportModel::SetSaveModeValue(SaveMode value)
+{
+  m_SaveMode = value;
+  UpdateFormatDomain();
+  InvokeEvent(StateMachineChangeEvent());
+}
+
+bool MeshExportModel::GetExportFileNameValue(std::string &value)
+{
+  value = m_ExportFileName;
+  return true;
+}
+
+
+void MeshExportModel::SetExportFileNameValue(std::string value)
+{
+  m_ExportFileName = value;
+
+  // Try to determine the file format from the extension
+  for(int format = 0; format < GuidedMeshIO::FORMAT_COUNT; format++)
+    {
+    std::string regexp_str = m_FormatRegExp[(FileFormat) format];
+    itksys::RegularExpression regexp(regexp_str.c_str());
+    if(regexp.find(m_ExportFileName))
+      {
+      m_ExportFormatModel->SetValue((FileFormat) format);
+      }
+    }
+}
diff --git a/GUI/Model/MeshExportModel.h b/GUI/Model/MeshExportModel.h
new file mode 100644
index 0000000..e16d17a
--- /dev/null
+++ b/GUI/Model/MeshExportModel.h
@@ -0,0 +1,105 @@
+#ifndef MESHEXPORTMODEL_H
+#define MESHEXPORTMODEL_H
+
+#include "PropertyModel.h"
+#include "ColorLabelPropertyModel.h"
+#include "GuidedMeshIO.h"
+
+class GlobalUIModel;
+
+class MeshExportModel : public AbstractModel
+{
+public:
+  irisITKObjectMacro(MeshExportModel, AbstractModel)
+
+  /**
+    States in which the model can be, which allow the activation and
+    deactivation of various widgets in the interface
+    */
+  enum UIState {
+    UIF_LABEL_SELECTION_ACTIVE
+    };
+
+  void SetParentModel(GlobalUIModel *parent);
+
+  bool CheckState(UIState flag);
+
+  /** Selected save mode */
+  enum SaveMode { SAVE_SINGLE_LABEL, SAVE_MULTIPLE_FILES, SAVE_SCENE };
+
+  /** Mesh file format */
+  typedef GuidedMeshIO::FileFormat FileFormat;
+
+  /** Domain for the mesh file format model */
+  typedef SimpleItemSetDomain<FileFormat, std::string> FileFormatDomain;
+
+  /** Model governing the selected save mode */
+  irisSimplePropertyAccessMacro(SaveMode, SaveMode)
+
+  /** Model for selecting the color label */
+  irisGenericPropertyAccessMacro(ExportedLabel, LabelType, ColorLabelItemSetDomain)
+
+  /** Filename for the export */
+  irisSimplePropertyAccessMacro(ExportFileName, std::string)
+
+  /** File format for the export */
+  irisGenericPropertyAccessMacro(ExportFormat, FileFormat, FileFormatDomain)
+
+  /** Get the parent model */
+  irisGetMacro(ParentModel, GlobalUIModel *)
+
+  /** Get the name of the history used for mesh export */
+  static std::string GetHistoryName() { return "SegmentationMesh"; }
+
+  /** This method is called when the dialog is opened */
+  void OnDialogOpen();
+
+  /** Perform the actual save */
+  void SaveMesh();
+
+  /** Get the file format corresponding to a name */
+  FileFormat GetFileFormatByName(const std::string &name) const;
+
+protected:
+
+  MeshExportModel();
+  virtual ~MeshExportModel() {}
+
+  // Parent model
+  GlobalUIModel *m_ParentModel;
+
+  // Model for the way meshes are saved
+  typedef AbstractPropertyModel<SaveMode, TrivialDomain> AbstractSaveModeModel;
+  SmartPtr<AbstractSaveModeModel> m_SaveModeModel;
+
+  bool GetSaveModeValue(SaveMode &value);
+  void SetSaveModeValue(SaveMode value);
+
+  // Save mode (cached)
+  SaveMode m_SaveMode;
+
+  // Color label used
+  SmartPtr<ConcreteColorLabelPropertyModel> m_ExportedLabelModel;
+
+  // Filename for the export
+  std::string m_ExportFileName;
+
+  // Model wrapping around the filename
+  SmartPtr<AbstractSimpleStringProperty> m_ExportFileNameModel;
+  bool GetExportFileNameValue(std::string &value);
+  void SetExportFileNameValue(std::string value);
+
+  // File format for the export
+  typedef ConcretePropertyModel<FileFormat, FileFormatDomain> ConcreteFileFormatModel;
+  SmartPtr<ConcreteFileFormatModel> m_ExportFormatModel;
+
+  // Update the domain of the format model based on the current state of the save
+  // mode. This is because only some formats are supported in save modes
+  void UpdateFormatDomain();
+
+  // Regular expressions for file formats
+  std::map<FileFormat, std::string> m_FormatRegExp;
+
+};
+
+#endif // MESHEXPORTMODEL_H
diff --git a/GUI/Model/NumericPropertyToggleAdaptor.h b/GUI/Model/NumericPropertyToggleAdaptor.h
new file mode 100644
index 0000000..97b899b
--- /dev/null
+++ b/GUI/Model/NumericPropertyToggleAdaptor.h
@@ -0,0 +1,122 @@
+#ifndef NUMERICPROPERTYTOGGLEADAPTOR_H
+#define NUMERICPROPERTYTOGGLEADAPTOR_H
+
+#include "PropertyModel.h"
+
+/**
+ * @brief The NumericPropertyToggleAdaptor class
+ *
+ * This model is a wrapper around a numerical property that allows the user
+ * to toggle the property on and off. When the property is toggled off, it is
+ * set to the DefaultOffValue, when it is toggled on, it is set to the last
+ * value when it was toggled off.
+ *
+ * The main intended use of this adapter is for opacity sliders
+ *
+ * This model necessarily has an ambiguity when the user moves the slider to
+ * the off value, and then toggles the switch to the on position. The model
+ * sets the slider to the DefaultOnValue when that happens.
+ *
+ * The model is templated over the model representing the numerical value.
+ * Typically, this would be ConcreteRangedIntProperty or a similar class.
+ */
+
+template <class TNumericValueModel>
+class NumericPropertyToggleAdaptor : public AbstractSimpleBooleanProperty
+{
+public:
+  typedef NumericPropertyToggleAdaptor<TNumericValueModel> Self;
+  typedef AbstractSimpleBooleanProperty Superclass;
+  typedef SmartPtr<Self> Pointer;
+  typedef SmartPtr<const Self> ConstPointer;
+  itkTypeMacro(NumericPropertyToggleAdaptor, AbstractSimpleBooleanProperty)
+  itkNewMacro(Self)
+
+  typedef TNumericValueModel ValueModelType;
+  typedef typename ValueModelType::ValueType NumericValueType;
+  typedef typename Superclass::ValueType ValueType;
+  typedef typename Superclass::DomainType DomainType;
+
+  /** Set the default value when going from off state to on state */
+  void SetDefaultOnValue(NumericValueType value)
+    { m_DefaultOnValue = value; }
+
+  /** The default off value should be zero, but can be changed */
+  void SetDefaultOffValue(NumericValueType value)
+    { m_DefaultOffValue = value; }
+
+  /** Set the wrapped value property model */
+  void SetWrappedValueModel(ValueModelType *model)
+  {
+    m_ValueModel = model;
+    Rebroadcast(model, ValueChangedEvent(), ValueChangedEvent());
+  }
+
+  virtual bool GetValueAndDomain(bool &value, TrivialDomain *)
+  {
+    if(!m_ValueModel) return false;
+
+    NumericValueType numValue;
+    if(!m_ValueModel->GetValueAndDomain(numValue, NULL))
+      return false;
+
+    value = (numValue != m_DefaultOffValue);
+    return true;
+  }
+
+  virtual void SetValue(bool value)
+  {
+    if(!m_ValueModel) return;
+
+    NumericValueType numValue;
+    if(!m_ValueModel->GetValueAndDomain(numValue, NULL))
+      return;
+
+    if(value && numValue == m_DefaultOffValue)
+      {
+      // Restore the value to what it was before we clicked the checkbox off
+      m_ValueModel->SetValue(m_LastOnValue);
+      m_LastOnValue = m_DefaultOnValue;
+      }
+
+    if(!value && numValue != m_DefaultOffValue)
+      {
+      // Save the current value before setting to default
+      m_LastOnValue = numValue;
+      m_ValueModel->SetValue(m_DefaultOffValue);
+      }
+  }
+
+protected:
+  NumericPropertyToggleAdaptor()
+  {
+    m_DefaultOffValue = 0;
+    m_DefaultOnValue = 0;
+    m_LastOnValue = 0;
+  }
+
+  NumericValueType m_DefaultOnValue, m_DefaultOffValue, m_LastOnValue;
+  SmartPtr<ValueModelType> m_ValueModel;
+};
+
+
+/**
+ * A factory method to create these models
+ */
+template <class TNumericValueModel>
+SmartPtr<AbstractSimpleBooleanProperty>
+NewNumericPropertyToggleAdaptor(
+    TNumericValueModel *model,
+    typename TNumericValueModel::ValueType defaultOffValue,
+    typename TNumericValueModel::ValueType defaultOnValue)
+{
+  typedef NumericPropertyToggleAdaptor<TNumericValueModel> Prop;
+  SmartPtr<Prop> p = Prop::New();
+  p->SetWrappedValueModel(model);
+  p->SetDefaultOffValue(defaultOffValue);
+  p->SetDefaultOnValue(defaultOnValue);
+  SmartPtr<AbstractSimpleBooleanProperty> pp = p.GetPointer();
+  return pp;
+}
+
+#endif // NUMERICPROPERTYTOGGLEADAPTOR_H
diff --git a/GUI/Model/OrthogonalSliceCursorNavigationModel.cxx b/GUI/Model/OrthogonalSliceCursorNavigationModel.cxx
new file mode 100644
index 0000000..9c19cbe
--- /dev/null
+++ b/GUI/Model/OrthogonalSliceCursorNavigationModel.cxx
@@ -0,0 +1,185 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "OrthogonalSliceCursorNavigationModel.h"
+#include "GenericSliceModel.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "GlobalUIModel.h"
+#include "SliceWindowCoordinator.h"
+#include "ImageCoordinateTransform.h"
+
+void OrthogonalSliceCursorNavigationModel::UpdateCursor(Vector2f x)
+{
+  // Compute the position in slice coordinates
+  Vector3f xClick = m_Parent->MapWindowToSlice(x);
+
+  // Compute the new cross-hairs position in image space
+  Vector3f xCross = m_Parent->MapSliceToImage(xClick);
+
+  // Round the cross-hairs position down to integer
+  Vector3i xCrossInteger = to_int(xCross);
+
+  // Make sure that the cross-hairs position is within bounds by clamping
+  // it to image dimensions
+  Vector3i xSize = to_int(m_Parent->GetDriver()->
+                          GetCurrentImageData()->GetVolumeExtents());
+  Vector3ui xCrossClamped = to_unsigned_int(
+    xCrossInteger.clamp(Vector3i(0),xSize - Vector3i(1)));
+
+  // Update the crosshairs position in the global state
+  m_Parent->GetDriver()->SetCursorPosition(xCrossClamped);
+}
+
+void OrthogonalSliceCursorNavigationModel::ProcessKeyNavigation(Vector3i dx)
+{
+  // Get the displacement in image space
+  Vector3f dximg =
+      m_Parent->GetDisplayToImageTransform().TransformVector(to_float(dx));
+  Vector3i dximgi = to_int(dximg);
+
+  // Update the cursor
+  IRISApplication *app = m_Parent->GetDriver();
+  Vector3i xSize = to_int(app->GetCurrentImageData()->GetVolumeExtents());
+  Vector3i cursor = to_int(app->GetCursorPosition());
+  cursor += dximgi;
+  cursor = cursor.clamp(Vector3i(0), xSize - 1);
+  app->SetCursorPosition(to_unsigned_int(cursor));
+}
+
+void OrthogonalSliceCursorNavigationModel::BeginZoom()
+{
+  m_StartViewZoom = m_Parent->GetViewZoom();
+}
+
+void OrthogonalSliceCursorNavigationModel::BeginPan()
+{
+  m_StartViewPosition = m_Parent->GetViewPosition();
+}
+
+void OrthogonalSliceCursorNavigationModel::EndZoom() { }
+void OrthogonalSliceCursorNavigationModel::EndPan() { }
+
+void OrthogonalSliceCursorNavigationModel
+::ProcessZoomGesture(float scaleFactor)
+{
+  // Get the slice coordinator
+  SliceWindowCoordinator *coordinator =
+      m_Parent->GetParentUI()->GetSliceCoordinator();
+
+  // Sometimes the scalefactor is 1, in which case, we restore the zoom
+  if(scaleFactor == 1.0f)
+    {
+    if(m_Parent->GetViewZoom() == m_StartViewZoom)
+      return;
+    else
+      m_Parent->SetViewZoom(m_StartViewZoom);
+    }
+  else
+    {
+    // Compute the zoom factor (is this good?)
+    float zoom = m_StartViewZoom * scaleFactor;
+
+    // Clamp the zoom factor to reasonable limits
+    zoom = coordinator->ClampZoom(m_Parent->GetId(), zoom);
+
+    // Make sure the zoom factor is an integer fraction
+    zoom = m_Parent->GetOptimalZoom() *
+           ((int)(zoom / m_Parent->GetOptimalZoom() * 100)) / 100.0f;
+
+    // Set the zoom factor using the window coordinator
+    m_Parent->SetViewZoom(zoom);
+    }
+
+  // TODO: remove this!
+  coordinator->OnZoomUpdateInWindow(m_Parent->GetId(), m_Parent->GetViewZoom());
+}
+
+void
+OrthogonalSliceCursorNavigationModel
+::ProcessPanGesture(Vector2f uvOffset)
+{
+  // Compute the start and end point in slice coordinates
+  Vector3f zOffset = m_Parent->MapWindowOffsetToSliceOffset(uvOffset);
+  Vector2f xOffset(zOffset[0] * m_Parent->GetSliceSpacing()[0],
+                   zOffset[1] * m_Parent->GetSliceSpacing()[1]);
+
+  // Under the left button, the tool changes the view_pos by the
+  // distance traversed
+  m_Parent->SetViewPosition(m_StartViewPosition - xOffset);
+}
+
+void OrthogonalSliceCursorNavigationModel
+::ProcessScrollGesture(float scrollAmount)
+{
+  // Get the cross-hairs position in image space
+  Vector3ui xCrossImage = m_Parent->GetDriver()->GetCursorPosition();
+
+  // Map it into slice space
+  Vector3f xCrossSlice =
+    m_Parent->MapImageToSlice(to_float(xCrossImage) + Vector3f(0.5f));
+
+  // Advance by the scroll amount
+  xCrossSlice[2] += scrollAmount;
+
+  // Map back into display space
+  xCrossImage = to_unsigned_int(m_Parent->MapSliceToImage(xCrossSlice));
+
+  // Clamp by the image size
+  Vector3ui xSize =
+      m_Parent->GetDriver()->GetCurrentImageData()->GetVolumeExtents();
+  Vector3ui xCrossClamped =
+      xCrossImage.clamp(Vector3ui(0,0,0), xSize - Vector3ui(1,1,1));
+
+  // Update the crosshairs position in the global state
+  m_Parent->GetDriver()->SetCursorPosition(xCrossClamped);
+}
+
+bool OrthogonalSliceCursorNavigationModel::CheckThumbnail(Vector2i xCanvas)
+{
+  // Check if the event is inside of the thumbnail boundaries
+  Vector2i xThumb = m_Parent->GetThumbnailPosition();
+  Vector2i sThumb = m_Parent->GetThumbnailSize();
+  return (m_Parent->IsThumbnailOn() &&
+    xCanvas[0] > xThumb[0] &&
+    xCanvas[0] < xThumb[0] + sThumb[0] &&
+    xCanvas[1] > xThumb[1] &&
+          xCanvas[1] < xThumb[1] + sThumb[1]);
+  }
+
+void OrthogonalSliceCursorNavigationModel
+::ProcessThumbnailPanGesture(Vector2i uvOffset)
+{
+  // Figure out how this movement translates to space units
+  Vector2f xOffset(
+    uvOffset[0] / m_Parent->GetThumbnailZoom(),
+    uvOffset[1] / m_Parent->GetThumbnailZoom());
+
+  // Add to the position
+  m_Parent->SetViewPosition(m_StartViewPosition - xOffset);
+}
+
diff --git a/GUI/Model/OrthogonalSliceCursorNavigationModel.h b/GUI/Model/OrthogonalSliceCursorNavigationModel.h
new file mode 100644
index 0000000..e1b3936
--- /dev/null
+++ b/GUI/Model/OrthogonalSliceCursorNavigationModel.h
@@ -0,0 +1,93 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef ORTHOGONALSLICECURSORNAVIGATIONMODEL_H
+#define ORTHOGONALSLICECURSORNAVIGATIONMODEL_H
+
+#include <SNAPCommon.h>
+#include "AbstractModel.h"
+
+class GenericSliceModel;
+
+class OrthogonalSliceCursorNavigationModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(OrthogonalSliceCursorNavigationModel, AbstractModel)
+
+  irisSetMacro(Parent, GenericSliceModel *)
+  irisGetMacro(Parent, GenericSliceModel *)
+
+  // Move 3D cursor to (x,y) point on the screen supplied by user
+  void UpdateCursor(Vector2f x);
+
+  // Start zoom operation
+  void BeginZoom();
+
+  // End zoom operation
+  void EndZoom();
+
+  // Start pan operation
+  void BeginPan();
+
+  // End pan
+  void EndPan();
+
+  // Process zoom or pan operation (parameter is the gesture length,
+  // which in theory should work both on desktop and on an iPhone).
+  void ProcessZoomGesture(float scaleFactor);
+
+  // Process pan operation (parameter is the gesture vector, i.e., mouse
+  // drag or three-finger gesture)
+  void ProcessPanGesture(Vector2f uvOffset);
+
+  // Process a scrolling-type gesture (mouse wheel, or two-finger scroll)
+  void ProcessScrollGesture(float gLength);
+
+  // Check if the user press position is inside the thumbnail
+  bool CheckThumbnail(Vector2i xCanvas);
+
+  // Process pan operation (parameter is the gesture vector, i.e., mouse
+  // drag or three-finger gesture)
+  void ProcessThumbnailPanGesture(Vector2i uvOffset);
+
+  // Process arrow key and pageup/down commands
+  void ProcessKeyNavigation(Vector3i dx);
+protected:
+
+  OrthogonalSliceCursorNavigationModel() {}
+  ~OrthogonalSliceCursorNavigationModel() {}
+
+  // Zoom and pan factors at the beginning of interaction
+  Vector2f m_StartViewPosition;
+  float m_StartViewZoom;
+
+  GenericSliceModel *m_Parent;
+
+
+};
+
+#endif // ORTHOGONALSLICECURSORNAVIGATIONMODEL_H
diff --git a/GUI/Model/PaintbrushModel.cxx b/GUI/Model/PaintbrushModel.cxx
new file mode 100644
index 0000000..2182375
--- /dev/null
+++ b/GUI/Model/PaintbrushModel.cxx
@@ -0,0 +1,490 @@
+#include "PaintbrushModel.h"
+#include "GenericSliceModel.h"
+#include "GlobalState.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+
+#include "itkRegionOfInterestImageFilter.h"
+#include "itkGradientAnisotropicDiffusionImageFilter.h"
+#include "itkGradientMagnitudeImageFilter.h"
+#include "itkWatershedImageFilter.h"
+
+
+// TODO: move this into a separate file!!!!
+class BrushWatershedPipeline
+{
+public:
+  typedef itk::Image<GreyType, 3> GreyImageType;
+  typedef itk::Image<LabelType, 3> LabelImageType;
+  typedef itk::Image<float, 3> FloatImageType;
+  typedef itk::Image<unsigned long, 3> WatershedImageType;
+  typedef WatershedImageType::IndexType IndexType;
+
+  BrushWatershedPipeline()
+    {
+    roi = ROIType::New();
+    adf = ADFType::New();
+    adf->SetInput(roi->GetOutput());
+    adf->SetConductanceParameter(0.5);
+    gmf = GMFType::New();
+    gmf->SetInput(adf->GetOutput());
+    wf = WFType::New();
+    wf->SetInput(gmf->GetOutput());
+    }
+
+  void PrecomputeWatersheds(
+    GreyImageType *grey,
+    LabelImageType *label,
+    itk::ImageRegion<3> region,
+    itk::Index<3> vcenter,
+    size_t smoothing_iter)
+    {
+    this->region = region;
+
+    // Get the offset of vcenter in the region
+    if(region.IsInside(vcenter))
+      for(size_t d = 0; d < 3; d++)
+        this->vcenter[d] = vcenter[d] - region.GetIndex()[d];
+    else
+      for(size_t d = 0; d < 3; d++)
+        this->vcenter[d] = region.GetSize()[d] / 2;
+
+    // Create a backup of the label image
+    LROIType::Pointer lroi = LROIType::New();
+    lroi->SetInput(label);
+    lroi->SetRegionOfInterest(region);
+    lroi->Update();
+    lsrc = lroi->GetOutput();
+    lsrc->DisconnectPipeline();
+
+    // Initialize the watershed pipeline
+    roi->SetInput(grey);
+    roi->SetRegionOfInterest(region);
+    adf->SetNumberOfIterations(smoothing_iter);
+
+    // Set the initial level to lowest possible - to get all watersheds
+    wf->SetLevel(1.0);
+    wf->Update();
+    }
+
+  void RecomputeWatersheds(double level)
+    {
+    // Reupdate the filter with new level
+    wf->SetLevel(level);
+    wf->Update();
+    }
+
+  bool IsPixelInSegmentation(IndexType idx)
+    {
+    // Get the watershed ID at the center voxel
+    unsigned long wctr = wf->GetOutput()->GetPixel(vcenter);
+    unsigned long widx = wf->GetOutput()->GetPixel(idx);
+    return wctr == widx;
+    }
+
+  bool UpdateLabelImage(
+    LabelImageType *ltrg,
+    CoverageModeType mode,
+    LabelType drawing_color,
+    LabelType overwrt_color)
+    {
+    // Get the watershed ID at the center voxel
+    unsigned long wid = wf->GetOutput()->GetPixel(vcenter);
+
+    // Keep track of changed voxels
+    bool flagChanged = false;
+
+    // Do the update
+    typedef itk::ImageRegionConstIterator<WatershedImageType> WIter;
+    typedef itk::ImageRegionIterator<LabelImageType> LIter;
+    WIter wit(wf->GetOutput(), wf->GetOutput()->GetBufferedRegion());
+    LIter sit(lsrc, lsrc->GetBufferedRegion());
+    LIter tit(ltrg, region);
+    for(; !wit.IsAtEnd(); ++sit,++tit,++wit)
+      {
+      LabelType pxLabel = sit.Get();
+      if(wit.Get() == wid)
+        {
+        // Standard paint mode
+        if (mode == PAINT_OVER_ALL ||
+          (mode == PAINT_OVER_ONE && pxLabel == overwrt_color) ||
+          (mode == PAINT_OVER_VISIBLE && pxLabel != 0))
+          {
+          pxLabel = drawing_color;
+          }
+        }
+      if(pxLabel != tit.Get())
+        {
+        tit.Set(pxLabel);
+        flagChanged = true;
+        }
+      }
+
+    if(flagChanged)
+      ltrg->Modified();
+    return flagChanged;
+    }
+
+private:
+  typedef itk::RegionOfInterestImageFilter<GreyImageType, FloatImageType> ROIType;
+  typedef itk::RegionOfInterestImageFilter<LabelImageType, LabelImageType> LROIType;
+  typedef itk::GradientAnisotropicDiffusionImageFilter<FloatImageType,FloatImageType> ADFType;
+  typedef itk::GradientMagnitudeImageFilter<FloatImageType, FloatImageType> GMFType;
+  typedef itk::WatershedImageFilter<FloatImageType> WFType;
+
+  ROIType::Pointer roi;
+  ADFType::Pointer adf;
+  GMFType::Pointer gmf;
+  WFType::Pointer wf;
+
+  itk::ImageRegion<3> region;
+  LabelImageType::Pointer lsrc;
+  itk::Index<3> vcenter;
+};
+
+
+
+
+
+
+PaintbrushModel::PaintbrushModel()
+{
+  m_ReverseMode = false;
+  m_Watershed = new BrushWatershedPipeline();
+}
+
+PaintbrushModel::~PaintbrushModel()
+{
+  delete m_Watershed;
+}
+
+Vector3f PaintbrushModel::ComputeOffset()
+{
+  // Get the paintbrush properties
+  PaintbrushSettings pbs =
+      m_Parent->GetDriver()->GetGlobalState()->GetPaintbrushSettings();
+
+  Vector3f offset(0.0);
+  if(fmod(pbs.radius,1.0)==0)
+    {
+    offset.fill(0.5);
+    offset(m_Parent->GetSliceDirectionInImageSpace()) = 0.0;
+    }
+
+  return offset;
+}
+
+void PaintbrushModel::ComputeMousePosition(const Vector3f &xSlice)
+{
+  // Only when an image is loaded
+  if(!m_Parent->GetDriver()->IsMainImageLoaded())
+    return;
+
+  // Get the paintbrush properties
+  PaintbrushSettings pbs =
+      m_Parent->GetDriver()->GetGlobalState()->GetPaintbrushSettings();
+
+  // Compute the new cross-hairs position in image space
+  Vector3f xCross = m_Parent->MapSliceToImage(xSlice);
+
+  // Round the cross-hairs position down to integer
+  Vector3i xCrossInteger = to_int(xCross + ComputeOffset());
+
+  // Make sure that the cross-hairs position is within bounds by clamping
+  // it to image dimensions
+  Vector3i xSize =
+      to_int(m_Parent->GetDriver()->GetCurrentImageData()->GetVolumeExtents());
+
+  Vector3ui newpos = to_unsigned_int(
+    xCrossInteger.clamp(Vector3i(0),xSize - Vector3i(1)));
+
+  if(newpos != m_MousePosition || m_MouseInside == false)
+    {
+    m_MousePosition = newpos;
+    m_MouseInside = true;
+    InvokeEvent(PaintbrushMovedEvent());
+    }
+}
+
+bool PaintbrushModel::TestInside(const Vector2d &x, const PaintbrushSettings &ps)
+{
+  return this->TestInside(Vector3d(x(0), x(1), 0.0), ps);
+}
+
+
+// TODO: make this faster by precomputing all the repeated quantities. The inside
+// check should take a lot less time!
+bool PaintbrushModel::TestInside(const Vector3d &x, const PaintbrushSettings &ps)
+{
+  // Determine how to scale the voxels
+  Vector3d xTest = x;
+  if(ps.isotropic)
+    {
+    const Vector3f &spacing = m_Parent->GetSliceSpacing();
+    double xMinVoxelDim = spacing.min_value();
+    xTest(0) *= spacing(0) / xMinVoxelDim;
+    xTest(1) *= spacing(1) / xMinVoxelDim;
+    xTest(2) *= spacing(2) / xMinVoxelDim;
+    }
+
+  // Test inside/outside
+  if(ps.mode == PAINTBRUSH_ROUND)
+    {
+    return xTest.squared_magnitude() <= (ps.radius-0.25) * (ps.radius-0.25);
+    }
+  else
+    {
+    return xTest.inf_norm() <= ps.radius - 0.25;
+    }
+}
+
+bool
+PaintbrushModel
+::ProcessPushEvent(const Vector3f &xSlice, bool reverse_mode)
+{
+  // Get the paintbrush properties (TODO: should we own them?)
+  PaintbrushSettings pbs =
+      m_Parent->GetDriver()->GetGlobalState()->GetPaintbrushSettings();
+
+  // Compute the mouse position
+  ComputeMousePosition(xSlice);
+
+  // Check if the right button was pressed
+  ApplyBrush(reverse_mode, false);
+
+  // Store the reverse mode
+  m_ReverseMode = reverse_mode;
+
+  // Store this as the last apply position
+  m_LastApplyX = xSlice;
+
+  // Eat the event unless cursor chasing is enabled
+  return pbs.chase ? 0 : 1;
+}
+
+bool
+PaintbrushModel
+::ProcessDragEvent(const Vector3f &xSlice, const Vector3f &xSliceLast,
+                   double pixelsMoved, bool release)
+{
+  IRISApplication *driver = m_Parent->GetDriver();
+  PaintbrushSettings pbs = driver->GetGlobalState()->GetPaintbrushSettings();
+
+  // The behavior is different for 'fast' regular brushes and adaptive brush. For the
+  // adaptive brush, dragging is disabled.
+  if(pbs.mode != PAINTBRUSH_WATERSHED || m_ReverseMode)
+    {
+    // See how much we have moved since the last event. If we moved more than
+    // the value of the radius, we interpolate the path and place brush strokes
+    // along the path
+    if(pixelsMoved > pbs.radius)
+      {
+      // Break up the path into steps
+      size_t nSteps = (int) ceil(pixelsMoved / pbs.radius);
+      for(size_t i = 0; i < nSteps; i++)
+        {
+        float t = (1.0 + i) / nSteps;
+        Vector3f X = t * m_LastApplyX + (1.0f - t) * xSlice;
+        ComputeMousePosition(X);
+        ApplyBrush(m_ReverseMode, true);
+        }
+      }
+    else
+      {
+      // Find the pixel under the mouse
+      ComputeMousePosition(xSlice);
+
+      // Scan convert the points into the slice
+      ApplyBrush(m_ReverseMode, true);
+      }
+
+    // Store this as the last apply position
+    m_LastApplyX = xSlice;
+    }
+
+  // If the mouse is being released, we need to commit the drawing
+  if(release)
+    {
+    driver->StoreUndoPoint("Drawing with paintbrush");
+
+    // TODO: this is ugly. The code for applying a brush should really be
+    // placed in the IRISApplication.
+    driver->InvokeEvent(SegmentationChangeEvent());
+    }
+
+  // Eat the event unless cursor chasing is enabled
+  return pbs.chase ? 0 : 1;
+}
+
+bool PaintbrushModel::ProcessMouseMoveEvent(const Vector3f &xSlice)
+{
+  ComputeMousePosition(xSlice);
+  return true;
+}
+
+
+bool PaintbrushModel::ProcessMouseLeaveEvent()
+{
+  m_MouseInside = false;
+  InvokeEvent(PaintbrushMovedEvent());
+  return true;
+}
+
+void PaintbrushModel::AcceptAtCursor()
+{
+  IRISApplication *driver = m_Parent->GetDriver();
+
+  m_MousePosition = m_Parent->GetDriver()->GetCursorPosition();
+  m_MouseInside = true;
+  ApplyBrush(false, false);
+
+  // We need to commit the drawing
+  driver->StoreUndoPoint("Drawing with paintbrush");
+
+  // TODO: this is ugly. The code for applying a brush should really be
+  // placed in the IRISApplication.
+  driver->InvokeEvent(SegmentationChangeEvent());
+}
+
+bool
+PaintbrushModel::ApplyBrush(bool reverse_mode, bool dragging)
+{
+  // Get the global objects
+  IRISApplication *driver = m_Parent->GetDriver();
+  GlobalState *gs = driver->GetGlobalState();
+
+  // Get the segmentation image
+  LabelImageWrapper *imgLabel = driver->GetCurrentImageData()->GetSegmentation();
+
+  // Get the paint properties
+  LabelType drawing_color = gs->GetDrawingColorLabel();
+  DrawOverFilter drawover = gs->GetDrawOverFilter();
+
+  // Get the paintbrush properties
+  PaintbrushSettings pbs = gs->GetPaintbrushSettings();
+
+  // Whether watershed filter is used (adaptive brush)
+  bool flagWatershed = (
+        pbs.mode == PAINTBRUSH_WATERSHED
+        && (!reverse_mode) && (!dragging));
+
+  // Define a region of interest
+  LabelImageWrapper::ImageType::RegionType xTestRegion;
+  for(size_t i = 0; i < 3; i++)
+    {
+    if(i != imgLabel->GetDisplaySliceImageAxis(m_Parent->GetId())
+       || pbs.volumetric)
+      {
+      // For watersheds, the radius must be > 2
+      double rad = (flagWatershed && pbs.radius < 1.5) ? 1.5 : pbs.radius;
+      xTestRegion.SetIndex(i, (long) (m_MousePosition(i) - rad)); // + 1);
+      xTestRegion.SetSize(i, (long) (2 * rad + 1)); // - 1);
+      }
+    else
+      {
+      xTestRegion.SetIndex(i, m_MousePosition(i));
+      xTestRegion.SetSize(i, 1);
+      }
+    }
+
+  // Crop the region by the buffered region
+  xTestRegion.Crop(imgLabel->GetImage()->GetBufferedRegion());
+
+  // Flag to see if anything was changed
+  bool flagUpdate = false;
+
+  // Special code for Watershed brush
+  if(flagWatershed)
+    {
+    GenericImageData *gid = driver->GetCurrentImageData();
+
+    // Precompute the watersheds
+    m_Watershed->PrecomputeWatersheds(
+          gid->GetMain()->GetDefaultScalarRepresentation()->GetCommonFormatImage(),
+          driver->GetCurrentImageData()->GetSegmentation()->GetImage(),
+          xTestRegion, to_itkIndex(m_MousePosition), pbs.watershed.smooth_iterations);
+
+    m_Watershed->RecomputeWatersheds(pbs.watershed.level);
+    }
+
+  // Shift vector (different depending on whether the brush has odd/even diameter
+  Vector3f offset = ComputeOffset();
+
+  // Iterate over the region
+  LabelImageWrapper::Iterator it(imgLabel->GetImage(), xTestRegion);
+  for(; !it.IsAtEnd(); ++it)
+    {
+    // Check if we are inside the sphere
+    LabelImageWrapper::ImageType::IndexType idx = it.GetIndex();
+    Vector3f xDelta =
+        offset
+        + to_float(Vector3l(idx.GetIndex()))
+        - to_float(m_MousePosition);
+
+    Vector3d xDeltaSliceSpace = to_double(
+          m_Parent->GetImageToDisplayTransform().TransformVector(xDelta));
+
+    // Check if the pixel is inside
+    if(!TestInside(xDeltaSliceSpace, pbs))
+      continue;
+
+    // Check if the pixel is in the watershed
+    if(flagWatershed)
+      {
+      LabelImageWrapper::ImageType::IndexType idxoff = to_itkIndex(
+        Vector3l(idx.GetIndex()) - Vector3l(xTestRegion.GetIndex().GetIndex()));
+      if(!m_Watershed->IsPixelInSegmentation(idxoff))
+        continue;
+      }
+
+    // Paint the pixel
+    LabelType pxLabel = it.Get();
+
+    // Standard paint mode
+    if(!reverse_mode)
+      {
+      if(drawover.CoverageMode == PAINT_OVER_ALL ||
+        (drawover.CoverageMode == PAINT_OVER_ONE && pxLabel == drawover.DrawOverLabel) ||
+        (drawover.CoverageMode == PAINT_OVER_VISIBLE && pxLabel != 0))
+        {
+        it.Set(drawing_color);
+        if(pxLabel != drawing_color) flagUpdate = true;
+        }
+      }
+    // Background paint mode (clear label over current label)
+    else
+      {
+      if(drawing_color != 0 && pxLabel == drawing_color)
+        {
+        it.Set(0);
+        if(pxLabel != 0) flagUpdate = true;
+        }
+      else if(drawing_color == 0 && drawover.CoverageMode == PAINT_OVER_ONE)
+        {
+        it.Set(drawover.DrawOverLabel);
+        if(pxLabel != drawover.DrawOverLabel) flagUpdate = true;
+        }
+      }
+    }
+
+  // Image has been updated
+  if(flagUpdate)
+    {
+    imgLabel->GetImage()->Modified();
+    }
+
+  return flagUpdate;
+}
+
+
+Vector3f PaintbrushModel::GetCenterOfPaintbrushInSliceSpace()
+{
+  PaintbrushSettings pbs =
+      m_Parent->GetDriver()->GetGlobalState()->GetPaintbrushSettings();
+
+  if(fmod(pbs.radius, 1.0) == 0)
+    return m_Parent->MapImageToSlice(to_float(m_MousePosition));
+  else
+    return m_Parent->MapImageToSlice(to_float(m_MousePosition) + Vector3f(0.5f));
+}
diff --git a/GUI/Model/PaintbrushModel.h b/GUI/Model/PaintbrushModel.h
new file mode 100644
index 0000000..fee5ff5
--- /dev/null
+++ b/GUI/Model/PaintbrushModel.h
@@ -0,0 +1,69 @@
+#ifndef PAINTBRUSHMODEL_H
+#define PAINTBRUSHMODEL_H
+
+#include "AbstractModel.h"
+#include "GlobalState.h"
+
+class GenericSliceModel;
+class BrushWatershedPipeline;
+
+
+class PaintbrushModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(PaintbrushModel, AbstractModel)
+
+  itkEventMacro(PaintbrushMovedEvent, IRISEvent)
+
+  irisGetSetMacro(Parent, GenericSliceModel *)
+
+  irisIsMacro(MouseInside)
+
+  FIRES(PaintbrushMovedEvent)
+
+  bool ProcessPushEvent(const Vector3f &xSlice, bool reverse_mode);
+  bool ProcessDragEvent(const Vector3f &xSlice, const Vector3f &xSliceLast,
+                        double pixelsMoved, bool release);
+
+  bool ProcessMouseMoveEvent(const Vector3f &xSlice);
+  bool ProcessMouseLeaveEvent();
+
+  void AcceptAtCursor();
+
+  // Get the location in slice coordinates where the center of the paintbrush
+  // should be rendered
+  Vector3f GetCenterOfPaintbrushInSliceSpace();
+
+
+protected:
+
+  // Whether we are inverting the paintbrush when drawing
+  bool m_ReverseMode;
+
+  // Mouse position in voxel coordinates
+  Vector3ui m_MousePosition;
+  bool m_MouseInside;
+
+  // Mouse position in slice coordinates from which we need to draw the
+  // next segment
+  Vector3f m_LastApplyX;
+
+  PaintbrushModel();
+  virtual ~PaintbrushModel();
+
+  Vector3f ComputeOffset();
+  void ComputeMousePosition(const Vector3f &xSlice);
+
+  bool ApplyBrush(bool reverse_mode, bool dragging);
+  bool TestInside(const Vector2d &x, const PaintbrushSettings &ps);
+  bool TestInside(const Vector3d &x, const PaintbrushSettings &ps);
+
+  GenericSliceModel *m_Parent;
+  BrushWatershedPipeline *m_Watershed;
+
+  friend class PaintbrushRenderer;
+
+};
+
+#endif // PAINTBRUSHMODEL_H
diff --git a/GUI/Model/PaintbrushSettingsModel.cxx b/GUI/Model/PaintbrushSettingsModel.cxx
new file mode 100644
index 0000000..6785a21
--- /dev/null
+++ b/GUI/Model/PaintbrushSettingsModel.cxx
@@ -0,0 +1,136 @@
+#include "PaintbrushSettingsModel.h"
+#include "GlobalUIModel.h"
+#include "GlobalState.h"
+
+PaintbrushSettingsModel::PaintbrushSettingsModel()
+{
+  m_PaintbrushSettingsModel =
+      wrapGetterSetterPairAsProperty(this,
+                                     &Self::GetPaintbrushSettings,
+                                     &Self::SetPaintbrushSettings);
+
+  // Create models for the fields of PaintbrushSettings
+  m_PaintbrushModeModel =
+      wrapStructMemberAsSimpleProperty<PaintbrushSettings, PaintbrushMode>(
+        m_PaintbrushSettingsModel, offsetof(PaintbrushSettings, mode));
+
+  m_VolumetricBrushModel =
+      wrapStructMemberAsSimpleProperty<PaintbrushSettings, bool>(
+        m_PaintbrushSettingsModel, offsetof(PaintbrushSettings, volumetric));
+
+  m_IsotropicBrushModel =
+      wrapStructMemberAsSimpleProperty<PaintbrushSettings, bool>(
+        m_PaintbrushSettingsModel, offsetof(PaintbrushSettings, isotropic));
+
+  m_ChaseCursorModel =
+      wrapStructMemberAsSimpleProperty<PaintbrushSettings, bool>(
+        m_PaintbrushSettingsModel, offsetof(PaintbrushSettings, chase));
+
+  // The paintbrush size model requires special processing, so it is implemeted
+  // using a getter/setter pair
+  m_BrushSizeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetBrushSizeValueAndRange,
+        &Self::SetBrushSizeValue);
+
+  m_AdaptiveModeModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetAdaptiveModeValue);
+
+  m_ThresholdLevelModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetThresholdLevelValueAndRange,
+        &Self::SetThresholdLevelValue);
+
+  m_SmoothingIterationsModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetSmoothingIterationValueAndRange,
+        &Self::SetSmoothingIterationValue);
+}
+
+PaintbrushSettingsModel::~PaintbrushSettingsModel()
+{
+}
+
+PaintbrushSettings PaintbrushSettingsModel::GetPaintbrushSettings()
+{
+  return m_ParentModel->GetGlobalState()->GetPaintbrushSettings();
+}
+
+void PaintbrushSettingsModel::SetPaintbrushSettings(PaintbrushSettings ps)
+{
+  m_ParentModel->GetGlobalState()->SetPaintbrushSettings(ps);
+  InvokeEvent(ModelUpdateEvent());
+}
+
+bool PaintbrushSettingsModel
+::GetBrushSizeValueAndRange(int &value, NumericValueRange<int> *domain)
+{
+  PaintbrushSettings pbs = GetPaintbrushSettings();
+
+  // Round just in case
+  value = (int) (pbs.radius * 2 + 0.5);
+  if(domain)
+    domain->Set(1, 40, 1);
+  return true;
+}
+
+void PaintbrushSettingsModel::SetBrushSizeValue(int value)
+{
+  PaintbrushSettings pbs = GetPaintbrushSettings();
+
+  pbs.radius = 0.5 * value;
+  SetPaintbrushSettings(pbs);
+}
+
+bool PaintbrushSettingsModel::GetAdaptiveModeValue(bool &value)
+{
+  PaintbrushSettings pbs = GetPaintbrushSettings();
+
+  value = (pbs.mode == PAINTBRUSH_WATERSHED);
+  return true;
+}
+
+bool PaintbrushSettingsModel::GetThresholdLevelValueAndRange(double &value, NumericValueRange<double> *domain)
+{
+  PaintbrushSettings pbs = GetPaintbrushSettings();
+
+  value = pbs.watershed.level * 100.0;
+  if(domain)
+    {
+    domain->Set(0, 100, 1);
+    }
+  return true;
+}
+
+void PaintbrushSettingsModel::SetThresholdLevelValue(double value)
+{
+  PaintbrushSettings pbs = GetPaintbrushSettings();
+  pbs.watershed.level = 0.01 * value;
+  SetPaintbrushSettings(pbs);
+}
+
+bool PaintbrushSettingsModel::GetSmoothingIterationValueAndRange(
+    int &value, NumericValueRange<int> *domain)
+{
+  PaintbrushSettings pbs = GetPaintbrushSettings();
+
+  value = pbs.watershed.smooth_iterations;
+  if(domain)
+    {
+    domain->Set(0, 100, 1);
+    }
+  return true;
+
+}
+
+void PaintbrushSettingsModel::SetSmoothingIterationValue(int value)
+{
+  PaintbrushSettings pbs = GetPaintbrushSettings();
+  pbs.watershed.smooth_iterations = value;
+  SetPaintbrushSettings(pbs);
+}
+
+
+
+
+
diff --git a/GUI/Model/PaintbrushSettingsModel.h b/GUI/Model/PaintbrushSettingsModel.h
new file mode 100644
index 0000000..bdb2419
--- /dev/null
+++ b/GUI/Model/PaintbrushSettingsModel.h
@@ -0,0 +1,65 @@
+#ifndef PAINTBRUSHSETTINGSMODEL_H
+#define PAINTBRUSHSETTINGSMODEL_H
+
+#include "AbstractModel.h"
+#include "PropertyModel.h"
+#include "GlobalState.h"
+
+class GlobalUIModel;
+
+class PaintbrushSettingsModel : public AbstractModel
+{
+public:
+  irisITKObjectMacro(PaintbrushSettingsModel, AbstractModel)
+
+  typedef AbstractPropertyModel<PaintbrushMode> AbstractPaintbrushModeModel;
+  typedef ConcretePropertyModel<PaintbrushMode> ConcretePaintbrushModeModel;
+
+  irisGetSetMacro(ParentModel, GlobalUIModel *)
+
+  irisGetMacro(PaintbrushModeModel, AbstractPaintbrushModeModel *)
+
+  irisGetMacro(BrushSizeModel, AbstractRangedIntProperty *)
+  irisGetMacro(VolumetricBrushModel, AbstractSimpleBooleanProperty *)
+  irisGetMacro(IsotropicBrushModel, AbstractSimpleBooleanProperty *)
+  irisGetMacro(ChaseCursorModel, AbstractSimpleBooleanProperty *)
+
+  irisGetMacro(AdaptiveModeModel, AbstractSimpleBooleanProperty *)
+  irisGetMacro(ThresholdLevelModel, AbstractRangedDoubleProperty *)
+  irisGetMacro(SmoothingIterationsModel, AbstractRangedIntProperty *)
+
+protected:
+
+  PaintbrushSettingsModel();
+  virtual ~PaintbrushSettingsModel();
+
+  GlobalUIModel *m_ParentModel;
+
+  // Model that sets and retrieves the PaintbrushSettings
+  typedef AbstractPropertyModel<PaintbrushSettings> PaintbrushSettingsStructModel;
+  SmartPtr<PaintbrushSettingsStructModel> m_PaintbrushSettingsModel;
+  PaintbrushSettings GetPaintbrushSettings();
+  void SetPaintbrushSettings(PaintbrushSettings ps);
+
+  SmartPtr<AbstractPaintbrushModeModel> m_PaintbrushModeModel;
+  SmartPtr<AbstractSimpleBooleanProperty> m_VolumetricBrushModel;
+  SmartPtr<AbstractSimpleBooleanProperty> m_IsotropicBrushModel;
+  SmartPtr<AbstractSimpleBooleanProperty> m_ChaseCursorModel;
+
+  SmartPtr<AbstractRangedIntProperty> m_BrushSizeModel;
+  bool GetBrushSizeValueAndRange(int &value, NumericValueRange<int> *domain);
+  void SetBrushSizeValue(int value);
+
+  SmartPtr<AbstractSimpleBooleanProperty> m_AdaptiveModeModel;
+  bool GetAdaptiveModeValue(bool &value);
+
+  SmartPtr<AbstractRangedDoubleProperty> m_ThresholdLevelModel;
+  bool GetThresholdLevelValueAndRange(double &value, NumericValueRange<double> *domain);
+  void SetThresholdLevelValue(double value);
+
+  SmartPtr<AbstractRangedIntProperty> m_SmoothingIterationsModel;
+  bool GetSmoothingIterationValueAndRange(int &value, NumericValueRange<int> *domain);
+  void SetSmoothingIterationValue(int value);
+};
+
+#endif // PAINTBRUSHSETTINGSMODEL_H
diff --git a/GUI/Model/PolygonDrawingModel.cxx b/GUI/Model/PolygonDrawingModel.cxx
new file mode 100644
index 0000000..6e5e416
--- /dev/null
+++ b/GUI/Model/PolygonDrawingModel.cxx
@@ -0,0 +1,862 @@
+#include "PolygonDrawingModel.h"
+#include "PolygonScanConvert.h"
+#include "SNAPOpenGL.h"
+#include <iostream>
+#include <cstdlib>
+#include <algorithm>
+#include <set>
+#include <vnl/vnl_random.h>
+
+#include "GenericSliceModel.h"
+#include "itkImage.h"
+#include "itkPointSet.h"
+#include "itkBSplineScatteredDataPointSetToImageFilter.h"
+#include "IRISApplication.h"
+
+#include <SNAPUIFlag.h>
+#include <SNAPUIFlag.txx>
+
+// Enable this model to be used with the flag engine
+template class SNAPUIFlag<PolygonDrawingModel, PolygonDrawingUIState>;
+
+using namespace std;
+
+
+PolygonDrawingModel
+::PolygonDrawingModel()
+{
+  m_CachedPolygon = false;
+  m_State = INACTIVE_STATE;
+  m_SelectedVertices = false;
+  m_DraggingPickBox = false;
+  m_FreehandFittingRate = 8;
+  m_StartX = 0; m_StartY = 0;
+  m_PolygonSlice = PolygonSliceType::New();
+  m_HoverOverFirstVertex = false;
+}
+
+PolygonDrawingModel
+::~PolygonDrawingModel()
+{
+
+}
+
+Vector2f
+PolygonDrawingModel::GetPixelSize()
+{
+  Vector3f x =
+    m_Parent->MapWindowToSlice(Vector2f(1.0f)) -
+    m_Parent->MapWindowToSlice(Vector2f(0.0f));
+
+  return Vector2f(x[0],x[1]);
+}
+
+bool
+PolygonDrawingModel
+::CheckNearFirstVertex(float x, float y, float pixel_x, float pixel_y)
+{
+  if(m_Vertices.size() > 2)
+    {
+    Vector2d A(m_Vertices.front().x / pixel_x,
+               m_Vertices.front().y / pixel_y);
+    Vector2d C(x / pixel_x, y / pixel_y);
+    if((A-C).inf_norm() < 4)
+      return true;
+    }
+  return false;
+}
+
+bool
+PolygonDrawingModel
+::ProcessPushEvent(float x, float y,
+                   bool shift_state)
+{
+  bool handled = false;
+  Vector2f pxsize = GetPixelSize();
+  float pixel_x = pxsize(0), pixel_y = pxsize(1);
+
+  if(m_State == INACTIVE_STATE)
+    {
+    SetState(DRAWING_STATE);
+    m_Vertices.push_back( Vertex(x, y, false, true) );
+
+    handled = true;
+    }
+
+  else if(m_State == DRAWING_STATE)
+    {
+    // Restart Dragging
+    m_DragVertices.clear();
+
+    // The hover state is false
+    m_HoverOverFirstVertex = false;
+
+    // Left click means to add a vertex to the polygon. However, for
+    // compatibility reasons, we must make sure that there are no duplicates
+    // in the polygon (otherwise, division by zero occurs).
+    if(m_Vertices.size() == 0 ||
+       m_Vertices.back().x != x || m_Vertices.back().y != y)
+      {
+      // Check if the user wants to close the polygon
+      if(CheckNearFirstVertex(x, y, pixel_x, pixel_y))
+        ClosePolygon();
+      else
+        m_Vertices.push_back( Vertex(x, y, false, true) );
+      }
+
+    handled = true;
+    }
+
+  else if(m_State == EDITING_STATE)
+    {
+    m_StartX = x;
+    m_StartY = y;
+
+    if(!shift_state && m_SelectedVertices &&
+       (x >= (m_EditBox[0] - 4.0*pixel_x)) &&
+       (x <= (m_EditBox[1] + 4.0*pixel_x)) &&
+       (y >= (m_EditBox[2] - 4.0*pixel_y)) &&
+       (y <= (m_EditBox[3] + 4.0*pixel_y)))
+      {
+      // user not holding shift key; if user clicked inside edit box,
+      // edit box will be moved in drag event
+      }
+    else
+      {
+      if(!shift_state)
+        {
+        // clicked outside of edit box & shift not held, this means the
+        // current selection will be cleared
+        for(VertexIterator it = m_Vertices.begin(); it!=m_Vertices.end(); ++it)
+          it->selected = false;
+        m_SelectedVertices = false;
+        }
+
+      // check if vertex clicked
+      if(CheckClickOnVertex(x,y,pixel_x,pixel_y,4))
+        ComputeEditBox();
+
+      // check if clicked near a line segment
+      else if(CheckClickOnLineSegment(x,y,pixel_x,pixel_y,4))
+        ComputeEditBox();
+
+      // otherwise start dragging pick box
+      else
+        {
+        m_DraggingPickBox = true;
+        m_SelectionBox[0] = m_SelectionBox[1] = x;
+        m_SelectionBox[2] = m_SelectionBox[3] = y;
+        }
+      }
+
+    handled = true;
+    }
+
+  if(handled)
+    InvokeEvent(StateMachineChangeEvent());
+
+  return handled;
+}
+
+bool
+PolygonDrawingModel
+::ProcessMouseMoveEvent(float x, float y)
+{
+  if(m_State == DRAWING_STATE)
+    {
+    // Check if we are hovering over the starting vertex
+    Vector2f pxsize = GetPixelSize();
+    float pixel_x = pxsize(0), pixel_y = pxsize(1);
+    bool hover = CheckNearFirstVertex(x, y, pixel_x, pixel_y);
+
+    if(hover != m_HoverOverFirstVertex)
+      {
+      m_HoverOverFirstVertex = hover;
+      return true;
+      }
+    }
+
+  return false;
+}
+
+bool
+PolygonDrawingModel
+::ProcessDragEvent(float x, float y)
+{
+  bool handled = false;
+  if(m_State == DRAWING_STATE)
+    {
+    if(m_Vertices.size() == 0)
+      {
+      m_Vertices.push_back(Vertex(x,y,false,true));
+      }
+    else
+      {
+      // Check/set the hover state
+      ProcessMouseMoveEvent(x, y);
+
+      // Check if a point should be added here
+      if(m_FreehandFittingRate == 0)
+        {
+        m_Vertices.push_back(Vertex(x,y,false,false));
+        }
+      else
+        {
+        Vector2f pxsize = GetPixelSize();
+        Vertex &v = m_Vertices.back();
+        double dx = (v.x-x) / pxsize[0];
+        double dy = (v.y-y) / pxsize[1];
+        double d = dx*dx+dy*dy;
+        if(d >= m_FreehandFittingRate * m_FreehandFittingRate)
+          m_Vertices.push_back(Vertex(x,y,false,true));
+        }
+      }
+    handled = true;
+    }
+
+  else if(m_State == EDITING_STATE)
+    {
+    if (m_DraggingPickBox)
+      {
+      m_SelectionBox[1] = x;
+      m_SelectionBox[3] = y;
+      }
+    else
+      {
+      m_EditBox[0] += (x - m_StartX);
+      m_EditBox[1] += (x - m_StartX);
+      m_EditBox[2] += (y - m_StartY);
+      m_EditBox[3] += (y - m_StartY);
+
+      // If the selection is bounded by control vertices, we simply shift it
+      for(VertexIterator it = m_Vertices.begin(); it!=m_Vertices.end(); ++it)
+        {
+        if (it->selected)
+          {
+          it->x += (x - m_StartX);
+          it->y += (y - m_StartY);
+          }
+        }
+
+      // If the selection is bounded by freehand vertices, we apply a smooth
+      m_StartX = x;
+      m_StartY = y;
+      }
+
+    handled = true;
+    }
+
+  if(handled)
+    InvokeEvent(StateMachineChangeEvent());
+  return handled;
+}
+
+bool
+PolygonDrawingModel
+::ProcessReleaseEvent(float x, float y)
+{
+  bool handled = false;
+  Vector2f pxsize = GetPixelSize();
+  float pixel_x = pxsize(0), pixel_y = pxsize(1);
+
+  if(m_State == DRAWING_STATE)
+    {
+    // Check if we've closed the loop
+    if(CheckNearFirstVertex(x, y, pixel_x, pixel_y))
+      {
+      ClosePolygon();
+      }
+
+    // Make sure the last point is a control point
+    if(m_Vertices.size() && m_Vertices.back().control == false)
+      m_Vertices.back().control = true;
+
+    handled = true;
+    }
+
+  else if(m_State == EDITING_STATE)
+    {
+    if (m_DraggingPickBox)
+      {
+      m_DraggingPickBox = false;
+
+      float temp;
+      if (m_SelectionBox[0] > m_SelectionBox[1])
+        {
+        temp = m_SelectionBox[0];
+        m_SelectionBox[0] = m_SelectionBox[1];
+        m_SelectionBox[1] = temp;
+        }
+      if (m_SelectionBox[2] > m_SelectionBox[3])
+        {
+        temp = m_SelectionBox[2];
+        m_SelectionBox[2] = m_SelectionBox[3];
+        m_SelectionBox[3] = temp;
+        }
+
+      for(VertexIterator it = m_Vertices.begin(); it!=m_Vertices.end(); ++it)
+        {
+        if((it->x >= m_SelectionBox[0]) && (it->x <= m_SelectionBox[1])
+           && (it->y >= m_SelectionBox[2]) && (it->y <= m_SelectionBox[3]))
+          it->selected = 1;
+        }
+      ComputeEditBox();
+      }
+    handled = true;
+    }
+
+  if(handled)
+    InvokeEvent(StateMachineChangeEvent());
+  return handled;
+
+}
+
+
+
+/**
+ * ComputeEditBox()
+ *
+ * purpose:
+ * compute the bounding box around selected vertices
+ *
+ * post:
+ * if m_Vertices are selected, sets m_SelectedVertices to 1, else 0
+ */
+void
+PolygonDrawingModel
+::ComputeEditBox()
+{
+  VertexIterator it;
+
+  // Find the first selected vertex and initialize the selection box
+  m_SelectedVertices = false;
+  for (it = m_Vertices.begin(); it!=m_Vertices.end();++it)
+    {
+    if (it->selected)
+      {
+      m_EditBox[0] = m_EditBox[1] = it->x;
+      m_EditBox[2] = m_EditBox[3] = it->y;
+      m_SelectedVertices = true;
+      break;
+      }
+    }
+
+  // Continue only if a selection exists
+  if (!m_SelectedVertices) return;
+
+  // Grow selection box to fit all selected vertices
+  for(it = m_Vertices.begin(); it!=m_Vertices.end();++it)
+    {
+    if (it->selected)
+      {
+      if (it->x < m_EditBox[0]) m_EditBox[0] = it->x;
+      else if (it->x > m_EditBox[1]) m_EditBox[1] = it->x;
+
+      if (it->y < m_EditBox[2]) m_EditBox[2] = it->y;
+      else if (it->y > m_EditBox[3]) m_EditBox[3] = it->y;
+      }
+    }
+}
+
+void
+PolygonDrawingModel
+::DropLastPoint()
+{
+  if(m_State == DRAWING_STATE)
+    {
+    if(m_Vertices.size())
+      m_Vertices.pop_back();
+    InvokeEvent(StateMachineChangeEvent());
+    }
+}
+
+void
+PolygonDrawingModel
+::ClosePolygon()
+{
+  if(m_State == DRAWING_STATE)
+    {
+    SetState(EDITING_STATE);
+    m_SelectedVertices = true;
+
+    for(VertexIterator it = m_Vertices.begin(); it!=m_Vertices.end(); ++it)
+      it->selected = false;
+
+    ComputeEditBox();
+    InvokeEvent(StateMachineChangeEvent());
+    }
+}
+
+/**
+ * Delete()
+ *
+ * purpose:
+ * delete all vertices that are selected
+ *
+ * post:
+ * if all m_Vertices removed, m_State becomes INACTIVE_STATE
+ * length of m_Vertices array does not decrease
+ */
+void
+PolygonDrawingModel
+::Delete()
+{
+  VertexIterator it=m_Vertices.begin();
+  while(it!=m_Vertices.end())
+    {
+    if(it->selected)
+      it = m_Vertices.erase(it);
+    else ++it;
+    }
+
+  if (m_Vertices.empty())
+    {
+    SetState(INACTIVE_STATE);
+    m_SelectedVertices = false;
+    }
+
+  ComputeEditBox();
+  InvokeEvent(StateMachineChangeEvent());
+}
+
+void
+PolygonDrawingModel
+::Reset()
+{
+  SetState(INACTIVE_STATE);
+  m_Vertices.clear();
+  ComputeEditBox();
+  InvokeEvent(StateMachineChangeEvent());
+}
+
+/**
+ * Insert()
+ *
+ * purpose:
+ * insert vertices between adjacent selected vertices
+ *
+ * post:
+ * length of m_Vertices array does not decrease
+ */
+void
+PolygonDrawingModel
+::Insert()
+{
+  // Insert a vertex between every pair of adjacent vertices
+  VertexIterator it = m_Vertices.begin();
+  while(it != m_Vertices.end())
+    {
+    // Get the itNext iterator to point to the next point in the list
+    VertexIterator itNext = it;
+    if(++itNext == m_Vertices.end())
+      itNext = m_Vertices.begin();
+
+    // Check if the insertion is needed
+    if(it->selected && itNext->selected)
+      {
+      // Insert a new vertex
+      Vertex vNew(0.5 * (it->x + itNext->x), 0.5 * (it->y + itNext->y), true, true);
+      it = m_Vertices.insert(++it, vNew);
+      }
+
+    // On to the next point
+    ++it;
+    }
+  InvokeEvent(StateMachineChangeEvent());
+}
+
+int
+PolygonDrawingModel
+::GetNumberOfSelectedSegments()
+{
+  int isel = 0;
+  for(VertexIterator it = m_Vertices.begin(); it != m_Vertices.end(); it++)
+    {
+    // Get the itNext iterator to point to the next point in the list
+    VertexIterator itNext = it;
+    if(++itNext == m_Vertices.end())
+      itNext = m_Vertices.begin();
+
+    // Check if the insertion is needed
+    if(it->selected && itNext->selected)
+      isel++;
+    }
+  return isel;
+}
+
+void
+PolygonDrawingModel
+::ProcessFreehandCurve()
+{
+  // Special case: no fitting
+  if(m_FreehandFittingRate == 0.0)
+    {
+    for(VertexIterator it = m_DragVertices.begin();
+      it != m_DragVertices.end(); ++it)
+      {
+      m_Vertices.push_back(*it);
+      }
+    m_DragVertices.clear();
+    return;
+    }
+
+  // We will fit a b-spline of the 0-th order to the freehand curve
+  if(m_Vertices.size() > 0)
+    {
+    // Prepend the last vertex before freehand drawing
+    m_DragVertices.push_front(m_Vertices.back());
+    m_Vertices.pop_back();
+    }
+
+  // Create a list of input points
+  typedef itk::Vector<double, 2> VectorType;
+  typedef itk::Image<VectorType, 1> ImageType;
+  typedef itk::PointSet<VectorType, 1> PointSetType;
+  PointSetType::Pointer pointSet = PointSetType::New();
+
+  double len = 0;
+  double t = 0, dt = 1.0 / (m_DragVertices.size());
+  size_t i = 0;
+  Vertex last;
+  for(VertexIterator it = m_DragVertices.begin();
+    it != m_DragVertices.end(); ++it)
+    {
+    PointSetType::PointType point;
+    point[0] = t;
+    pointSet->SetPoint(i,point);
+    VectorType v;
+    v[0] = it->x; v[1] = it->y;
+    pointSet->SetPointData(i, v);
+    t+=dt; i++;
+    if(it != m_DragVertices.begin())
+      {
+      double dx = last.x - it->x;
+      double dy = last.y - it->y;
+      len += sqrt(dx * dx + dy * dy);
+      }
+    last = *it;
+    }
+
+  // Compute the number of control points
+  size_t nctl = (size_t)ceil(len / m_FreehandFittingRate);
+  if(nctl < 3)
+    nctl = 3;
+
+  // Compute the number of levels and the control points at coarsest level
+  size_t nl = 1; size_t ncl = nctl;
+  while(ncl >= 8)
+    { ncl >>= 1; nl++; }
+
+
+  // Create the scattered interpolator
+  typedef itk::BSplineScatteredDataPointSetToImageFilter<
+    PointSetType, ImageType> FilterType;
+  FilterType::Pointer filter = FilterType::New();
+
+  ImageType::SpacingType spacing; spacing.Fill( 0.001 );
+  ImageType::SizeType size; size.Fill((int)(1.0/spacing[0]));
+  ImageType::PointType origin; origin.Fill(0.0);
+
+  filter->SetSize( size );
+  filter->SetOrigin( origin );
+  filter->SetSpacing( spacing );
+  filter->SetInput( pointSet );
+  filter->SetSplineOrder( 1 );
+  FilterType::ArrayType ncps;
+  ncps.Fill(ncl);
+  filter->SetNumberOfLevels(nl);
+  filter->SetNumberOfControlPoints(ncps);
+  filter->SetGenerateOutputImage(false);
+
+  // Run the filter
+  filter->Update();
+
+  ImageType::Pointer lattice = filter->GetPhiLattice();
+  size_t n = lattice->GetBufferedRegion().GetNumberOfPixels();
+  for(size_t i = 0; i < n; i++)
+    {
+    ImageType::IndexType idx;
+    idx.Fill(i);
+    VectorType v = lattice->GetPixel(idx);
+    m_Vertices.push_back(Vertex(v[0],v[1],false,true));
+    }
+
+  /*
+
+  // Get the control points?
+  double du = 1.0 / nctl;
+  for(double u = 0; u < 1.00001; u += du)
+    {
+    if(u > 1.0) u = 1.0;
+    PointSetType::PointType point;
+    point[0] = u;
+    VectorType v;
+    filter->Evaluate(point,v);
+    m_Vertices.push_back(Vertex(v[0],v[1],false));
+    }
+    */
+
+  // Empty the drag list
+  // m_DragVertices.clear();
+}
+
+bool PolygonVertexTest(const PolygonVertex &v1, const PolygonVertex &v2)
+{
+  return v1.x == v2.x && v1.y == v2.y;
+}
+
+/**
+ * AcceptPolygon()
+ *
+ * purpose:
+ * to rasterize the current polygon into a buffer & copy the edited polygon
+ * into the polygon m_Cache
+ *
+ * parameters:
+ * buffer - an array of unsigned chars interpreted as an RGBA buffer
+ * width  - the width of the buffer
+ * height - the height of the buffer
+ *
+ * pre:
+ * buffer array has size width*height*4
+ * m_State == EDITING_STATE
+ *
+ * post:
+ * m_State == INACTIVE_STATE
+ */
+void
+PolygonDrawingModel
+::AcceptPolygon(std::vector<IRISWarning> &warnings)
+{
+  assert(m_State == EDITING_STATE);
+
+  // Allocate the polygon to match current image size. This will only
+  // allocate new memory if the slice size changed
+  itk::Size<2> sz =
+    {{ m_Parent->GetSliceSize()[0], m_Parent->GetSliceSize()[1] }};
+  m_PolygonSlice->SetRegions(sz);
+  m_PolygonSlice->Allocate();
+
+  // Remove duplicates from the vertex array
+  VertexIterator itEnd = std::unique(m_Vertices.begin(), m_Vertices.end(), PolygonVertexTest);
+  m_Vertices.erase(itEnd, m_Vertices.end());
+
+  // There may still be duplicates in the array, in which case we should
+  // add a tiny offset to them. Thanks to Jeff Tsao for this bug fix!
+  std::set< std::pair<float, float> > xVertexSet;
+  vnl_random rnd;
+  for(VertexIterator it = m_Vertices.begin(); it != m_Vertices.end(); ++it)
+    {
+    while(xVertexSet.find(make_pair(it->x, it->y)) != xVertexSet.end())
+      {
+      it->x += 0.0001 * rnd.drand32(-1.0, 1.0);
+      it->y += 0.0001 * rnd.drand32(-1.0, 1.0);
+      }
+    xVertexSet.insert(make_pair(it->x, it->y));
+    }
+
+  // Scan convert the points into the slice
+  typedef PolygonScanConvert<
+    unsigned char, GL_UNSIGNED_BYTE, VertexIterator> ScanConvertType;
+
+  ScanConvertType::RasterizeFilled(
+    m_Vertices.begin(), m_Vertices.size(), m_PolygonSlice);
+
+  // Apply the segmentation to the main segmentation
+  int nUpdates = m_Parent->MergeSliceSegmentation(m_PolygonSlice);
+  if(nUpdates == 0)
+    {
+    warnings.push_back(
+          IRISWarning("Warning: No voxels updated."
+                      "No voxels in the segmentation image were changed as the "
+                      "result of accepting this polygon. Check that the foreground "
+                      "and background labels are set correctly."));
+    }
+
+  // Copy polygon into polygon m_Cache
+  m_CachedPolygon = true;
+  m_Cache = m_Vertices;
+
+  // Reset the vertex array for next time
+  m_Vertices.clear();
+  m_SelectedVertices = false;
+
+  // Set the state
+  SetState(INACTIVE_STATE);
+  InvokeEvent(StateMachineChangeEvent());
+}
+
+/**
+ * PastePolygon()
+ *
+ * purpose:
+ * copy the m_Cached polygon to the edited polygon
+ *
+ * pre:
+ * m_CachedPolygon == 1
+ * m_State == INACTIVE_STATE
+ *
+ * post:
+ * m_State == EDITING_STATE
+ */
+void
+PolygonDrawingModel
+::PastePolygon(void)
+{
+  // Copy the cache into the vertices
+  m_Vertices = m_Cache;
+
+  // Select everything
+  for(VertexIterator it = m_Vertices.begin(); it!=m_Vertices.end();++it)
+    it->selected = false;
+
+  // Set the state
+  m_SelectedVertices = false;
+  SetState(EDITING_STATE);
+
+  // Compute the edit box
+  ComputeEditBox();
+  InvokeEvent(StateMachineChangeEvent());
+}
+
+
+/**
+ * Check if a click is within k pixels of a vertex, if so select the vertices
+ * of that line segment
+ */
+bool
+PolygonDrawingModel
+::CheckClickOnVertex(
+  float x, float y, float pixel_x, float pixel_y, int k)
+{
+  // check if clicked within 4 pixels of a node (use closest node)
+  VertexIterator itmin = m_Vertices.end();
+  double distmin = k;
+  for(VertexIterator it = m_Vertices.begin(); it!=m_Vertices.end(); ++it)
+    {
+    Vector2d A(it->x / pixel_x, it->y / pixel_y);
+    Vector2d C(x / pixel_x, y / pixel_y);
+    double dist = (A-C).inf_norm();
+
+    if(distmin > dist)
+      {
+      distmin = dist;
+      itmin = it;
+      }
+    }
+
+  if(itmin != m_Vertices.end())
+    {
+    itmin->selected = true;
+    return true;
+    }
+  else return false;
+}
+
+/**
+ * Check if a click is within k pixels of a line segment, if so select the vertices
+ * of that line segment
+ */
+bool
+PolygonDrawingModel
+::CheckClickOnLineSegment(
+  float x, float y, float pixel_x, float pixel_y, int k)
+{
+  // check if clicked near a line segment
+  VertexIterator itmin1 = m_Vertices.end(), itmin2 = m_Vertices.end();
+  double distmin = k;
+  for(VertexIterator it = m_Vertices.begin(); it!=m_Vertices.end(); ++it)
+    {
+    VertexIterator itnext = it;
+    if(++itnext == m_Vertices.end())
+      itnext = m_Vertices.begin();
+
+    Vector2d A(it->x / pixel_x, it->y / pixel_y);
+    Vector2d B(itnext->x / pixel_x, itnext->y / pixel_y);
+    Vector2d C(x / pixel_x, y / pixel_y);
+
+    double ab = (A - B).squared_magnitude();
+    if(ab > 0)
+      {
+      double alpha = - dot_product(A-B, B-C) / ab;
+      if(alpha > 0 && alpha < 1)
+        {
+        double dist = (alpha * A + (1-alpha) * B - C).magnitude();
+        if(distmin > dist)
+          {
+          distmin = dist;
+          itmin1 = it;
+          itmin2 = itnext;
+          }
+        }
+      }
+    }
+
+  if(itmin1 != m_Vertices.end())
+    {
+    itmin1->selected = true;
+    itmin2->selected = true;
+    return true;
+    }
+  else return false;
+}
+
+/* Can the polygon be closed? */
+bool
+PolygonDrawingModel
+::CanClosePolygon()
+{
+  return m_Vertices.size() > 2;
+}
+
+/* Can last point be dropped? */
+bool
+PolygonDrawingModel
+::CanDropLastPoint()
+{
+  return m_Vertices.size() > 0;
+}
+
+/* Can edges be split? */
+bool
+PolygonDrawingModel
+::CanInsertVertices()
+{
+  return GetNumberOfSelectedSegments() > 0;
+}
+
+void PolygonDrawingModel::SetState(PolygonDrawingModel::PolygonState state)
+{
+  if(m_State != state)
+    {
+    m_State = state;
+    InvokeEvent(StateMachineChangeEvent());
+    }
+}
+
+bool PolygonDrawingModel::CheckState(PolygonDrawingUIState state)
+{
+  switch(state)
+    {
+    case UIF_HAVE_VERTEX_SELECTION:
+      return this->GetSelectedVertices();
+    case UIF_HAVE_EDGE_SELECTION:
+      return this->CanInsertVertices();
+    case UIF_INACTIVE:
+      return m_State == INACTIVE_STATE;
+    case UIF_DRAWING:
+      return m_State == DRAWING_STATE;
+    case UIF_EDITING:
+      return m_State == EDITING_STATE;
+    case UIF_HAVEPOLYGON:
+      return m_Vertices.size() > 0;
+    case UIF_HAVECACHED:
+      return m_CachedPolygon;
+    }
+
+  return false;
+}
+
+
+
+
diff --git a/GUI/Model/PolygonDrawingModel.h b/GUI/Model/PolygonDrawingModel.h
new file mode 100644
index 0000000..612bd55
--- /dev/null
+++ b/GUI/Model/PolygonDrawingModel.h
@@ -0,0 +1,192 @@
+#ifndef POLYGONDRAWINGMODEL_H
+#define POLYGONDRAWINGMODEL_H
+
+#include "AbstractModel.h"
+#include <SNAPCommon.h>
+#include <IRISException.h>
+
+namespace itk {
+  template <class TPixel, unsigned int VDimensions> class Image;
+}
+
+class GenericSliceModel;
+
+
+struct PolygonVertex
+{
+  float x, y;
+  bool selected;
+  bool control;
+  PolygonVertex(float x_, float y_, bool on_, bool ctl_)
+    : x(x_), y(y_), selected(on_), control(ctl_) {}
+  PolygonVertex() : x(0.0f), y(0.0f), selected(false), control(true) {}
+  float &operator[](unsigned int i)
+  { return (i==0) ? x : y; }
+};
+
+enum PolygonDrawingUIState {
+  UIF_INACTIVE,
+  UIF_DRAWING,
+  UIF_EDITING,
+  UIF_HAVEPOLYGON,
+  UIF_HAVECACHED,
+  UIF_HAVE_VERTEX_SELECTION,
+  UIF_HAVE_EDGE_SELECTION
+};
+
+class PolygonDrawingModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(PolygonDrawingModel, AbstractModel)
+
+  FIRES(StateMachineChangeEvent)
+
+  irisSetMacro(Parent, GenericSliceModel *)
+  irisGetMacro(Parent, GenericSliceModel *)
+
+  /** Vertex structure */
+  typedef PolygonVertex Vertex;
+  typedef std::list<Vertex> VertexList;
+  typedef VertexList::iterator VertexIterator;
+  typedef VertexList::reverse_iterator VertexRIterator;
+
+  typedef vnl_vector_fixed<float, 4> BoxType;
+
+  /** States that the polygon drawing is in */
+  enum PolygonState { INACTIVE_STATE = 0, DRAWING_STATE, EDITING_STATE };
+
+  /** Render polygon onto a target image */
+  void AcceptPolygon(std::vector<IRISWarning> &warnings);
+
+  /** Copies cached polygon to current polygon */
+  void PastePolygon(void);
+
+  /** Deletes selected vertices */
+  void Delete();
+
+  /** Inserts vertices in selected edges */
+  void Insert();
+
+  /** Clears the drawing */
+  void Reset();
+
+  /** In drawing mode, remove the last point drawn */
+  void DropLastPoint();
+
+  /** In drawing mode, close the polygon (same as RMB) */
+  void ClosePolygon();
+
+  /** Can the polygon be closed? */
+  bool CanClosePolygon();
+
+  /** Can last point be dropped? */
+  bool CanDropLastPoint();
+
+  /** Can edges be split? */
+  bool CanInsertVertices();
+
+  /** Get the current state of the polygon editor */
+  irisGetMacro(State, PolygonState)
+
+  /** How many vertices are selected */
+  irisGetMacro(SelectedVertices,bool)
+
+  /** How many vertices are selected */
+  irisGetMacro(CachedPolygon,bool)
+
+  /** Set the accuracy of freehand curve fitting */
+  irisGetMacro(FreehandFittingRate, double)
+  irisSetMacro(FreehandFittingRate, double)
+
+  /** Access to the vertices */
+  irisGetMacro(Vertices, const VertexList &)
+  irisSetMacro(Vertices, const VertexList &)
+
+  /** Access to the vertices */
+  irisGetMacro(DragVertices, const VertexList &)
+  irisSetMacro(DragVertices, const VertexList &)
+
+  /** Current selection box */
+  irisGetMacro(SelectionBox, const BoxType &)
+
+  /** Current edit box */
+  irisGetMacro(EditBox, const BoxType &)
+
+  /** Are we dragging the selection box? */
+  irisIsMacro(DraggingPickBox)
+
+  /** Is the cursor hovering over the starting voxel */
+  irisIsMacro(HoverOverFirstVertex)
+
+  bool ProcessPushEvent(float x, float y, bool shift_state);
+
+  bool ProcessDragEvent(float x, float y);
+
+  bool ProcessMouseMoveEvent(float x, float y);
+
+  bool ProcessReleaseEvent(float x, float y);
+
+  Vector2f GetPixelSize();
+
+  bool CheckState(PolygonDrawingUIState state);
+
+protected:
+  PolygonDrawingModel();
+  virtual ~PolygonDrawingModel();
+
+  GenericSliceModel *m_Parent;
+
+  // Array of vertices, cached vertices from last operation
+
+  VertexList m_Vertices, m_Cache;
+  VertexList m_DragVertices;
+
+  // State of the system
+  PolygonState m_State;
+
+  bool m_CachedPolygon;
+  bool m_SelectedVertices;
+  bool m_DraggingPickBox;
+
+  // contains selected points
+  BoxType m_EditBox;
+
+  // box the user drags to select new points
+  BoxType m_SelectionBox;
+
+  float m_StartX, m_StartY;
+
+  // Whether we are hovering over the starting vertex
+  bool m_HoverOverFirstVertex;
+
+
+  void ComputeEditBox();
+  void Add(float x, float y, int selected);
+  void ProcessFreehandCurve();
+
+  bool CheckClickOnVertex(float x, float y,
+                          float pixel_x, float pixel_y, int k);
+
+  bool CheckClickOnLineSegment(float x, float y,
+                               float pixel_x, float pixel_y, int k);
+
+  // Check if the cursor (x,y) is near the first vertex (i.e., we should be
+  // closing the polygon)
+  bool CheckNearFirstVertex(float x, float y, float pixel_x, float pixel_y);
+
+  int GetNumberOfSelectedSegments();
+
+  void SetState(PolygonState state);
+
+  double m_FreehandFittingRate;
+
+  // Type definition for the slice used for polygon rendering
+  typedef itk::Image<unsigned char,2> PolygonSliceType;
+  typedef SmartPtr<PolygonSliceType> PolygonSlicePointer;
+
+  /** Slice used for polygon drawing and merging */
+  PolygonSlicePointer m_PolygonSlice;
+};
+
+#endif // POLYGONDRAWINGMODEL_H
diff --git a/GUI/Model/RandomAccessCollectionModel.cxx b/GUI/Model/RandomAccessCollectionModel.cxx
new file mode 100644
index 0000000..72ffdc7
--- /dev/null
+++ b/GUI/Model/RandomAccessCollectionModel.cxx
@@ -0,0 +1,2 @@
+#include "RandomAccessCollectionModel.h"
+
diff --git a/GUI/Model/RandomAccessCollectionModel.h b/GUI/Model/RandomAccessCollectionModel.h
new file mode 100644
index 0000000..c991d7f
--- /dev/null
+++ b/GUI/Model/RandomAccessCollectionModel.h
@@ -0,0 +1,242 @@
+#ifndef RANDOMACCESSCOLLECTIONMODEL_H
+#define RANDOMACCESSCOLLECTIONMODEL_H
+
+#include <PropertyModel.h>
+#include <IRISException.h>
+#include <Registry.h>
+
+template <class TKey, class TItem>
+class StandardMapContainerTraits
+{
+public:
+  typedef TKey KeyType;
+  typedef TItem ItemType;
+  typedef std::map<TKey, TItem> ContainerType;
+  typedef ContainerType * ContainerPointer;
+  typedef typename ContainerType::iterator Iterator;
+
+  static Iterator begin(ContainerType *p)
+  {
+    return p->begin();
+  }
+
+  static Iterator end(ContainerType *p)
+  {
+    return p->end();
+  }
+
+  static KeyType key(ContainerType *p, Iterator &it)
+  {
+    return it->first;
+  }
+
+  static TItem value(ContainerType *p, Iterator &it)
+  {
+    return it->second;
+  }
+
+  static Iterator find(ContainerType *p, KeyType key)
+  {
+    return p->find(key);
+  }
+};
+
+template <class TItem>
+class StandardVectorContainerTraits
+{
+public:
+  typedef unsigned int KeyType;
+  typedef TItem ItemType;
+  typedef std::vector<TItem> ContainerType;
+  typedef ContainerType * ContainerPointer;
+  typedef typename ContainerType::iterator Iterator;
+
+  static Iterator begin(ContainerType *p)
+  {
+    return p->begin();
+  }
+
+  static Iterator end(ContainerType *p)
+  {
+    return p->end();
+  }
+
+  static KeyType key(ContainerType *p, Iterator &it)
+  {
+    return it - p->begin();
+  }
+
+  static TItem value(ContainerType *p, Iterator &it)
+  {
+    return *it;
+  }
+
+  static Iterator find(ContainerType *p, KeyType key)
+  {
+    return p->begin() + key;
+  }
+};
+
+template<class TContainerTraits>
+class RandomAccessCollectionNullFilter
+{
+public:
+  typedef typename TContainerTraits::KeyType KeyType;
+  typedef typename TContainerTraits::ItemType ItemType;
+  bool Check(KeyType &key, ItemType &item) { return true; }
+};
+
+/**
+  This class exposes an indexed collection of items (map/vector) as a random
+  access list. This makes it possible to couple this collection with GUI widgets
+  such as lists, combo boxes, etc. Internally, the model caches an array of indices
+  into the source list. If the source collection changes, the model must be notified
+  with an event so that the cache can be rebuilt.
+*/
+template <class TContainerTraits,
+          class TFilter = RandomAccessCollectionNullFilter<TContainerTraits> >
+class RandomAccessCollectionModel
+    : public AbstractRandomAccessCollectionModel<typename TContainerTraits::ItemType>
+{
+public:
+
+  // They key/item types
+  typedef typename TContainerTraits::KeyType KeyType;
+  typedef typename TContainerTraits::ItemType ItemType;
+
+  // ITK typedefs
+  typedef RandomAccessCollectionModel<TContainerTraits, TFilter> Self;
+  typedef AbstractRandomAccessCollectionModel<ItemType> Superclass;
+  typedef SmartPtr<Self> Pointer;
+  typedef SmartPtr<const Self> ConstPointer;
+
+  itkTypeMacro(RandomAccessCollectionModel,
+               AbstractRandomAccessCollectionModel)
+
+  itkNewMacro(Self)
+
+  // The type of the source array
+  typedef typename TContainerTraits::ContainerPointer ContainerPointer;
+
+  RandomAccessCollectionModel()
+  {
+    m_Filter = NULL;
+    m_SourceContainer = NULL;
+  }
+
+  void SetSourceContainer(ContainerPointer p)
+  {
+    if(p != m_SourceContainer)
+      {
+      m_SourceContainer = p;
+      m_ArrayDirty = true;
+      }
+  }
+
+  void SetFilter(TFilter *filter)
+  {
+    if(filter != m_Filter)
+      {
+      m_Filter = filter;
+      m_ArrayDirty = true;
+      }
+  }
+
+  // Number of items in the collection
+  unsigned int GetSize()
+  {
+    // Respond to accumulated events
+    this->Update();
+
+    // If the cache is dirty, rebuild it
+    if(m_ArrayDirty)
+      RebuildArray();
+
+    // Return the cached array size
+    return m_Array.size();
+  }
+
+  // Access to the elements
+  ItemType operator[](unsigned int n)
+  {
+    // Respond to accumulated events
+    this->Update();
+
+    // If the cache is dirty, rebuild it
+    if(m_ArrayDirty)
+      RebuildArray();
+
+    // Get the item
+    typename TContainerTraits::Iterator it =
+        TContainerTraits::find(m_SourceContainer, m_Array[n]);
+    if(it == TContainerTraits::end(m_SourceContainer))
+      throw IRISException("Access violation in RandomAccessCollectionModel");
+    return TContainerTraits::value(m_SourceContainer, it);
+  }
+
+protected:
+
+  // Rebuild the array (in response to an event(
+  void RebuildArray()
+  {
+    m_Array.clear();
+    typename TContainerTraits::Iterator it;
+    for(it = TContainerTraits::begin(m_SourceContainer);
+        it != TContainerTraits::end(m_SourceContainer);
+        ++it)
+      {
+      // What is the key for this iterator?
+      KeyType key = TContainerTraits::key(m_SourceContainer, it);
+
+      // Apply filter!
+      if(m_Filter)
+        {
+        ItemType item = TContainerTraits::value(m_SourceContainer, it);
+        if(m_Filter->Check(key, item))
+          m_Array.push_back(key);
+        }
+      else
+        m_Array.push_back(key);
+      }
+
+    m_ArrayDirty = false;
+  }
+
+  virtual void OnUpdate()
+  {
+    // If any event has been received, dirty the cache
+    m_ArrayDirty = true;
+  }
+
+  // Pointer to the source array
+  ContainerPointer m_SourceContainer;
+
+  // Filter, if present
+  TFilter *m_Filter;
+
+  // Cached array of indices into the source array
+  std::vector<KeyType> m_Array;
+
+  // Whether the array is dirty, needs to be rebuilt
+  bool m_ArrayDirty;
+};
+
+/**
+  Factory object to create a model wrapping around an existing STL array
+  */
+template<class TItem>
+SmartPtr<AbstractRandomAccessCollectionModel<TItem> >
+newRandomAccessContainerModel(std::vector<TItem> &vec)
+{
+  typedef AbstractRandomAccessCollectionModel<TItem> AbstractModelType;
+  typedef StandardVectorContainerTraits<TItem> TraitsType;
+  typedef RandomAccessCollectionModel<TraitsType> ModelType;
+  typename ModelType::Pointer model = ModelType::New();
+  model->SetSourceContainer(&vec);
+
+  SmartPtr<AbstractModelType> retptr(model);
+  return retptr;
+}
+
+
+#endif // RANDOMACCESSCOLLECTIONMODEL_H
diff --git a/GUI/Model/RegistryEntryPropertyModel.h b/GUI/Model/RegistryEntryPropertyModel.h
new file mode 100644
index 0000000..46d5ee4
--- /dev/null
+++ b/GUI/Model/RegistryEntryPropertyModel.h
@@ -0,0 +1,75 @@
+#ifndef REGISTRYENTRYPROPERTYMODEL_H
+#define REGISTRYENTRYPROPERTYMODEL_H
+
+#include "PropertyModel.h"
+#include "Registry.h"
+
+/**
+ * A model encapsulating a registry entry. The registry mechanism does not
+ * support metadata, so the registry entry can only store the data itself.
+ * The domain is supplied by the user.
+ */
+template <class TVal, class TDomain>
+class RegistryEntryPropertyModel
+    : public AbstractModel<TVal, TDomain>
+{
+public:
+
+  // Standard ITK stuff (can't use irisITKObjectMacro because of two template
+  // parameters, comma breaks the macro).
+  typedef RegistryEntryPropertyModel<TVal, TDomain> Self;
+  typedef AbstractPropertyModel<TVal, TDomain> Superclass;
+  typedef SmartPtr<Self> Pointer;
+  typedef SmartPtr<const Self> ConstPointer;
+
+  itkTypeMacro(RegistryEntryPropertyModel, AbstractPropertyModel)
+  itkNewMacro(Self)
+
+  /**
+   * Initialize the model with a pointer to the registry (which must remain
+   * valid), the key, and a default value for the property
+   */
+  void Initialize(Registry *registry, const char *key, TVal deflt)
+  {
+    m_Registry = registry;
+    m_Key = key;
+    m_DefaultValue = deflt;
+
+    // Listen to events from the corresponding folder (how)
+  }
+
+  irisSetWithEventMacro(Domain, TDomain, DomainChangedEvent)
+
+  virtual bool GetValueAndDomain(TVal &value, TDomain *domain)
+  {
+    if(!m_Registry) return false;
+
+    value = (*m_Registry)[m_Key][m_DefaultValue];
+    if(domain)
+      *domain = m_Domain;
+
+    return true;
+  }
+
+  virtual void SetValue(TVal value)
+  {
+    assert(m_Registry);
+    (*m_Registry)[m_Key] << value;
+  }
+
+protected:
+
+  // The registry
+  Registry *m_Registry;
+
+  // Key
+  const char *m_Key;
+
+  // Default value
+  TVal m_DefaultValue;
+
+  // The domain is stored in the model
+  TDomain m_Domain;
+};
+
+#endif // REGISTRYENTRYPROPERTYMODEL_H
diff --git a/GUI/Model/ReorientImageModel.cxx b/GUI/Model/ReorientImageModel.cxx
new file mode 100644
index 0000000..fbfb284
--- /dev/null
+++ b/GUI/Model/ReorientImageModel.cxx
@@ -0,0 +1,332 @@
+#include "ReorientImageModel.h"
+#include "GlobalUIModel.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "GenericSliceModel.h"
+
+
+
+
+ReorientImageModel::ReorientImageModel()
+{
+  // Initialized cached values
+  m_CurrentRAIValue = "";
+  m_CurrentOrientationIsOblique = false;
+
+  // Create the sub-models
+  m_NewRAICodeModel = ConcreteSimpleStringProperty::New();
+  m_NewRAICodeModel->SetValue("");
+
+  m_CurrentRAICodeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetCurrentRAICodeValue);
+
+  m_InvalidStatusModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetInvalidStatusValue);
+
+  // Invalid status model listens to changes to the new RAI model
+  m_InvalidStatusModel->Rebroadcast(m_NewRAICodeModel,
+                                    ValueChangedEvent(), ValueChangedEvent());
+
+  // Changes to the new RAI model are rebroadcast as state change events
+  // for the widget activation system
+  Rebroadcast(m_NewRAICodeModel, ValueChangedEvent(),
+              StateMachineChangeEvent());
+
+  // Create the axis direction models
+  for(int axis = 0; axis < 3; axis++)
+    {
+    m_NewAxisDirectionModel[axis] = wrapIndexedGetterSetterPairAsProperty(
+          this, axis,
+          &Self::GetNthNewAxisDirectionValueAndDomain,
+          &Self::SetNthNewAxisDirectionValue);
+
+    m_NewAxisDirectionModel[axis]->Rebroadcast(
+          m_NewRAICodeModel, ValueChangedEvent(), ValueChangedEvent());
+
+    m_NewAxisDirectionModel[axis]->Rebroadcast(
+          m_NewRAICodeModel, ValueChangedEvent(), DomainChangedEvent());
+
+    m_CurrentAxisDirectionModel[axis] = wrapIndexedGetterSetterPairAsProperty(
+          this, axis,
+          &Self::GetNthCurrentAxisDirectionValue);
+    }
+
+  // The current NIFTI matrix
+  m_CurrentWorldMatrixModel = ConcreteMatrixProperty::New();
+
+  // The current direction matrix
+  m_CurrentDirectionMatrixModel = ConcreteMatrixProperty::New();
+
+  // The new NIFTI matrix
+  m_NewWorldMatrixModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetNewWorldMatrixValue);
+
+  m_NewWorldMatrixModel->Rebroadcast(
+        m_NewRAICodeModel, ValueChangedEvent(), ValueChangedEvent());
+
+  // The new NIFTI matrix
+  m_NewDirectionMatrixModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetNewDirectionMatrixValue);
+
+  m_NewDirectionMatrixModel->Rebroadcast(
+        m_NewRAICodeModel, ValueChangedEvent(), ValueChangedEvent());
+}
+
+/** Initialize with the parent model */
+void ReorientImageModel::SetParentModel(GlobalUIModel *parent)
+{
+  // Store the model
+  m_Parent = parent;
+
+  // Listen to changes to the main image
+  Rebroadcast(m_Parent->GetDriver(),
+              MainImageDimensionsChangeEvent(), ModelUpdateEvent());
+
+  // Listen to changes to the main image
+  Rebroadcast(m_Parent->GetDriver(),
+              MainImagePoseChangeEvent(), ModelUpdateEvent());
+}
+
+AbstractSimpleStringProperty
+*ReorientImageModel::GetCurrentAxisDirectionModel(int axis) const
+{
+  return m_CurrentAxisDirectionModel[axis];
+}
+
+ReorientImageModel::AbstractAxisDirectionProperty
+*ReorientImageModel::GetNewAxisDirectionModel(int axis) const
+{
+  return m_NewAxisDirectionModel[axis];
+}
+
+void ReorientImageModel::ApplyCurrentRAI()
+{
+  IRISApplication *driver = m_Parent->GetDriver();
+
+  // Check that the current RAI is valid
+  std::string rai = this->m_NewRAICodeModel->GetValue();
+  assert(ImageCoordinateGeometry::IsRAICodeValid(rai.c_str()));
+
+  // Convert the rai code to a direction matrix
+  ImageCoordinateGeometry::DirectionMatrix dm =
+      ImageCoordinateGeometry::ConvertRAICodeToDirectionMatrix(rai);
+
+  // Set the direction in the image
+  driver->ReorientImage(dm);
+
+  // Tell the display slices to reinitialize
+  for(int i = 0; i < 3; i++)
+    {
+    m_Parent->GetSliceModel(i)->InitializeSlice(driver->GetCurrentImageData());
+    }
+}
+
+void ReorientImageModel::ReverseAxisDirection(int axis)
+{
+  AxisDirection dir;
+  bool valid = m_NewAxisDirectionModel[axis]->GetValueAndDomain(dir, NULL);
+  if(valid)
+    {
+    AxisDirection reverse =
+        static_cast<AxisDirection>(- static_cast<int>(dir));
+    m_NewAxisDirectionModel[axis]->SetValue(reverse);
+    }
+}
+
+bool ReorientImageModel::CheckState(ReorientImageModel::UIState state)
+{
+  AxisDirection dummy;
+  switch(state)
+    {
+    case UIF_IMAGE_LOADED:
+      return m_Parent->GetDriver()->IsMainImageLoaded();
+    case UIF_VALID_NEW_RAI:
+      {
+      std::string rai = this->m_NewRAICodeModel->GetValue();
+      return ImageCoordinateGeometry::IsRAICodeValid(rai.c_str());
+      }
+    case UIF_VALID_AXIS_DIRECTION_X:
+      return GetNthNewAxisDirectionValueAndDomain(0, dummy, NULL);
+    case UIF_VALID_AXIS_DIRECTION_Y:
+      return GetNthNewAxisDirectionValueAndDomain(1, dummy, NULL);
+    case UIF_VALID_AXIS_DIRECTION_Z:
+      return GetNthNewAxisDirectionValueAndDomain(2, dummy, NULL);
+    default: return false;
+    }
+}
+
+
+bool ReorientImageModel::GetCurrentRAICodeValue(std::string &value)
+{
+  if(m_CurrentRAIValue.size())
+    {
+    value = m_CurrentOrientationIsOblique
+        ? std::string("Oblique (closest to ") + m_CurrentRAIValue + std::string(")")
+        : m_CurrentRAIValue;
+    return true;
+    }
+  else
+    return false;
+}
+
+bool ReorientImageModel
+::GetNthCurrentAxisDirectionValue(int axis, std::string &value)
+{
+  // Get the current rai code value
+  if(m_CurrentRAIValue.size())
+    {
+    char letter = m_CurrentRAIValue[axis];
+    AxisDirection dir =
+        ImageCoordinateGeometry::ConvertRAILetterToAxisDirection(letter);
+    std::string dirstr
+        = ImageCoordinateGeometry::GetAxisDirectionDescriptionMap()[dir];
+    value = m_CurrentOrientationIsOblique
+        ? std::string("Oblique (appr. ") + dirstr + std::string(")")
+        : dirstr;
+    return true;
+    }
+  else
+    return false;
+}
+
+
+bool ReorientImageModel::GetInvalidStatusValue(std::string &value)
+{
+  // Check that the current RAI is valid
+  std::string rai = this->m_NewRAICodeModel->GetValue();
+  if(ImageCoordinateGeometry::IsRAICodeValid(rai.c_str()))
+    value = "";
+  else
+    value = "Invalid RAI code";
+  return true;
+}
+
+
+bool ReorientImageModel
+::GetNthNewAxisDirectionValueAndDomain(
+    int axis,
+    AxisDirection &value,
+    AxisDirectionDomain *domain)
+{
+  // Check that the current RAI is 'sort of' valid
+  std::string rai = this->m_NewRAICodeModel->GetValue();
+
+  // Make sure that the rai is long enough for us to process
+  if(rai.size() <= axis)
+    return false;
+
+  // Make sure that the letter in the RAI is a valid letter
+  value = ImageCoordinateGeometry::ConvertRAILetterToAxisDirection(rai[axis]);
+
+  // Is this a valid direction?
+  if(value == ImageCoordinateGeometry::INVALID_DIRECTION)
+    return false;
+
+  // Now deal with the domain
+  if(domain)
+    {
+    domain->SetWrappedMap(
+          &ImageCoordinateGeometry::GetAxisDirectionDescriptionMap());
+    }
+
+  return true;
+}
+
+void ReorientImageModel
+::SetNthNewAxisDirectionValue(int axis, AxisDirection value)
+{
+  // Get the letter for the direction
+  char letter = ImageCoordinateGeometry::ConvertAxisDirectionToRAILetter(value);
+
+  // Make sure the RAI code is long enough for the letter to fit
+  std::string rai = this->m_NewRAICodeModel->GetValue();
+  while(rai.size() <= axis)
+    rai.append(" ");
+
+  // Set the letter in the RAI code
+  rai[axis] = letter;
+
+  // Set the rai string in the model
+  m_NewRAICodeModel->SetValue(rai);
+}
+
+bool ReorientImageModel
+::GetNewWorldMatrixValue(ReorientImageModel::WorldMatrix &value)
+{
+  // Get the RAI
+  std::string rai = this->m_NewRAICodeModel->GetValue();
+  if(!ImageCoordinateGeometry::IsRAICodeValid(rai.c_str()))
+    return false;
+
+  // Get the direction matrix
+  ImageCoordinateGeometry::DirectionMatrix dm
+      = ImageCoordinateGeometry::ConvertRAICodeToDirectionMatrix(rai);
+
+  ImageWrapperBase *im = m_Parent->GetDriver()->GetCurrentImageData()->GetMain();
+  value = ImageWrapperBase::ConstructNiftiSform(
+      dm,
+      im->GetImageBase()->GetOrigin().GetVnlVector(),
+        im->GetImageBase()->GetSpacing().GetVnlVector());
+
+  return true;
+}
+
+bool ReorientImageModel
+::GetNewDirectionMatrixValue(ReorientImageModel::WorldMatrix &value)
+{
+  // Get the RAI
+  std::string rai = this->m_NewRAICodeModel->GetValue();
+  if(!ImageCoordinateGeometry::IsRAICodeValid(rai.c_str()))
+    return false;
+
+  // Get the direction matrix
+  value = ImageCoordinateGeometry::ConvertRAICodeToDirectionMatrix(rai);
+  return true;
+}
+
+void ReorientImageModel::OnUpdate()
+{
+  if(this->m_EventBucket->HasEvent(MainImageDimensionsChangeEvent())
+     || this->m_EventBucket->HasEvent(MainImagePoseChangeEvent()))
+    {    
+    // Obtain the current RAI value
+    IRISApplication *app = m_Parent->GetDriver();
+    if(app->IsMainImageLoaded())
+      {
+      // Get teh RAI value
+      m_CurrentRAIValue = app->GetImageToAnatomyRAI();
+
+      // Get the obliqueness
+      m_CurrentOrientationIsOblique = app->IsImageOrientationOblique();
+
+      // Get the direction matrix
+      ImageWrapperBase *mainImage = app->GetCurrentImageData()->GetMain();
+      WorldMatrix dm = mainImage->GetImageBase()->GetDirection().GetVnlMatrix();
+
+      m_CurrentDirectionMatrixModel->SetIsValid(true);
+      m_CurrentDirectionMatrixModel->SetValue(dm);
+
+      // Get the NIFTI matrix
+      WorldMatrix mw = mainImage->GetNiftiSform();
+
+      m_CurrentWorldMatrixModel->SetIsValid(true);
+      m_CurrentWorldMatrixModel->SetValue(mw);
+      }
+    else
+      {
+      m_CurrentRAIValue = "";
+      m_CurrentWorldMatrixModel->SetIsValid(false);
+      m_CurrentDirectionMatrixModel->SetIsValid(false);
+      }
+
+    // Set it as the new RAI value
+    m_NewRAICodeModel->SetValue(m_CurrentRAIValue);
+    }
+}
+
+
diff --git a/GUI/Model/ReorientImageModel.h b/GUI/Model/ReorientImageModel.h
new file mode 100644
index 0000000..93b40d8
--- /dev/null
+++ b/GUI/Model/ReorientImageModel.h
@@ -0,0 +1,145 @@
+#ifndef REORIENTIMAGEMODEL_H
+#define REORIENTIMAGEMODEL_H
+
+#include <AbstractModel.h>
+#include <PropertyModel.h>
+#include <ImageCoordinateGeometry.h>
+
+class GlobalUIModel;
+
+/**
+ * @brief The ReorientImageModel class
+ * Model for the reorient dialog
+ */
+class ReorientImageModel : public AbstractModel
+{
+public:
+
+  // A representation for an axis-direction pair
+  typedef ImageCoordinateGeometry::AxisDirection AxisDirection;
+  typedef STLMapWrapperItemSetDomain<AxisDirection, std::string> AxisDirectionDomain;
+  typedef AbstractPropertyModel<AxisDirection, AxisDirectionDomain>
+    AbstractAxisDirectionProperty;
+
+  // A model encapsulating the 4x4 NIFTI matrix
+  typedef vnl_matrix<double> WorldMatrix;
+  typedef AbstractPropertyModel<WorldMatrix> AbstractMatrixProperty;
+  typedef ConcretePropertyModel<WorldMatrix> ConcreteMatrixProperty;
+
+  // Standard ITK stuff
+  irisITKObjectMacro(ReorientImageModel, AbstractModel)
+
+  /** Initialize with the parent model */
+  void SetParentModel(GlobalUIModel *parent);
+
+  /** A model for the current RAI field */
+  irisGetMacro(NewRAICodeModel, AbstractSimpleStringProperty *)
+
+  /** A model for the current RAI field */
+  irisGetMacro(CurrentRAICodeModel, AbstractSimpleStringProperty *)
+
+  /** A model for the invalid status */
+  irisGetMacro(InvalidStatusModel, AbstractSimpleStringProperty *)
+
+  /** Models for the current direction of the three coordinate axes */
+  AbstractSimpleStringProperty *GetCurrentAxisDirectionModel(int axis) const;
+
+  /** Models for the new direction of the three coordinate axes */
+  AbstractAxisDirectionProperty *GetNewAxisDirectionModel(int axis) const;
+
+  /** Model for the current NIFTI matrix */
+  irisGetMacro(CurrentWorldMatrixModel, AbstractMatrixProperty *)
+
+  /** Model for the new NIFTI matrix */
+  irisGetMacro(NewWorldMatrixModel, AbstractMatrixProperty *)
+
+  /** Model for the current ITK Direction matrix */
+  irisGetMacro(CurrentDirectionMatrixModel, AbstractMatrixProperty *)
+
+  /** Model for the new ITK Direction matrix */
+  irisGetMacro(NewDirectionMatrixModel, AbstractMatrixProperty *)
+
+  /** Apply current RAI code to the image */
+  void ApplyCurrentRAI();
+
+  /** Reverse the direction of one of the axes */
+  void ReverseAxisDirection(int axis);
+
+  /**
+    States in which the model can be, which allow the activation and
+    deactivation of various widgets in the interface
+    */
+  enum UIState {
+    UIF_IMAGE_LOADED,
+    UIF_VALID_NEW_RAI,
+    UIF_VALID_AXIS_DIRECTION_X,
+    UIF_VALID_AXIS_DIRECTION_Y,
+    UIF_VALID_AXIS_DIRECTION_Z
+  };
+
+  /**
+    Check the state flags above
+    */
+  bool CheckState(UIState state);
+
+protected:
+
+  // Constructor
+  ReorientImageModel();
+  virtual ~ReorientImageModel() {}
+
+  // Model for the new RAI code
+  SmartPtr<ConcreteSimpleStringProperty> m_NewRAICodeModel;
+
+  // Model for the current RAI code
+  SmartPtr<AbstractSimpleStringProperty> m_CurrentRAICodeModel;
+  bool GetCurrentRAICodeValue(std::string &value);
+
+  // Model for the error message
+  SmartPtr<AbstractSimpleStringProperty> m_InvalidStatusModel;
+  bool GetInvalidStatusValue(std::string &value);
+
+  // Models for the three current axis directions
+  SmartPtr<AbstractSimpleStringProperty> m_CurrentAxisDirectionModel[3];
+  bool GetNthCurrentAxisDirectionValue(int axis, std::string &value);
+
+  // Models for the three new axis directions
+  SmartPtr<AbstractAxisDirectionProperty> m_NewAxisDirectionModel[3];
+
+  bool GetNthNewAxisDirectionValueAndDomain(
+      int axis, AxisDirection &value, AxisDirectionDomain *domain);
+
+  void SetNthNewAxisDirectionValue(int axis, AxisDirection value);
+
+  // Current world matrix
+  SmartPtr<ConcreteMatrixProperty> m_CurrentWorldMatrixModel;
+
+  // Current direction matrix
+  SmartPtr<ConcreteMatrixProperty> m_CurrentDirectionMatrixModel;
+
+  // New world matrix
+  SmartPtr<AbstractMatrixProperty> m_NewWorldMatrixModel;
+  bool GetNewWorldMatrixValue(WorldMatrix &value);
+
+  // New direction matrix
+  SmartPtr<AbstractMatrixProperty> m_NewDirectionMatrixModel;
+  bool GetNewDirectionMatrixValue(WorldMatrix &value);
+
+  // Respond to events received by the model
+  virtual void OnUpdate();
+
+  // The parent model
+  GlobalUIModel *m_Parent;
+
+  // The current RAI of the loaded image. This is updated in the OnUpdate
+  // method, and is equal to the GetImageToAnatomyRAI in IRISApplication.
+  // We keep a copy of this value to avoid unnecessary computation of the RAI
+  // in response to widget events.
+  std::string m_CurrentRAIValue;
+
+  // Whether the current rai value is oblique
+  bool m_CurrentOrientationIsOblique;
+
+};
+
+#endif // REORIENTIMAGEMODEL_H
diff --git a/GUI/Model/SNAPUIFlag.h b/GUI/Model/SNAPUIFlag.h
new file mode 100644
index 0000000..aecb155
--- /dev/null
+++ b/GUI/Model/SNAPUIFlag.h
@@ -0,0 +1,79 @@
+#ifndef SNAPUIFLAG_H
+#define SNAPUIFLAG_H
+
+#include "StateManagement.h"
+#include "UIState.h"
+#include "SNAPEventListenerCallbacks.h"
+
+class GlobalUIModel;
+
+/**
+  A BooleanCondition implementation that queries a TModel about different
+  UI states of type TStateEnum. The Model must implement a function
+  bool CheckState(TStateEnum state), which is called to check the state.
+  The model must also fire an event StateMachineChangeEvent() in order
+  for the activation machinery to work.
+
+  The implementation of this class is in a .txx file to allow use with
+  not yet known Models and Enums.
+  */
+template<class TModel, class TStateEnum>
+class SNAPUIFlag : public BooleanCondition
+{
+public:
+  typedef SNAPUIFlag<TModel, TStateEnum> Self;
+  typedef BooleanCondition Superclass;
+  itkTypeMacro(Self, Superclass)
+
+  static SmartPtr<Self> New(TModel *model, TStateEnum state)
+  {
+    SmartPtr<Self> p = new Self(model, state);
+    p->UnRegister();
+    return p;
+  }
+
+  bool operator() () const
+  {
+    if(m_Model)
+      return m_Model->CheckState(m_State);
+    else return false;
+  }
+
+protected:
+
+  SNAPUIFlag(TModel *model, TStateEnum state)
+  {
+    m_Model = model;
+    m_State = state;
+
+    m_Tag = AddListener<Self>(
+          m_Model, StateMachineChangeEvent(),
+          this, &Self::OnStateChange);
+
+    m_DeleteTag = AddListener<Self>(
+          m_Model, itk::DeleteEvent(),
+          this, &Self::OnModelDeletion);
+  }
+
+  virtual ~SNAPUIFlag()
+  {
+    if(m_Model)
+      {
+      m_Model->RemoveObserver(m_Tag);
+      m_Model->RemoveObserver(m_DeleteTag);
+      }
+  }
+
+  virtual void OnModelDeletion()
+  {
+    m_Model = NULL;
+  }
+
+
+private:
+  TModel *m_Model;
+  TStateEnum m_State;
+  unsigned long m_Tag, m_DeleteTag;
+};
+
+#endif // SNAPUIFLAG_H
diff --git a/GUI/Model/SNAPUIFlag.txx b/GUI/Model/SNAPUIFlag.txx
new file mode 100644
index 0000000..e69de29
diff --git a/GUI/Model/SaveModifiedLayersModel.cxx b/GUI/Model/SaveModifiedLayersModel.cxx
new file mode 100644
index 0000000..8ea31b9
--- /dev/null
+++ b/GUI/Model/SaveModifiedLayersModel.cxx
@@ -0,0 +1,301 @@
+#include "SaveModifiedLayersModel.h"
+#include "ImageWrapperBase.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "IRISImageData.h"
+#include "ImageIODelegates.h"
+
+
+bool AbstractSaveableItem::IsSaveable()
+{
+  for(DependencyList::iterator it = m_Dependencies.begin(); it != m_Dependencies.end(); ++it)
+    if((*it)->NeedsDecision())
+      return false;
+  return true;
+}
+
+void AbstractSaveableItem::AddDependency(AbstractSaveableItem *dep)
+{
+  m_Dependencies.push_back(dep);
+}
+
+
+
+
+
+void ImageLayerSaveableItem
+::Initialize(SaveModifiedLayersModel *model, ImageWrapperBase *wrapper, LayerRole role)
+{
+  m_Model = model;
+  m_Wrapper = wrapper;
+  m_Role = role;
+}
+
+std::string ImageLayerSaveableItem::GetDescription() const
+{
+  if(m_Wrapper->GetCustomNickname().length())
+    return m_Wrapper->GetCustomNickname();
+  else
+    return m_Wrapper->GetDefaultNickname();
+}
+
+std::string ImageLayerSaveableItem::GetFilename() const
+{
+  return m_Wrapper->GetFileName();
+}
+
+bool ImageLayerSaveableItem::IsSaved()
+{
+  return !m_Wrapper->HasUnsavedChanges();
+}
+
+bool ImageLayerSaveableItem::Save(AbstractSaveModifiedLayersInteractionDelegate *cb_delegate)
+{
+  // Create a delegate for saving this image
+  return cb_delegate->SaveImageLayer(m_Model->GetParentModel(), m_Wrapper, m_Role);
+}
+
+bool ImageLayerSaveableItem::RequiresInteraction()
+{
+  return GetFilename().size() == 0;
+}
+
+
+
+
+
+void WorkspaceSaveableItem::Initialize(SaveModifiedLayersModel *model)
+{
+  m_Model = model;
+  m_Saved = false;
+}
+
+std::string WorkspaceSaveableItem::GetDescription() const
+{
+  return std::string("Workspace");
+}
+
+std::string WorkspaceSaveableItem::GetFilename() const
+{
+  return m_Model->GetParentModel()->GetGlobalState()->GetProjectFilename();
+}
+
+bool WorkspaceSaveableItem::IsSaved()
+{
+  return m_Saved;
+}
+
+bool WorkspaceSaveableItem::Save(AbstractSaveModifiedLayersInteractionDelegate *cb_delegate)
+{
+  m_Saved = cb_delegate->SaveProject(m_Model->GetParentModel());
+  return m_Saved;
+}
+
+bool WorkspaceSaveableItem::RequiresInteraction()
+{
+  return this->GetFilename().size() == 0;
+}
+
+
+
+
+
+
+
+SaveModifiedLayersModel::SaveModifiedLayersModel()
+{
+  m_CurrentItemModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetCurrentItemValue, &Self::SetCurrentItemValue);
+
+  m_CurrentItem = 0;
+}
+
+bool SaveModifiedLayersModel::GetCurrentItemValue(int &out_value)
+{
+  out_value = m_CurrentItem;
+  return true;
+}
+
+void SaveModifiedLayersModel::SetCurrentItemValue(int value)
+{
+  m_CurrentItem = value;
+
+  // Do something?
+  InvokeEvent(StateMachineChangeEvent());
+}
+
+void SaveModifiedLayersModel::BuildUnsavedItemsList(std::list<ImageWrapperBase *> layers)
+{
+  // Clear the list
+  m_UnsavedItems.clear();
+
+  // Get the list of all the layers that are applicable. Notice that we only
+  // consider the IRIS image data, we don't support saving of layers from
+  // SNAP mode. This might change in the future.
+  GenericImageData *gid = m_ParentModel->GetDriver()->GetIRISImageData();
+
+  // Are there any layers without filenames
+  bool flag_unnamed_layers = false;
+
+  // Is the main image layer included (i.e., the workspace is being closed)
+  bool flag_main_included = false;
+
+  // For each layer, check if it needs saving
+  // These are the types of layers that we consider "worth saving".
+  // TODO: this should be a parameter of the class, probably
+  for(LayerIterator lit = gid->GetLayers(MAIN_ROLE | LABEL_ROLE | OVERLAY_ROLE);
+      !lit.IsAtEnd(); ++lit)
+    {
+    ImageWrapperBase *w = lit.GetLayer();
+
+    if(layers.size() == 0 || std::find(layers.begin(), layers.end(), w) != layers.end())
+      {
+      // Is the main layer being included in what's discarded?
+      if(w == gid->GetMain())
+        flag_main_included = true;
+
+      if(w->HasUnsavedChanges())
+        {
+        // Add a new item
+        SmartPtr<ImageLayerSaveableItem> item = ImageLayerSaveableItem::New();
+        item->Initialize(this, w, lit.GetRole());
+        item->SetId(m_UnsavedItems.size());
+        m_UnsavedItems.push_back(item.GetPointer());
+
+        if(item->RequiresInteraction())
+          flag_unnamed_layers = true;
+        }
+      }
+    }
+
+  // The workspace should only be included in the list if the main image is being
+  // unloaded. Otherwise, any changes (loading/unloading) should be considered as
+  // part of editing the workspace, and thus we should not be prompting to save the
+  // workspace. Also, the workspace must already exist.
+  if(flag_main_included && m_ParentModel->GetGlobalState()->GetProjectFilename().size())
+    {
+    // Additional conditions are that either the project has unsaved changes, or one of
+    // the items proposed for saving does not have a filename yet (and so saving it would
+    // cause a modification to the workspace)
+    if(flag_unnamed_layers | m_ParentModel->GetDriver()->IsProjectUnsaved())
+      {
+      SmartPtr<WorkspaceSaveableItem> item = WorkspaceSaveableItem::New();
+      item->Initialize(this);
+      item->SetId(m_UnsavedItems.size());
+
+      // Add all of the other unsaved items as dependencies
+      for(int i = 0; i < m_UnsavedItems.size(); i++)
+        item->AddDependency(m_UnsavedItems[i]);
+
+      m_UnsavedItems.push_back(item.GetPointer());
+      }
+
+    }
+
+  // Adjust the current item
+  m_CurrentItem = 0;
+}
+
+void SaveModifiedLayersModel::Initialize(GlobalUIModel *parent, std::list<ImageWrapperBase *> layers)
+{
+  m_ParentModel = parent;
+
+  // The model is not listening to changes in the layers because the dialog
+  // it supports is meant to be modal, i.e. the user can't make changes.
+
+  // Update the list of unsaved items
+  BuildUnsavedItemsList(layers);
+}
+
+bool SaveModifiedLayersModel::CheckState(SaveModifiedLayersModel::UIState state)
+{
+  int i;
+  switch(state)
+    {
+    case SaveModifiedLayersModel::UIF_CAN_SAVE_ALL:
+      for(i = 0; i < m_UnsavedItems.size(); i++)
+        if(m_UnsavedItems[i]->NeedsDecision() && m_UnsavedItems[i]->RequiresInteraction())
+          return false;
+      return true;
+
+    case SaveModifiedLayersModel::UIF_CAN_SAVE_CURRENT:
+      return (m_CurrentItem >= 0 && m_CurrentItem < m_UnsavedItems.size()
+              && m_UnsavedItems[m_CurrentItem]->IsSaveable());
+
+    case SaveModifiedLayersModel::UIF_CAN_DISCARD_CURRENT:
+      return true;
+
+    case SaveModifiedLayersModel::UIF_CAN_QUICKSAVE_CURRENT:
+      break;
+
+    }
+  return false;
+}
+
+void SaveModifiedLayersModel::UpdateCurrentItem()
+{
+  for(int delta = 1; delta < m_UnsavedItems.size(); delta++)
+    {
+    int testItem = (m_CurrentItem + delta) % m_UnsavedItems.size();
+    if(m_UnsavedItems[testItem]->NeedsDecision()
+       && m_UnsavedItems[testItem]->IsSaveable())
+      {
+      SetCurrentItem(testItem);
+      return;
+      }
+    }
+}
+
+void SaveModifiedLayersModel::SaveCurrent()
+{
+  assert(m_CurrentItem >= 0 && m_CurrentItem < m_UnsavedItems.size());
+
+  // Try saving
+  if(m_UnsavedItems[m_CurrentItem]->Save(m_UIDelegate))
+    {
+    // Change the current item to the next unsaved item
+    this->UpdateCurrentItem();
+
+    // Fire an update event
+    this->InvokeEvent(ModelUpdateEvent());
+    }
+}
+
+void SaveModifiedLayersModel::DiscardCurrent()
+{
+  assert(m_CurrentItem >= 0 && m_CurrentItem < m_UnsavedItems.size());
+
+  // Discarding does not cause any action. It just means that the item should
+  // no longer appear on the 'to save' list.
+  m_UnsavedItems[m_CurrentItem]->SetDiscarded(true);
+
+  // Change the current item to the next unsaved item
+  this->UpdateCurrentItem();
+
+  // Fire an update event
+  this->InvokeEvent(ModelUpdateEvent());
+}
+
+void SaveModifiedLayersModel::SaveAll()
+{
+  // For all items that need decision, save them, respecting dependencies
+  int n_Unsaved = m_UnsavedItems.size();
+  while(n_Unsaved > 0)
+    {
+    n_Unsaved = 0;
+    for(int i = 0; i < m_UnsavedItems.size(); i++)
+      {
+      if(m_UnsavedItems[i]->NeedsDecision())
+        {
+        if(m_UnsavedItems[i]->IsSaveable())
+          m_UnsavedItems[i]->Save(m_UIDelegate);
+        else
+          n_Unsaved++;
+        }
+      }
+    }
+
+  // Fire an update event
+  this->InvokeEvent(ModelUpdateEvent());
+}
diff --git a/GUI/Model/SaveModifiedLayersModel.h b/GUI/Model/SaveModifiedLayersModel.h
new file mode 100644
index 0000000..4ca9f76
--- /dev/null
+++ b/GUI/Model/SaveModifiedLayersModel.h
@@ -0,0 +1,207 @@
+#ifndef SAVEMODIFIEDLAYERSMODEL_H
+#define SAVEMODIFIEDLAYERSMODEL_H
+
+#include "PropertyModel.h"
+
+class ImageWrapperBase;
+class GlobalUIModel;
+class ImageIOWizardModel;
+class SaveModifiedLayersModel;
+
+/**
+ * In this dialog, the interaction between the model and the GUI class is a
+ * bit complicated. Because some of the files that need to be saved may be
+ * without a filename, there is the need to prompt the user for the filename
+ * during the save operation. The easiest way to do so is via a callback. So
+ * the GUI has to provide a pointer to a child of this abstract delegate class
+ */
+class AbstractSaveModifiedLayersInteractionDelegate
+{
+public:
+  virtual bool SaveImageLayer(
+      GlobalUIModel *model, ImageWrapperBase *wrapper, LayerRole role) = 0;
+
+  virtual bool SaveProject(GlobalUIModel *model) = 0;
+
+};
+
+
+
+/**
+ * An abstract item that we might want to save. We inherit from AbstractModel
+ * in order to use the smart pointer support, etc.
+ */
+class AbstractSaveableItem : public AbstractModel
+{
+public:
+  irisITKAbstractObjectMacro(AbstractSaveableItem, AbstractModel)
+
+  virtual std::string GetDescription() const = 0;
+  virtual std::string GetFilename() const = 0;
+
+  irisGetSetMacro(Id, int)
+
+  /** Mark item as discarded */
+  irisGetSetMacro(Discarded, bool)
+
+  /** Save the item (pass in the delegate to allow call-back to GUI */
+  virtual bool Save(AbstractSaveModifiedLayersInteractionDelegate *delegate) = 0;
+
+  /** Whether this item requires interaction to be saved */
+  virtual bool RequiresInteraction() = 0;
+
+  /** Whether this item needs decision from the user */
+  bool NeedsDecision() { return !(m_Discarded || IsSaved()); }
+
+  /** Whether this item can be saved. This is true if all dependencies have
+   * been saved or discarded */
+  virtual bool IsSaveable();
+
+  // Add a dependency (the item is not saveable until all dependencies have
+  // been saved). Be careful not to create circular dependencies!
+  void AddDependency(AbstractSaveableItem *dep);
+
+protected:
+
+  AbstractSaveableItem() : m_Id(-1), m_Discarded(false) {}
+
+  /** Whether the user needs to decide about this item */
+  virtual bool IsSaved() = 0;
+
+  int m_Id;
+  bool m_Discarded;
+
+  typedef std::list<AbstractSaveableItem *> DependencyList;
+  DependencyList m_Dependencies;
+};
+
+/**
+ * A saveable item representing an image layer
+ */
+class ImageLayerSaveableItem : public AbstractSaveableItem
+{
+public:
+
+  irisITKObjectMacro(ImageLayerSaveableItem, AbstractSaveableItem)
+
+  void Initialize(SaveModifiedLayersModel *model, ImageWrapperBase *wrapper, LayerRole role);
+
+  virtual std::string GetDescription() const;
+  virtual std::string GetFilename() const;
+
+  virtual bool IsSaved();
+  virtual bool Save(AbstractSaveModifiedLayersInteractionDelegate *cb_delegate);
+
+  /** Whether this item requires interaction to be saved */
+  virtual bool RequiresInteraction();
+
+protected:
+
+  // The image wrapper
+  ImageWrapperBase *m_Wrapper;
+  LayerRole m_Role;
+  SaveModifiedLayersModel *m_Model;
+};
+
+/**
+ * A saveable item representing a workspace state (aka project)
+ */
+class WorkspaceSaveableItem : public AbstractSaveableItem
+{
+public:
+
+  irisITKObjectMacro(WorkspaceSaveableItem, AbstractSaveableItem)
+
+  void Initialize(SaveModifiedLayersModel *model);
+
+  virtual std::string GetDescription() const;
+  virtual std::string GetFilename() const;
+
+  virtual bool IsSaved();
+  virtual bool Save(AbstractSaveModifiedLayersInteractionDelegate *cb_delegate);
+
+  /** Whether this item requires interaction to be saved */
+  virtual bool RequiresInteraction();
+
+protected:
+
+  // The image wrapper
+  SaveModifiedLayersModel *m_Model;
+
+  // Saved state - based on the return code from save method
+  bool m_Saved;
+};
+
+
+
+/**
+ * This model supports saving or discarding of image layers. It is used when
+ * unloading images and segmentations, quitting, etc.
+ */
+class SaveModifiedLayersModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(SaveModifiedLayersModel, AbstractModel)
+
+  void Initialize(GlobalUIModel *parent, std::list<ImageWrapperBase *> layers);
+
+  irisGetMacro(ParentModel, GlobalUIModel *)
+
+  irisGetSetMacro(UIDelegate, AbstractSaveModifiedLayersInteractionDelegate *)
+
+  enum UIState
+  {
+    UIF_CAN_SAVE_ALL = 0,
+    UIF_CAN_SAVE_CURRENT,
+    UIF_CAN_DISCARD_CURRENT,
+    UIF_CAN_QUICKSAVE_CURRENT
+  };
+
+  bool CheckState(UIState state);
+
+  irisSimplePropertyAccessMacro(CurrentItem, int)
+
+  // Unsaved item definition
+  typedef SmartPtr<AbstractSaveableItem> SaveableItemPtr;
+  typedef std::vector<SaveableItemPtr> SaveableItemPtrArray;
+
+  // Get the unsaved items
+  irisGetMacro(UnsavedItems, const SaveableItemPtrArray &)
+
+  // Save the current item (interactively or non-interactively)
+  void SaveCurrent();
+
+  // Discard the current item
+  virtual void DiscardCurrent();
+
+  // Save all items that need saving
+  virtual void SaveAll();
+
+protected:
+  SaveModifiedLayersModel();
+
+  // Parent model
+  GlobalUIModel *m_ParentModel;
+
+  // Delegate that allows callbacks to the GUI
+  AbstractSaveModifiedLayersInteractionDelegate *m_UIDelegate;
+
+  // List of unsaved items
+  SaveableItemPtrArray m_UnsavedItems;
+
+  // Currently selected unsaved item
+  int m_CurrentItem;
+
+  SmartPtr<AbstractSimpleIntProperty> m_CurrentItemModel;
+  bool GetCurrentItemValue(int &out_value);
+  void SetCurrentItemValue(int value);
+
+  // Update the list of unsaved items
+  void BuildUnsavedItemsList(std::list<ImageWrapperBase *> layers);
+
+  // Update the current imate
+  void UpdateCurrentItem();
+};
+
+#endif // SAVEMODIFIEDLAYERSMODEL_H
diff --git a/GUI/Model/SliceWindowCoordinator.cxx b/GUI/Model/SliceWindowCoordinator.cxx
new file mode 100644
index 0000000..d7173bb
--- /dev/null
+++ b/GUI/Model/SliceWindowCoordinator.cxx
@@ -0,0 +1,471 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: SliceWindowCoordinator.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/12 17:57:11 $
+  Version:   $Revision: 1.5 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#include "SliceWindowCoordinator.h"
+
+#include "GlobalState.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "IRISImageData.h"
+#include "GlobalUIModel.h"
+#include "DisplayLayoutModel.h"
+#include <limits>
+
+SliceWindowCoordinator
+::SliceWindowCoordinator()
+{
+  // Set up the zoom model
+  m_CommonZoomFactorModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetCommonZoomValueAndRange, &Self::SetCommonZoomValue,
+        ZoomLevelUpdateEvent(), ZoomLevelUpdateEvent());
+
+  m_LinkedZoomModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetLinkedZoomValue, &Self::SetLinkedZoomValue,
+        ZoomLevelUpdateEvent(), ZoomLevelUpdateEvent());
+
+  // Initialize to defaults
+  m_SliceModel[0] = m_SliceModel[1] = m_SliceModel[2] = NULL;
+  m_LinkedZoom = false;
+  m_WindowsRegistered = false;
+  m_ParentModel = NULL;
+}
+
+SliceWindowCoordinator
+::~SliceWindowCoordinator()
+{
+}
+
+void
+SliceWindowCoordinator
+::SetParentModel(GlobalUIModel *model)
+{
+  m_ParentModel = model;
+
+  for(unsigned int i=0;i<3;i++)
+    {
+    m_SliceModel[i] = m_ParentModel->GetSliceModel(i);
+    m_SliceModel[i]->SetManagedZoom(m_LinkedZoom);
+
+    // Listen to updates to the viewport size. These require zoom factors to be
+    // recomputed
+    Rebroadcast(m_SliceModel[i], GenericSliceModel::ViewportResizeEvent(), ModelUpdateEvent());
+    }
+
+  m_WindowsRegistered = true;
+
+  // Listen to image dimension change events
+  Rebroadcast(m_ParentModel->GetDriver(), MainImageDimensionsChangeEvent(), ModelUpdateEvent());
+
+  // Listen to changes in the layout of the slice view into cells. When
+  // this change occurs, we have to modify the size of the slice views
+  DisplayLayoutModel *dlm = m_ParentModel->GetDisplayLayoutModel();
+  Rebroadcast(dlm, DisplayLayoutModel::LayerLayoutChangeEvent(), ModelUpdateEvent());
+
+}
+
+void SliceWindowCoordinator::OnUpdate()
+{
+  // Has a new main image been loaded
+  if(this->m_EventBucket->HasEvent(MainImageDimensionsChangeEvent()))
+    {
+    // Update each of the slice models, allowing them to respond to the main image
+    // dimensions change
+    for(unsigned int i = 0; i < 3; i++)
+      m_SliceModel[i]->Update();
+
+    // Reset the view to fit (depending on linked zoom)
+    if(m_ParentModel->GetDriver()->IsMainImageLoaded())
+      this->ResetViewToFitInAllWindows();
+    }
+
+  if(this->m_EventBucket->HasEvent(GenericSliceModel::ViewportResizeEvent())
+     || this->m_EventBucket->HasEvent(DisplayLayoutModel::LayerLayoutChangeEvent()))
+    {
+    // If we are maintaining linked zoom, then this class is going to manage the
+    // recomputation of optimal zoom in each window and resetting of the zoom.
+    if(m_LinkedZoom && AreSliceModelsInitialized())
+      {
+      // Is the current zoom same as the optimal zoom? If so, we will force a
+      // reset after the optimal zooms have been computed
+      double common_opt_zoom = ComputeSmallestOptimalZoomLevel();
+      double common_zoom = GetCommonZoomLevel();
+      bool rezoom = (common_zoom == common_opt_zoom);
+
+      // Recompute the optimal zoom in each of the views
+      for(unsigned int i = 0; i < 3; i++)
+        m_SliceModel[i]->ComputeOptimalZoom();
+
+      // Optionally, reset the view
+      if(rezoom)
+        this->ResetViewToFitInAllWindows();
+      }
+
+    // Update each of the slice models. This will cause them to recompute their
+    // optimal zoom.
+    }
+
+}
+
+double
+SliceWindowCoordinator
+::ComputeSmallestOptimalZoomLevel()
+{
+  assert(m_WindowsRegistered);
+
+  // How this is computed depends on whether all four views are visible or not
+  DisplayLayoutModel *dlm = m_ParentModel->GetDisplayLayoutModel();
+
+  // Figure out what is the optimal zoom in each window
+  bool foundVisible = false;
+  double minoptzoom = 0;
+  for(int i = 0; i < 3; i++)
+    {
+    if(dlm->GetViewPanelVisibilityModel(i)->GetValue())
+      {
+      double optzoom = m_SliceModel[i]->GetOptimalZoom();
+      if(!foundVisible || minoptzoom > optzoom)
+        {
+        minoptzoom = optzoom;
+        foundVisible = true;
+        }
+      }
+    }
+
+  // If nothing is visible, use the optimal zoom from the first window
+  return minoptzoom;
+}
+
+void
+SliceWindowCoordinator
+::ResetViewToFitInAllWindows()
+{
+  // Only if initialized
+  assert(m_WindowsRegistered);
+
+  // Reset the view in all windows (center slices)
+  for(unsigned int i=0;i<3;i++)
+    {
+    m_SliceModel[i]->ResetViewToFit();
+    }
+
+  // If linked zoom, use the smallest optimal zoom level
+  if(m_LinkedZoom)
+    {
+    double optzoom = ComputeSmallestOptimalZoomLevel();
+    if(optzoom > 0.0)
+      SetZoomLevelAllWindows(optzoom);
+    }
+}
+
+void SliceWindowCoordinator
+::SetZoomPercentageInAllWindows(float x)
+{
+  // x screen pixels = smallest voxel dimension
+  // zf = x / (smallest voxel dimension)
+  SetZoomLevelAllWindows(x / m_SliceModel[0]->GetSliceSpacing().min_value());
+}
+
+void 
+SliceWindowCoordinator
+::SetZoomFactorAllWindows(float factor)
+{
+  // Only if initialized
+  assert(m_WindowsRegistered);
+
+  // If linked zoom, use the smallest optimal zoom level
+  if(m_LinkedZoom)
+    {
+    SetZoomLevelAllWindows(ComputeSmallestOptimalZoomLevel() * factor);
+    }
+  else
+    {
+    for(unsigned int i=0;i<3;i++)
+      {
+      m_SliceModel[i]->SetViewZoom(
+            m_SliceModel[i]->GetOptimalZoom() * factor);
+      }
+    }
+}
+
+void
+SliceWindowCoordinator
+::SetZoomLevelAllWindows(float level)
+{
+  // Now scale the zoom in each window
+  for(unsigned int i=0;i<3;i++)
+    {
+    m_SliceModel[i]->SetViewZoom(level);
+    }
+
+  // Invoke event
+  if(m_LinkedZoom)
+    {
+    InvokeEvent(ZoomLevelUpdateEvent());
+    }
+}
+
+
+
+void
+SliceWindowCoordinator
+::ResetViewToFitInOneWindow(unsigned int window)
+{
+  // Only if initialized
+  assert(m_WindowsRegistered);
+
+  // Reset zoom to fit in the current window
+  if(m_LinkedZoom)
+    {
+    SetZoomLevelAllWindows(m_SliceModel[window]->GetOptimalZoom());
+    }
+
+  m_SliceModel[window]->ResetViewToFit();
+}
+
+void
+SliceWindowCoordinator
+::ZoomInOrOutInOneWindow(unsigned int window, float factor)
+{
+  // Only if initialized
+  assert(m_WindowsRegistered);
+
+  // Apply in the current window
+  m_SliceModel[window]->ZoomInOrOut(factor);
+
+  // Reset zoom to fit in the current window
+  if(m_LinkedZoom)
+    {
+    SetZoomLevelAllWindows(m_SliceModel[window]->GetViewZoom());
+    }
+}
+
+void SliceWindowCoordinator::CenterViewOnCursorInAllWindows()
+{
+  for(int i = 0; i < 3; i++)
+    m_SliceModel[i]->CenterViewOnCursor();
+}
+
+void
+SliceWindowCoordinator
+::OnZoomUpdateInWindow(unsigned int irisNotUsed(window), float zoom)
+{
+  // Only if initialized
+  assert(m_WindowsRegistered);
+  
+  if(m_LinkedZoom)
+    {
+    SetZoomLevelAllWindows(zoom);
+    }
+}
+
+void
+SliceWindowCoordinator
+::OnWindowResize()
+{
+  if(m_LinkedZoom)
+    {
+    SetCommonZoomToSmallestWindowZoom();
+    }
+}
+
+void
+SliceWindowCoordinator
+::SetCommonZoomToSmallestWindowZoom()
+{
+  // Compute the minimum zoom
+  float minZoom = 0;
+  for(unsigned int i=0; i<3; i++)
+    {
+    if(i == 0 || minZoom > m_SliceModel[i]->GetViewZoom())
+      minZoom = m_SliceModel[i]->GetViewZoom();
+    }
+
+  // Assign the minimum zoom
+  SetZoomLevelAllWindows(minZoom);
+}
+
+
+float
+SliceWindowCoordinator
+::GetCommonZoomLevel()
+{
+  if(m_LinkedZoom && m_WindowsRegistered)
+    return m_SliceModel[0]->GetViewZoom();
+  else return std::numeric_limits<float>::quiet_NaN();
+}
+
+float
+SliceWindowCoordinator
+::GetCommonOptimalFitZoomLevel()
+{
+  assert(m_LinkedZoom && m_WindowsRegistered);
+  return m_SliceModel[0]->GetOptimalZoom();
+}
+
+void
+SliceWindowCoordinator
+::GetZoomRange(unsigned int window, float &minZoom, float &maxZoom)
+{
+  assert(m_WindowsRegistered);
+
+  maxZoom = 0.0f;
+  minZoom = 0.0f;
+
+  for(unsigned int i=0;i<3;i++)
+    {
+    if(m_LinkedZoom || window == i)
+      {
+      double w = (double) m_SliceModel[i]->GetSize()[0];
+      double h = (double) m_SliceModel[i]->GetSize()[1];
+
+      // Maximum zoom is constrained by the requirement that at least four
+      // pixels are visible in at least one dimensions
+      float zMax1 = 0.25 * w / m_SliceModel[i]->GetSliceSpacing()[0];
+      float zMax2 = 0.25 * h / m_SliceModel[i]->GetSliceSpacing()[1];
+      float zMax = zMax1 > zMax2 ? zMax1 : zMax2;
+      maxZoom = (maxZoom == 0.0f || maxZoom < zMax) ? zMax : maxZoom;
+
+      // Minimum zoom is just 0.25 of the optimal zoom
+      float zMin = 0.25 * m_SliceModel[i]->GetOptimalZoom();
+      minZoom = (minZoom == 0.0f || minZoom > zMin) ? zMin : minZoom;
+      }
+    }
+}
+
+
+float
+SliceWindowCoordinator
+::ClampZoom(unsigned int window,float zoom)
+{
+  assert(m_WindowsRegistered);
+
+  float minZoom, maxZoom;
+  GetZoomRange(window, minZoom, maxZoom);
+
+  // Apply the clamp
+  if(zoom < minZoom)
+    return minZoom;
+  if(zoom > maxZoom)
+    return maxZoom;
+  return zoom;
+}
+
+
+/**
+  Compute a round step size so that there are approximately
+  n_steps steps between a and b
+  */
+double round_step_size(double a, double b, double nsteps)
+{
+  double delta = fabs(b-a);
+  double k = pow(10, floor(log((delta) / nsteps) / log(10.0)));
+  double s = floor(0.5 + delta / (nsteps * k)) * k;
+  return s;
+}
+
+bool SliceWindowCoordinator::GetCommonZoomValueAndRange(
+    double &zoom, NumericValueRange<double> *range)
+{
+  // Linked zoom required
+  if(!GetLinkedZoom() || !m_ParentModel->GetDriver()->IsMainImageLoaded())
+    return false;
+
+  // Get the zoom
+  zoom = (double) GetCommonZoomLevel();
+
+  // Get the range
+  if(range)
+    {
+    float fmin, fmax;
+    GetZoomRange(0, fmin, fmax);
+
+    range->Minimum = fmin;
+    range->Maximum = fmax;
+
+    // Compute a reasonable step value. This is tricky, because zoom is not
+    // really a linear variable, at high zoom levels, you want steps to be
+    // larger than at small zoom levels. So how about a step that's just on
+    // the order of one hundredth of the current level?
+    range->StepSize = CalculatePowerOfTenStepSize(0, zoom, 10);
+    }
+
+  return true;
+}
+
+void SliceWindowCoordinator::SetCommonZoomValue(double zoom)
+{
+  this->SetZoomLevelAllWindows((float) zoom);
+}
+
+bool SliceWindowCoordinator::GetLinkedZoomValue(bool &out_value)
+{
+  out_value = m_LinkedZoom;
+  return true;
+}
+
+void SliceWindowCoordinator::SetLinkedZoomValue(bool value)
+{
+  if(m_LinkedZoom != value)
+    {
+    m_LinkedZoom = value;
+
+    if(m_WindowsRegistered)
+      {
+      // Tell the windows whether they are managed or not
+      for(unsigned int i=0;i<3;i++)
+        m_SliceModel[i]->SetManagedZoom(m_LinkedZoom);
+
+      // Set the common zoom if an image is loaded
+      if(m_LinkedZoom && m_ParentModel->GetDriver()->IsMainImageLoaded())
+        SetCommonZoomToSmallestWindowZoom();
+      }
+
+    // Fire the appropriate event
+    InvokeEvent(LinkedZoomUpdateEvent());
+    }
+}
+
+bool SliceWindowCoordinator::AreSliceModelsInitialized()
+{
+  if(!m_WindowsRegistered)
+    return false;
+
+  for(unsigned int i=0;i<3;i++)
+    if(!m_SliceModel[i]->IsSliceInitialized())
+      return false;
+
+  return true;
+}
+
+
diff --git a/GUI/Model/SliceWindowCoordinator.h b/GUI/Model/SliceWindowCoordinator.h
new file mode 100644
index 0000000..ebadf1e
--- /dev/null
+++ b/GUI/Model/SliceWindowCoordinator.h
@@ -0,0 +1,188 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: SliceWindowCoordinator.h,v $
+  Language:  C++
+  Date:      $Date: 2009/05/04 20:15:57 $
+  Version:   $Revision: 1.5 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#ifndef __SliceWindowCoordinator_h_
+#define __SliceWindowCoordinator_h_
+
+#include "GenericSliceModel.h"
+#include <itkObject.h>
+#include <SNAPEvents.h>
+#include "PropertyModel.h"
+
+class GlobalUIModel;
+
+/*
+  Who fires the events? Widgets interacting with the Zoom Factor model expect
+  events from the model. We don't want the parent object to fire events
+  separately. But this means, everyone should interact with the model, not
+  directly with the slice window coordinator.
+
+  */
+
+/**
+ * \class SliceWindowCoordinator
+ * \brief Coordinates the zoom (and perhaps other) aspects of behavior between
+ * three orthogonal slice windows.
+ *
+ * Helps manage linked zoom (the concept that 1 mm in image space is always the
+ * same number of pixels in each slice view).
+ */
+class SliceWindowCoordinator : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(SliceWindowCoordinator, itk::Object)
+
+  FIRES(LinkedZoomUpdateEvent)
+
+  /** Initialize the model. Assigns three windows for the coordinator to manage */
+  void SetParentModel(GlobalUIModel *model);
+
+  /** Respond to updates */
+  virtual void OnUpdate();
+
+  /** Specify whether the coordinator should maintain linked zoom
+   * in the three slice windows */
+  irisSimplePropertyAccessMacro(LinkedZoom, bool)
+
+  /** Set the zoom to a fraction of the optimal zoom.  This makes 
+   * the most sense when the zoom level is linked, but can be performed 
+   * regardless */
+  void SetZoomFactorAllWindows(float factor);
+
+  /** Set the zoom to an absolute value in all windows */
+  void SetZoomLevelAllWindows(float level);
+
+  /**
+    This sets the zoom 'percentage'. For example, if x=1, the zoom is set
+    such that one screen pixel is matched to the smallest of voxel dims. If
+    x=2, two pixels match the smallest voxel dim, and so on. The idea is that
+    if your image is isotropic, by setting x=1,2,4, etc., you can avoid
+    aliasing the displayed image
+    */
+  void SetZoomPercentageInAllWindows(float x);
+
+  /** Reset the zoom in all windows to an optimal value, ie, such a zoom
+   * that the image fits into each of the windows.  Depending on whether 
+   * the zoom is linked or not, this will either zoom each slice as much
+   * as possible, or zoom the largest of the 3 slices as much as possible */
+  void ResetViewToFitInAllWindows();
+
+  /** Reset the zoom in one window to optimal value.  When linked zoom is
+   * maintained, this has the same effect as ResetViewToFitInAllWindows, 
+   * and if not, it only affects the given window */
+  void ResetViewToFitInOneWindow(unsigned int window);
+
+  /** Update zoom by a specified factor in a window */
+  void ZoomInOrOutInOneWindow(unsigned int window, float factor);
+
+  /** Center the view on the cursor in all slice windows */
+  void CenterViewOnCursorInAllWindows();
+
+  /** When one of the windows wants to change the zoom w.r.t. a user
+   * action, this class will adjust, if necessary, the zoom in the other
+   * windows */
+  void OnZoomUpdateInWindow(unsigned int window, float zoom);
+
+  /** React to a resizing of the windows.  This will try to maintain the current view
+   * depending on the state.  If the zooms are in 'reset' state, this will keep
+   * them in the reset state, and otherwise, it will maintain the zoom levels */
+  void OnWindowResize();
+
+  /** Get the common zoom factor */
+  float GetCommonZoomLevel();
+
+  /** Get the zoom factor that will fit all three slices optimally */
+  float GetCommonOptimalFitZoomLevel();
+
+  /** Get the model representing the optimal zoom */
+  irisGetMacro(CommonZoomFactorModel, AbstractRangedDoubleProperty*)
+
+  /** Constrain a zoom factor to reasonable limits */
+  float ClampZoom(unsigned int window,float zoom);
+
+  /** Get the range of zoom allowed */
+  void GetZoomRange(unsigned int window, float &minZoom, float &maxZoom);
+
+  /** Get the window number n */
+  GenericSliceModel *GetSliceModel(unsigned int window)
+    { return m_SliceModel[window]; }
+
+
+protected:
+
+  /** Constructor */
+  SliceWindowCoordinator();
+
+  /** Virtual destructor */
+  virtual ~SliceWindowCoordinator();
+
+  /** The parent model */
+  GlobalUIModel *m_ParentModel;
+
+  /** The pointers to three window interactors managed by this class */
+  GenericSliceModel *m_SliceModel[3];
+
+  /** Whether or not linked zoom is maintained */
+  bool m_LinkedZoom;
+
+  /** Whether the windows have been registered */
+  bool m_WindowsRegistered;
+
+  /** Method that sets all the zooms to a common value */
+  void SetCommonZoomToSmallestWindowZoom();
+
+  /** Compute the smallest of the optimal zoom levels of the slice views */
+  double ComputeSmallestOptimalZoomLevel();
+
+  // Child model governing linked zoom properties
+  SmartPtr<AbstractRangedDoubleProperty> m_CommonZoomFactorModel;
+
+  // Methods that the model above wraps around
+  bool GetCommonZoomValueAndRange(double &zoom,
+                                  NumericValueRange<double> *range);
+  void SetCommonZoomValue(double zoom);
+
+  // Child model for the linked zoom flag
+  SmartPtr<AbstractSimpleBooleanProperty> m_LinkedZoomModel;
+
+  // Methods that the model above wraps around
+  bool GetLinkedZoomValue(bool &out_value);
+  void SetLinkedZoomValue(bool value);
+
+  // Are the slice models initialized
+  bool AreSliceModelsInitialized();
+};
+
+#endif // __SliceWindowCoordinator_h_
diff --git a/GUI/Model/SnakeParameterModel.cxx b/GUI/Model/SnakeParameterModel.cxx
new file mode 100644
index 0000000..9837ef3
--- /dev/null
+++ b/GUI/Model/SnakeParameterModel.cxx
@@ -0,0 +1,379 @@
+#include "SnakeParameterModel.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "GlobalState.h"
+#include "SnakeParametersPreviewPipeline.h"
+#include "itkImageFileReader.h"
+#include "itkShiftScaleImageFilter.h"
+#include "UIReporterDelegates.h"
+#include "SNAPRegistryIO.h"
+#include "HistoryManager.h"
+#include "SNAPImageData.h"
+
+
+SnakeParameterModel::SnakeParameterModel()
+{
+  // Create the derived models
+  for(int i = 0; i < 3; i++)
+    {
+    m_WeightModel[i] = wrapIndexedGetterSetterPairAsProperty(
+          this, i, &Self::GetWeightValueAndRange, &Self::SetWeightValue);
+
+    m_ExponentModel[i] = wrapIndexedGetterSetterPairAsProperty(
+          this, i, &Self::GetExponentValueAndRange, &Self::SetExponentValue);
+    }
+
+  m_SpeedupFactorModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetSpeedupFactorValueAndRange, &Self::SetSpeedupFactorValue);
+
+  m_AdvancedEquationModeModel = NewSimpleConcreteProperty(false);
+
+  m_CasellesOrAdvancedModeModel = wrapGetterSetterPairAsProperty(
+        this, &Self::GetCasellesOrAdvancedModeValue);
+
+  m_AnimateDemoModel = NewSimpleConcreteProperty(false);
+
+  // Treat changes to the state as model updates
+  Rebroadcast(m_AdvancedEquationModeModel, ValueChangedEvent(), ModelUpdateEvent());
+
+  m_PreviewPipeline = NULL;
+}
+
+SnakeParameterModel::~SnakeParameterModel()
+{
+  if(m_PreviewPipeline) delete m_PreviewPipeline;
+}
+
+void SnakeParameterModel::SetParentModel(GlobalUIModel *model)
+{
+  this->m_ParentModel = model;
+  this->m_ParametersModel = m_ParentModel->GetGlobalState()->GetSnakeParametersModel();
+
+  // Listen and rebroadcast changes to the internally stored snake parameters
+  Rebroadcast(m_ParametersModel, ValueChangedEvent(), ModelUpdateEvent());
+
+  // Set up the preview pipeline
+  this->SetupPreviewPipeline();
+}
+
+
+void SnakeParameterModel::SetupPreviewPipeline()
+{
+  // Initialize the pipeline
+  if(m_PreviewPipeline) delete m_PreviewPipeline;
+  m_PreviewPipeline = new SnakeParametersPreviewPipeline(m_ParentModel->GetGlobalState());
+
+  // Get the parent's system object
+  SystemInterface *si = m_ParentModel->GetSystemInterface();
+
+  // Get the edge and region example image file names
+  std::string fnImage[] =
+    { "EdgeForcesExample.png", "RegionForcesExample.png"};
+
+  // Typedefs
+  typedef itk::Image<unsigned char, 2> InputImageType;
+  typedef itk::ImageFileReader<InputImageType> ReaderType;
+  typedef itk::ImageRegionIterator<InputImageType> IteratorType;
+  typedef itk::ShiftScaleImageFilter<InputImageType, ExampleImageType> ScaleShiftType;
+
+  // Load each of these images
+  static const float scale_factor[] = { 1.0f / 255.0f, -2.0f / 255.0f };
+  static const float shift_factor[] = { 0.0f, -127.5f };
+
+  for(unsigned int i = 0; i < 2; i++)
+    {
+    try
+      {
+      // Initialize the image
+      SmartPtr<InputImageType> imgInput = InputImageType::New();
+
+      // Load the example image using the application resource system
+      si->GetSystemInfoDelegate()->LoadResourceAsImage2D(fnImage[i], imgInput);
+
+      // Read the image in
+      ScaleShiftType::Pointer scaler = ScaleShiftType::New();
+      scaler->SetScale(0x7fff * scale_factor[i]);
+      scaler->SetShift(shift_factor[i]);
+      scaler->SetInput(imgInput);
+
+      scaler->Update();
+
+      // Allocate the example image
+      m_ExampleImage[i] = scaler->GetOutput();
+      }
+    catch(...)
+      {
+      // An exception occurred. We don't want to freak out about this, so
+      // just print out a message
+      std::cerr << "Unable to read example image " << fnImage[i]
+                << "; Snake preview will me missing an image" << std::endl;
+
+      // Initialize the image to zeros
+      itk::ImageRegion<2> defregion;
+      defregion.SetSize(0, 128); defregion.SetSize(1, 128);
+
+      m_ExampleImage[i] = ExampleImageType::New();
+      m_ExampleImage[i]->SetRegions(defregion);
+      m_ExampleImage[i]->Allocate();
+      m_ExampleImage[i]->FillBuffer(0);
+      }
+    }
+
+  // Pass one of the images to the pipeline
+  if(this->IsRegionSnake())
+    m_PreviewPipeline->SetSpeedImage(m_ExampleImage[1]);
+  else
+    m_PreviewPipeline->SetSpeedImage(m_ExampleImage[0]);
+
+  // Load the points from the registry
+  std::vector<Vector2d> points;
+  try
+    {
+    Registry regPoints;
+    si->GetSystemInfoDelegate()->
+        LoadResourceAsRegistry("SnakeParameterPreviewCurve.txt", regPoints);
+    points = regPoints.Folder("Points").GetArray(Vector2d(0.0));
+    }
+  catch(...)
+    {
+    // Again, we don't want to freak out.
+    std::cerr << "Unable to read example point data for snake preview" << std::endl;
+    }
+
+  // If there are some points in there, draw them
+  if(points.size() >= 4)
+    {
+    // Set spline points, etc
+    m_PreviewPipeline->SetControlPoints(points);
+    }
+
+  // Pass the parameters to the preview pipeline
+  m_PreviewPipeline->SetSnakeParameters(m_ParametersModel->GetValue());
+}
+
+void SnakeParameterModel::OnUpdate()
+{
+  if(this->m_EventBucket->HasEvent(ValueChangedEvent(), m_ParametersModel))
+    {
+    // Send the parameters to the segmentation pipeline. This is kind of
+    // stupid, because we are using a model to coordinate between two copies
+    // of the parameters, but it should work
+    SNAPImageData *sid = m_ParentModel->GetDriver()->GetSNAPImageData();
+    if(sid && sid->IsSegmentationActive())
+      {
+      sid->SetSegmentationParameters(m_ParametersModel->GetValue());
+      }
+
+    // Update the speed image used by the preview pipeline
+    ExampleImageType *speed = this->IsRegionSnake()
+        ? m_ExampleImage[1] : m_ExampleImage[0];
+    if(m_PreviewPipeline->GetSpeedImage() != speed)
+      m_PreviewPipeline->SetSpeedImage(speed);
+    m_PreviewPipeline->SetSnakeParameters(m_ParametersModel->GetValue());
+    }
+}
+
+bool SnakeParameterModel::IsRegionSnake()
+{
+  SnakeParameters param = m_ParametersModel->GetValue();
+  return param.GetSnakeType() == SnakeParameters::REGION_SNAKE;
+}
+
+void SnakeParameterModel::PerformAnimationStep()
+{
+  m_PreviewPipeline->AnimationCallback();
+  InvokeEvent(DemoLoopEvent());
+}
+
+void SnakeParameterModel::ResetAnimation()
+{
+  m_PreviewPipeline->AnimationRestart();
+}
+
+void SnakeParameterModel::LoadParameters(const std::string &file)
+{
+  // Create default parameters
+  SnakeParameters param = (this->IsRegionSnake())
+      ? SnakeParameters::GetDefaultInOutParameters()
+      : SnakeParameters::GetDefaultEdgeParameters();
+
+  // Read parameters from file
+  SNAPRegistryIO io;
+  Registry regParameters(file.c_str());
+  param = io.ReadSnakeParameters(regParameters, param);
+
+  // Update the history
+  m_ParentModel->GetDriver()->GetHistoryManager()->
+      UpdateHistory("SnakeParameters", file, true);
+
+  // Set the parameters
+  m_ParametersModel->SetValue(param);
+}
+
+void SnakeParameterModel::SaveParameters(const std::string &file)
+{
+  // Load the parameters
+  SnakeParameters param = m_ParametersModel->GetValue();
+  SNAPRegistryIO io;
+  Registry regParameters;
+  io.WriteSnakeParameters(param, regParameters);
+  regParameters.WriteToFile(file.c_str());
+
+  // Update the history
+  m_ParentModel->GetDriver()->GetHistoryManager()->
+      UpdateHistory("SnakeParameters", file, true);
+}
+
+void SnakeParameterModel::RestoreDefaults()
+{
+  // Create default parameters
+  SnakeParameters param = (this->IsRegionSnake())
+      ? SnakeParameters::GetDefaultInOutParameters()
+      : SnakeParameters::GetDefaultEdgeParameters();
+
+
+  // Set the parameters
+  m_ParametersModel->SetValue(param);
+}
+
+
+bool SnakeParameterModel
+::GetWeightValueAndRange(
+    int index, double &value, NumericValueRange<double> *domain)
+{
+  SnakeParameters param = m_ParametersModel->GetValue();
+  if(index == ALHPA)
+    {
+    value = param.GetPropagationWeight();
+    if(domain)
+      domain->Set(this->IsRegionSnake() ? 0.0 : -1.0, 1.0, 0.01);
+    return true;
+    }
+  else if(index == BETA)
+    {
+    value = param.GetCurvatureWeight();
+    if(domain)
+      domain->Set(0.0, 1.0, 0.01);
+    return true;
+    }
+  else if(index == GAMMA && this->GetCasellesOrAdvancedModeValue())
+    {
+    value = param.GetAdvectionWeight();
+    if(domain)
+      domain->Set(0.0, 5.0, 0.05);
+    return true;
+    }
+  return false;
+}
+
+
+void
+SnakeParameterModel
+::SetWeightValue(int index, double value)
+{
+  SnakeParameters param = m_ParametersModel->GetValue();
+  switch(index)
+    {
+    case ALHPA:
+      param.SetPropagationWeight(value); break;
+    case BETA:
+      param.SetCurvatureWeight(value); break;
+    case GAMMA:
+      param.SetAdvectionWeight(value); break;
+    }
+  m_ParametersModel->SetValue(param);
+}
+
+
+bool SnakeParameterModel
+::GetExponentValueAndRange(
+    int index, int &value, NumericValueRange<int> *domain)
+{
+  // Only valid in advanced mode
+  if(!this->m_AdvancedEquationModeModel->GetValue())
+    return false;
+
+  SnakeParameters param = m_ParametersModel->GetValue();
+  if(index == ALHPA)
+    {
+    value = param.GetPropagationSpeedExponent();
+    if(domain)
+      domain->Set(0, 2, 1);
+    return true;
+    }
+  else if(index == BETA)
+    {
+    value = param.GetCurvatureSpeedExponent();
+    if(domain)
+      domain->Set(0, 2, 1);
+    return true;
+    }
+  else if(index == GAMMA)
+    {
+    value = param.GetAdvectionSpeedExponent();
+    if(domain)
+      domain->Set(0, 2, 1);
+    return true;
+    }
+  return false;
+}
+
+
+void
+SnakeParameterModel
+::SetExponentValue(int index, int value)
+{
+  SnakeParameters param = m_ParametersModel->GetValue();
+  switch(index)
+    {
+    case ALHPA:
+      param.SetPropagationSpeedExponent(value); break;
+    case BETA:
+      param.SetCurvatureSpeedExponent(value); break;
+    case GAMMA:
+      param.SetAdvectionSpeedExponent(value); break;
+    }
+  m_ParametersModel->SetValue(param);
+}
+
+bool
+SnakeParameterModel
+::GetSpeedupFactorValueAndRange(double &value, NumericValueRange<double> *domain)
+{
+  SnakeParameters param = m_ParametersModel->GetValue();
+  if(param.GetAutomaticTimeStep())
+    value = 1;
+  else
+    value = param.GetTimeStepFactor();
+
+  if(domain)
+    domain->Set(1.0, 10.0, 0.25);
+
+  return true;
+}
+
+void
+SnakeParameterModel
+::SetSpeedupFactorValue(double value)
+{
+  SnakeParameters param = m_ParametersModel->GetValue();
+
+  if(value == 1.0)
+    {
+    param.SetAutomaticTimeStep(true);
+    param.SetTimeStepFactor(1.0f);
+    }
+  else
+    {
+    param.SetAutomaticTimeStep(false);
+    param.SetTimeStepFactor((float) value);
+    }
+
+  m_ParametersModel->SetValue(param);
+}
+
+bool SnakeParameterModel::GetCasellesOrAdvancedModeValue()
+{
+  return this->GetAdvancedEquationModeModel()->GetValue() || (!this->IsRegionSnake());
+}
+
diff --git a/GUI/Model/SnakeParameterModel.h b/GUI/Model/SnakeParameterModel.h
new file mode 100644
index 0000000..bb46d72
--- /dev/null
+++ b/GUI/Model/SnakeParameterModel.h
@@ -0,0 +1,126 @@
+#ifndef SNAKEPARAMETERMODEL_H
+#define SNAKEPARAMETERMODEL_H
+
+#include "SNAPCommon.h"
+#include "AbstractModel.h"
+#include "PropertyModel.h"
+#include "SnakeParameters.h"
+
+class GlobalUIModel;
+class SnakeParametersPreviewPipeline;
+
+namespace itk
+{
+template <class TPixel, unsigned int VDim> class Image;
+}
+
+/**
+ * @brief The SnakeParameterModel class
+ * This model handles interaction with snake parameters
+ */
+class SnakeParameterModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(SnakeParameterModel, AbstractModel)
+
+  // This model fires a custom DemoLoopEvent when the demo loop is run
+  itkEventMacro(DemoLoopEvent, IRISEvent)
+  FIRES(DemoLoopEvent)
+
+  irisGetMacro(ParentModel, GlobalUIModel *)
+  void SetParentModel(GlobalUIModel *model);
+
+  virtual void OnUpdate();
+
+  // State machine enums
+  enum UIState {
+    UIF_CASELLES_MODE,
+    UIF_ZHU_MODE,
+    UIF_EXPONENTS_SHOWN
+  };
+
+  // To make life easier, we access the parameters using an index, instead
+  // of having an endless list of models.
+  enum ParamIndex { ALHPA = 0, BETA, GAMMA };
+
+  // Access one of the models for the weights alpha, beta, gamma
+  AbstractRangedDoubleProperty *GetWeightModel(int index)
+    { return m_WeightModel[index]; }
+
+  // Access one of the models for the exponents of corresp. terms
+  AbstractRangedIntProperty *GetExponentModel(int index)
+    { return m_ExponentModel[index]; }
+
+  // Speedup factor
+  irisRangedPropertyAccessMacro(SpeedupFactor, double)
+
+  // The model for whether the advanced mode (exponents) is on
+  irisSimplePropertyAccessMacro(AdvancedEquationMode, bool)
+  irisSimplePropertyAccessMacro(CasellesOrAdvancedMode, bool)
+
+  // Whether the demo is being animated
+  irisSimplePropertyAccessMacro(AnimateDemo, bool)
+
+  // Whether or not we are in Zhu (region competition) mode
+  bool IsRegionSnake();
+
+  // Preview pipeline
+  irisGetMacro(PreviewPipeline, SnakeParametersPreviewPipeline *)
+
+  // Run a loop of the demo animation
+  void PerformAnimationStep();
+
+  // Run a loop of the demo animation
+  void ResetAnimation();
+
+  // Parameter IO
+  void LoadParameters(const std::string &file);
+  void SaveParameters(const std::string &file);
+  void RestoreDefaults();
+
+
+protected:
+
+  SnakeParameterModel();
+  virtual ~SnakeParameterModel();
+
+  SmartPtr<AbstractRangedDoubleProperty> m_WeightModel[3];
+  bool GetWeightValueAndRange(
+      int index, double &value, NumericValueRange<double> *domain);
+  void SetWeightValue(int index, double value);
+
+  SmartPtr<AbstractRangedIntProperty> m_ExponentModel[3];
+  bool GetExponentValueAndRange(
+      int index, int &value, NumericValueRange<int> *domain);
+  void SetExponentValue(int index, int value);
+
+  SmartPtr<AbstractRangedDoubleProperty> m_SpeedupFactorModel;
+  bool GetSpeedupFactorValueAndRange(
+      double &value, NumericValueRange<double> *domain);
+  void SetSpeedupFactorValue(double value);
+
+  SmartPtr<ConcreteSimpleBooleanProperty> m_AdvancedEquationModeModel;
+
+  SmartPtr<AbstractSimpleBooleanProperty> m_CasellesOrAdvancedModeModel;
+  bool GetCasellesOrAdvancedModeValue();
+
+  SmartPtr<ConcreteSimpleBooleanProperty> m_AnimateDemoModel;
+
+  void SetupPreviewPipeline();
+
+  // Preview pipeline
+  SnakeParametersPreviewPipeline *m_PreviewPipeline;
+
+  // Example images for the preview pipeline
+  typedef itk::Image<short, 2> ExampleImageType;
+  SmartPtr<ExampleImageType> m_ExampleImage[2];
+
+  // Parent model
+  GlobalUIModel *m_ParentModel;
+
+  // Model governing the parameters
+  AbstractPropertyModel<SnakeParameters, TrivialDomain> *m_ParametersModel;
+};
+
+#endif // SNAKEPARAMETERMODEL_H
diff --git a/GUI/Model/SnakeROIModel.cxx b/GUI/Model/SnakeROIModel.cxx
new file mode 100644
index 0000000..4782600
--- /dev/null
+++ b/GUI/Model/SnakeROIModel.cxx
@@ -0,0 +1,299 @@
+#include "SnakeROIModel.h"
+#include "GenericSliceModel.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "GlobalState.h"
+
+SnakeROIModel::SnakeROIModel()
+{
+}
+
+
+void SnakeROIModel::SetParent(GenericSliceModel *parent)
+{
+  // Set up the parent
+  m_Parent = parent;
+
+  // Listen to changes in the parent's segmentation ROI settings
+  Rebroadcast(
+        m_Parent->GetDriver()->GetGlobalState()->GetSegmentationROISettingsModel(),
+        ValueChangedEvent(), ModelUpdateEvent());
+
+  // Layer change events too?
+  Rebroadcast(m_Parent->GetDriver(), LayerChangeEvent(), ModelUpdateEvent());
+}
+
+// Return true if the selection state has changed
+SnakeROISideSelectionState
+SnakeROIModel
+::ComputeSelection(Vector2f &uvSlice, Vector3f corners[])
+{
+  // This code computes the current selection based on the mouse coordinates
+  // Flag indicating whether we respond to this event or not
+  SnakeROISideSelectionState h;
+
+  // Repeat for vertical and horizontal edges
+  for(unsigned int dir = 0; dir < 2; dir++)
+    {
+    // Variables used to find the closest edge that's within delta
+    int iClosest = -1;
+    float dToClosest = m_PixelDelta;
+
+    // Search for the closest edge
+    for(unsigned int i=0;i<2;i++)
+      {
+      float d = GetEdgeDistance(dir,i,uvSlice,corners);
+      if(d < dToClosest)
+        {
+        dToClosest = d;
+        iClosest = i;
+        }
+      }
+
+    // Highlight the selected edge
+    if(iClosest >= 0)
+      {
+      h.Highlighted[dir][iClosest] = true;
+      }
+    }
+
+  // Also test for an inside click (all selected)
+  if(!h.AnyHighlighted())
+    {
+    // Are we inside?
+    if(uvSlice[0] > std::min(corners[0][0], corners[1][0]) &&
+       uvSlice[0] < std::max(corners[0][0], corners[1][0]) &&
+       uvSlice[1] > std::min(corners[0][1], corners[1][1]) &&
+       uvSlice[1] < std::max(corners[0][1], corners[1][1]))
+      {
+      h.Highlighted[0][0]=true;
+      h.Highlighted[0][1]=true;
+      h.Highlighted[1][0]=true;
+      h.Highlighted[1][1]=true;
+      }
+    }
+
+  return h;
+}
+
+bool SnakeROIModel::ProcessPushEvent(float x, float y)
+{
+  // Convert the event location into slice u,v coordinates
+  Vector2f uvSlice(x, y);
+
+  // Record the system's corners at the time of drag start
+  GetSystemROICorners(m_CornerDragStart);
+
+  // Compute the selection
+  SnakeROISideSelectionState hl = ComputeSelection(uvSlice, m_CornerDragStart);
+  if(hl != m_Highlight)
+    {
+    m_Highlight = hl;
+    InvokeEvent(ModelUpdateEvent());
+    }
+
+  // If nothing was highlighted, then return and let the next handler process
+  // the event
+  return m_Highlight.AnyHighlighted();
+}
+
+bool SnakeROIModel
+::ProcessMoveEvent(float x, float y)
+{
+  // Convert the event location into slice u,v coordinates
+  Vector2f uvSlice(x, y);
+
+  // Record the system's corners at the time of drag start
+  GetSystemROICorners(m_CornerDragStart);
+
+  // Compute the selection
+  SnakeROISideSelectionState hl = ComputeSelection(uvSlice, m_CornerDragStart);
+  if(hl != m_Highlight)
+    {
+    m_Highlight = hl;
+    InvokeEvent(ModelUpdateEvent());
+    }
+
+  return true;
+}
+
+bool SnakeROIModel::ProcessDragEvent(
+    float x, float y, float xStart, float yStart, bool release)
+{
+  // Only do something if there is a highlight
+  if(m_Highlight.AnyHighlighted())
+    {
+    // Update the corners in response to the dragging
+    UpdateCorners(Vector2f(x, y), Vector2f(xStart,yStart));
+
+    // Event has been handled
+    return true;
+    }
+
+  // Event has not been handled
+  return false;
+}
+
+// The click detection radius (delta)
+const unsigned int SnakeROIModel::m_PixelDelta = 8;
+
+
+void
+SnakeROIModel
+::GetEdgeVertices(unsigned int direction,unsigned int index,
+                  Vector2f &x0,Vector2f &x1,
+                  const Vector3f corner[2])
+{
+  x0(direction) = corner[0](direction);
+  x1(direction) = corner[1](direction);
+  x0(1-direction) = x1(1-direction) = corner[index](1-direction);
+}
+
+float
+SnakeROIModel
+::GetEdgeDistance(unsigned int direction,
+                  unsigned int index,
+                  const Vector2f &x,
+                  const Vector3f corner[2])
+{
+  // Compute the vertices of the edge
+  Vector2f x0,x1;
+  GetEdgeVertices(direction,index,x0,x1,corner);
+
+  // Compute the squared distance between the vertices
+  float l2 = (x1-x0).squared_magnitude();
+  float l = sqrt(l2);
+
+  // Compute the projection of x onto x1-x0
+  float p = dot_product(x-x0,x1-x0) / sqrt(l2);
+  float p2 = p*p;
+
+  // Compute the squared distance to the line of the edge
+  float q2 = (x-x0).squared_magnitude() - p2;
+
+  // Compute the total distance
+  float d = sqrt(q2 + (p < 0 ? p2 : 0) + (p > l ? (p-l)*(p-l) : 0));
+
+  // Return this distance
+  return d;
+}
+
+void SnakeROIModel
+::GetSystemROICorners(Vector3f corner[2])
+{
+  // Get the region of interest in image coordinates
+  GlobalState *gs = m_Parent->GetDriver()->GetGlobalState();
+  GlobalState::RegionType roi = gs->GetSegmentationROI();
+
+  // Get the lower-valued corner
+  Vector3l ul(roi.GetIndex().GetIndex());
+
+  // Get the higher valued corner
+  Vector3ul sz(roi.GetSize().GetSize());
+
+  // Remap to slice coordinates
+  corner[0] = m_Parent->MapImageToSlice(to_float(ul));
+  corner[1] = m_Parent->MapImageToSlice(to_float(ul+to_long(sz)));
+}
+
+void SnakeROIModel
+::UpdateCorners(const Vector2f &uvSliceNow, const Vector2f &uvSlicePress)
+{
+  // Compute the corners in slice coordinates
+  Vector3f corner[2];
+  GetSystemROICorners(corner);
+
+  // Get the current bounds and extents of the region of interest
+  Vector3f xCornerImage[2] = {
+    m_Parent->MapSliceToImage(corner[0]),
+    m_Parent->MapSliceToImage(corner[1])
+  };
+
+  Vector3f clamp[2][2] =
+  {
+    {
+      Vector3f(0.0f,0.0f,0.0f),
+      xCornerImage[1] - Vector3f(1.0f,1.0f,1.0f)
+    },
+    {
+      xCornerImage[0] + Vector3f(1.0f,1.0f,1.0f),
+      to_float(m_Parent->GetDriver()->GetCurrentImageData()->GetVolumeExtents())
+    }
+  };
+
+  // For each highlighted edge, update the coordinates of the affected vertex
+  // by clamping to the maximum range
+  for (unsigned int dir=0;dir<2;dir++)
+    {
+    for (unsigned int i=0;i<2;i++)
+      {
+      if (m_Highlight.Highlighted[dir][i])
+        {
+        // Horizontal edge affects the y of the vertex and vice versa
+        corner[i](1-dir) =
+          m_CornerDragStart[i](1-dir) + uvSliceNow(1-dir) - uvSlicePress(1-dir);
+
+        // Map the affected vertex to image space
+        Vector3f vImage = m_Parent->MapSliceToImage(corner[i]);
+
+        // Clamp the affected vertex in image space
+        Vector3f vImageClamped = vImage.clamp(clamp[i][0],clamp[i][1]);
+
+        // Map the affected vertex back into slice space
+        corner[i] = m_Parent->MapImageToSlice(vImageClamped);
+        }
+      }
+    }
+
+  // Update the region of interest in the system
+  Vector3i xImageLower = to_int(m_Parent->MapSliceToImage(corner[0]));
+  Vector3i xImageUpper = to_int(m_Parent->MapSliceToImage(corner[1]));
+
+  // Create a region based on the corners
+  GlobalState::RegionType roiCorner(
+    to_itkIndex(xImageLower),to_itkSize(xImageUpper-xImageLower));
+
+  // Get the system's region of interest
+  GlobalState *gs = m_Parent->GetDriver()->GetGlobalState();
+  GlobalState::RegionType roiSystem = gs->GetSegmentationROI();
+
+  // The slice z-direction index and size in the ROI should retain the system's
+  // previous value because we are only manipulating the slice in 2D
+  unsigned int idx = m_Parent->GetSliceDirectionInImageSpace();
+  roiCorner.SetIndex(idx,roiSystem.GetIndex(idx));
+  roiCorner.SetSize(idx,roiSystem.GetSize(idx));
+
+  // Update the system's ROI (TODO: make this fire an event!)
+  gs->SetSegmentationROI(roiCorner);
+}
+
+void SnakeROIModel::ResetROI()
+{
+  // Region of interest from the main image
+  GlobalState::RegionType roi =
+      m_Parent->GetDriver()->GetCurrentImageData()->GetImageRegion();
+
+  // Can't be empty!
+  assert(roi.GetNumberOfPixels());
+
+  // Update
+  m_Parent->GetDriver()->GetGlobalState()->SetSegmentationROI(roi);
+}
+
+void SnakeROIModel::ProcessLeaveEvent()
+{
+  // Turn off the highlight
+  SnakeROISideSelectionState blank;
+  if(m_Highlight != blank)
+    {
+    m_Highlight = blank;
+    InvokeEvent(ModelUpdateEvent());
+    }
+}
+
+void SnakeROIModel::ProcessEnterEvent()
+{
+  // Nothing to do here!
+}
+
+
diff --git a/GUI/Model/SnakeROIModel.h b/GUI/Model/SnakeROIModel.h
new file mode 100644
index 0000000..3c32058
--- /dev/null
+++ b/GUI/Model/SnakeROIModel.h
@@ -0,0 +1,141 @@
+#ifndef SNAKEROIMODEL_H
+#define SNAKEROIMODEL_H
+
+#include <SNAPCommon.h>
+#include "AbstractModel.h"
+#include <IRISException.h>
+#include "PropertyModel.h"
+
+class GenericSliceModel;
+
+struct SnakeROISideSelectionState
+{
+  /**
+   * The four edges in the rectangle, ordered first by orientation
+   * (0 = horizontal), (1 = vertical) and then by adjacency to the
+   * first or second vertex of the cardinal cube defining the region
+   * of interest (0 = closest to 0,0,0), (1 = closest to sx,sy,sz)
+   */
+  bool Highlighted[2][2];
+
+  bool AnyHighlighted()
+  {
+    return (Highlighted[0][0] ||
+            Highlighted[0][1] ||
+            Highlighted[1][0] ||
+            Highlighted[1][1]);
+
+  }
+
+  SnakeROISideSelectionState()
+  {
+    Highlighted[0][0] = Highlighted[0][1] =
+        Highlighted[1][0] = Highlighted[1][1] = false;
+  }
+
+  SnakeROISideSelectionState(const SnakeROISideSelectionState &ref)
+  {
+    Highlighted[0][0] = ref.Highlighted[0][0];
+    Highlighted[0][1] = ref.Highlighted[0][1];
+    Highlighted[1][0] = ref.Highlighted[1][0];
+    Highlighted[1][1] = ref.Highlighted[1][1];
+  }
+
+  bool operator == (const SnakeROISideSelectionState &ref)
+  {
+    return (Highlighted[0][0] == ref.Highlighted[0][0] &&
+            Highlighted[0][1] == ref.Highlighted[0][1] &&
+            Highlighted[1][0] == ref.Highlighted[1][0] &&
+            Highlighted[1][1] == ref.Highlighted[1][1]);
+  }
+
+  bool operator != (const SnakeROISideSelectionState &ref)
+  {
+    return !(*this == ref);
+  }
+};
+
+/**
+  This class handles the interaction with the selection box.
+
+  TODO: The interaction could be improved to do things like highlight
+  the edge under the mouse on mouse motion, to change the cursor when
+  the mouse is over the draggable region, etc. Also it would be nice
+  to always show the box (even when the cursor is outside of the selection)
+  and to use a fill to indicate that a region is outside of the ROI. But
+  all this is easy to change.
+
+  The model also provides the property models for the dialog used to resample
+  the snake ROI.
+*/
+
+class SnakeROIModel : public AbstractModel
+{
+public:
+  irisITKObjectMacro(SnakeROIModel, AbstractModel)
+
+  irisGetMacro(Parent, GenericSliceModel *)
+
+  void SetParent(GenericSliceModel *);
+
+  bool ProcessPushEvent(float x, float y);
+
+  bool ProcessDragEvent(
+      float x, float y, float xStart, float yStart, bool release);
+
+  bool ProcessMoveEvent(float x, float y);
+
+  void ProcessLeaveEvent();
+  void ProcessEnterEvent();
+
+  void ResetROI();
+
+  friend class SnakeROIRenderer;
+
+
+protected:
+
+  // The click detection radius (delta)
+  static const unsigned int m_PixelDelta;
+
+  // Four vertices in the region box (correspond to the two corners
+  // of the 3D region of interest
+  Vector3f m_CornerDragStart[2];
+
+  /**
+   * The four edges in the rectangle, ordered first by orientation
+   * (0 = horizontal), (1 = vertical) and then by adjacency to the
+   * first or second vertex of the cardinal cube defining the region
+   * of interest (0 = closest to 0,0,0), (1 = closest to sx,sy,sz)
+   */
+  SnakeROISideSelectionState m_Highlight;
+
+  /** Map from system's ROI in image coordinates to 2D slice coords */
+  void GetSystemROICorners(Vector3f corner[2]);
+
+  /** Compute the slice-space vertices corresponding to an edge */
+  void GetEdgeVertices(unsigned int direction,
+    unsigned int index,Vector2f &x0,Vector2f &x1,const Vector3f corner[2]);
+
+  /** Compute a distance to an edge */
+  float GetEdgeDistance(unsigned int direction,
+    unsigned int index,const Vector2f &point,const Vector3f corner[2]);
+
+  /**
+   * Update the region of interest in response to the dragging or release
+   * operations.
+   */
+  void UpdateCorners(const Vector2f &xPress, const Vector2f &xDrag);
+
+  SnakeROISideSelectionState ComputeSelection(Vector2f &uvSlice, Vector3f corners[]);
+
+  // Parent model
+  GenericSliceModel *m_Parent;
+
+  // Private constructor stuff
+  SnakeROIModel();
+  virtual ~SnakeROIModel() {}
+
+};
+
+#endif // SNAKEROIMODEL_H
diff --git a/GUI/Model/SnakeROIResampleModel.cxx b/GUI/Model/SnakeROIResampleModel.cxx
new file mode 100644
index 0000000..d00d5d5
--- /dev/null
+++ b/GUI/Model/SnakeROIResampleModel.cxx
@@ -0,0 +1,256 @@
+#include "SnakeROIResampleModel.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "SNAPSegmentationROISettings.h"
+
+SnakeROIResampleModel::SnakeROIResampleModel()
+{
+  // Set up the property models
+  for(int i = 0; i < 3; i++)
+    {
+    m_InputSpacingModel[i] = wrapIndexedGetterSetterPairAsProperty(
+          this, i, &Self::GetInputSpacingValueAndRange);
+
+    m_InputDimensionsModel[i] = wrapIndexedGetterSetterPairAsProperty(
+          this, i, &Self::GetInputDimensionsValueAndRange);
+
+    m_OutputSpacingModel[i] = wrapIndexedGetterSetterPairAsProperty(
+          this, i, &Self::GetOutputSpacingValueAndRange, &Self::SetOutputSpacingValue);
+
+    m_OutputDimensionsModel[i] = wrapIndexedGetterSetterPairAsProperty(
+          this, i, &Self::GetOutputDimensionsValueAndRange, &Self::SetOutputDimensionsValue);
+    }
+
+  // Aspect ratio
+  m_FixedAspectRatioModel = NewSimpleConcreteProperty(false);
+
+  // Create the interpolation model
+  m_InterpolationModeModel = ConcreteInterpolationModeModel::New();
+}
+
+void SnakeROIResampleModel::SetParentModel(GlobalUIModel *model)
+{
+  m_Parent = model;
+  m_ROISettingsModel =
+      m_Parent->GetDriver()->GetGlobalState()->GetSegmentationROISettingsModel();
+
+  // Listen to changes in the parent's segmentation ROI settings
+  Rebroadcast(m_ROISettingsModel, ValueChangedEvent(), ModelUpdateEvent());
+
+  // Layer change events too
+  Rebroadcast(m_Parent->GetDriver(), LayerChangeEvent(), ModelUpdateEvent());
+}
+
+void SnakeROIResampleModel::Reset()
+{
+  SNAPSegmentationROISettings roi = m_ROISettingsModel->GetValue();
+  m_ResampleDimensions = roi.GetROI().GetSize();
+  m_InterpolationModeModel->SetValue(SNAPSegmentationROISettings::TRILINEAR);
+  InvokeEvent(ModelUpdateEvent());
+}
+
+void SnakeROIResampleModel::Accept()
+{
+  SNAPSegmentationROISettings roi = m_ROISettingsModel->GetValue();
+  roi.SetResampleDimensions(m_ResampleDimensions);
+  roi.SetInterpolationMethod(m_InterpolationModeModel->GetValue());
+  m_ROISettingsModel->SetValue(roi);
+}
+
+void SnakeROIResampleModel::ApplyPreset(SnakeROIResampleModel::ResamplePreset preset)
+{
+  // Get the current spacing
+  IRISApplication *app = m_Parent->GetDriver();
+  Vector3d in_spacing = app->GetCurrentImageData()->GetImageSpacing();
+  Vector3d out_spacing;
+
+  if(preset == SUPER_2)
+    {
+    out_spacing = in_spacing / 2.0;
+    }
+  else if(preset == SUB_2)
+    {
+    out_spacing = in_spacing * 2.0;
+    }
+  if(preset == SUPER_ISO)
+    {
+    double mindim = in_spacing.min_value();
+    out_spacing.fill(mindim);
+    this->SetFixedAspectRatio(false);
+    }
+  else if(preset == SUB_ISO)
+    {
+    double maxdim = in_spacing.max_value();
+    out_spacing.fill(maxdim);
+    this->SetFixedAspectRatio(false);
+    }
+
+  for(int i = 0; i < 3; i++)
+    m_OutputSpacingModel[i]->SetValue(out_spacing[i]);
+
+}
+
+void SnakeROIResampleModel::ComputeCachedDomains()
+{
+  IRISApplication *app = m_Parent->GetDriver();
+  Vector3d spacing = app->GetCurrentImageData()->GetImageSpacing();
+  SNAPSegmentationROISettings roi = m_ROISettingsModel->GetValue();
+
+  // The reasonable range for the value is not obvious. The largest possible
+  // value should be the dimension of the image times the voxel size. The
+  // smallest should be something reasonable, like voxel size/10, rounded,
+  // since any larger interpolation would be infeasible. The step should probably
+  // equal the smallest value
+  Vector3ui sz = roi.GetROI().GetSize();
+  for(int i = 0; i < 3; i++)
+    {
+    double step = pow(10, floor(log10(spacing[i] / 10.0)));
+    m_SpacingDomain[i].Set(step, sz[i] * spacing[i], step);
+    m_DimensionsDomain[i].Set(1, sz[i]*10, 1);
+    }
+
+  // TODO: higher order interpolation methods are currently unsupported for
+  // vector images. This is a problem and should be fixed
+
+  // Set up the interpolation mode map
+  m_InterpolationModeDomain[SNAPSegmentationROISettings::NEAREST_NEIGHBOR] =
+      "Nearest neighbor (fast)";
+  m_InterpolationModeDomain[SNAPSegmentationROISettings::TRILINEAR] =
+      "Linear interpolation (better quality)";
+  // m_InterpolationModeDomain[SNAPSegmentationROISettings::TRICUBIC] =
+  //     "Cubic interpolation (high quality)";
+  // m_InterpolationModeDomain[SNAPSegmentationROISettings::SINC_WINDOW_05] =
+  //     "Windowed sinc interpolation (best quality)";
+
+  m_InterpolationModeModel->SetDomain(m_InterpolationModeDomain);
+
+}
+
+void SnakeROIResampleModel::EnforceAspectRatio(int source_idx)
+{
+  SNAPSegmentationROISettings roi = m_ROISettingsModel->GetValue();
+
+  double aspect = m_ResampleDimensions[source_idx] * 1.0 / roi.GetROI().GetSize()[source_idx];
+
+  for(int i = 0; i < 3; i++)
+    {
+    if(i != source_idx)
+      {
+      unsigned int new_dim =
+          itk::Math::Round<double>(aspect * roi.GetROI().GetSize()[i]);
+      m_ResampleDimensions[i] = new_dim >= 1 ? new_dim : 1;
+      }
+    }
+}
+
+void SnakeROIResampleModel::OnUpdate()
+{
+  if(this->m_EventBucket->HasEvent(LayerChangeEvent()) ||
+     this->m_EventBucket->HasEvent(ValueChangedEvent(), m_ROISettingsModel))
+    {
+    if(m_Parent->GetDriver()->IsMainImageLoaded())
+      {
+      ComputeCachedDomains();
+      SNAPSegmentationROISettings roi = m_ROISettingsModel->GetValue();
+      m_ResampleDimensions = roi.GetResampleDimensions();
+      m_InterpolationModeModel->SetValue(roi.GetInterpolationMethod());
+      }
+    }
+}
+
+bool SnakeROIResampleModel::GetInputSpacingValueAndRange(int index,
+    double &value, NumericValueRange<double> *domain)
+{
+  IRISApplication *app = m_Parent->GetDriver();
+  if(app->IsMainImageLoaded())
+    {
+    value = app->GetCurrentImageData()->GetImageSpacing()[index];
+
+    if(domain)
+      *domain = m_SpacingDomain[index];
+
+    return true;
+    }
+  return false;
+}
+
+bool SnakeROIResampleModel
+::GetInputDimensionsValueAndRange(
+    int index, unsigned int &value, NumericValueRange<unsigned int> *domain)
+{
+  IRISApplication *app = m_Parent->GetDriver();
+  if(app->IsMainImageLoaded())
+    {
+    SNAPSegmentationROISettings roi = m_ROISettingsModel->GetValue();
+    value = roi.GetROI().GetSize()[index];
+    return true;
+    }
+
+  return false;
+}
+
+bool SnakeROIResampleModel::GetOutputSpacingValueAndRange(
+    int index, double &value, NumericValueRange<double> *domain)
+{
+  IRISApplication *app = m_Parent->GetDriver();
+  if(app->IsMainImageLoaded())
+    {
+    Vector3d inSpacing = app->GetCurrentImageData()->GetImageSpacing();
+    SNAPSegmentationROISettings roi = m_ROISettingsModel->GetValue();
+    value = roi.GetROI().GetSize()[index] * inSpacing[index] / m_ResampleDimensions[index];
+
+    if(domain)
+      *domain = m_SpacingDomain[index];
+
+    return true;
+    }
+  return false;
+}
+
+void SnakeROIResampleModel::SetOutputSpacingValue(int index, double value)
+{
+  IRISApplication *app = m_Parent->GetDriver();
+  SNAPSegmentationROISettings roi = m_ROISettingsModel->GetValue();
+  Vector3d inSpacing = app->GetCurrentImageData()->GetImageSpacing();
+
+  // Calculate the dimensions
+  m_ResampleDimensions[index] = itk::Math::Round<double>(
+        roi.GetROI().GetSize()[index] * inSpacing[index] / value);
+
+  if(GetFixedAspectRatio())
+    EnforceAspectRatio(index);
+
+  InvokeEvent(ModelUpdateEvent());
+}
+
+bool SnakeROIResampleModel
+::GetOutputDimensionsValueAndRange(int index, unsigned int &value, NumericValueRange<unsigned int> *domain)
+{
+  IRISApplication *app = m_Parent->GetDriver();
+  SNAPSegmentationROISettings roi = m_ROISettingsModel->GetValue();
+  if(app->IsMainImageLoaded())
+    {
+    value = m_ResampleDimensions[index];
+    if(domain)
+      {
+      *domain = m_DimensionsDomain[index];
+      }
+    return true;
+    }
+
+  return false;
+}
+
+void SnakeROIResampleModel
+::SetOutputDimensionsValue(int index, unsigned int value)
+{
+  m_ResampleDimensions[index] = value;
+
+  if(GetFixedAspectRatio())
+    EnforceAspectRatio(index);
+
+  InvokeEvent(ModelUpdateEvent());
+}
+
+
diff --git a/GUI/Model/SnakeROIResampleModel.h b/GUI/Model/SnakeROIResampleModel.h
new file mode 100644
index 0000000..3f64b49
--- /dev/null
+++ b/GUI/Model/SnakeROIResampleModel.h
@@ -0,0 +1,100 @@
+#ifndef SNAKEROIRESAMPLEMODEL_H
+#define SNAKEROIRESAMPLEMODEL_H
+
+#include "PropertyModel.h"
+#include "SNAPSegmentationROISettings.h"
+
+class GlobalUIModel;
+
+/**
+ * @brief The SnakeROIResampleModel class
+ * Handles the resample snake dialog.
+ */
+class SnakeROIResampleModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(SnakeROIResampleModel, AbstractModel)
+
+  AbstractRangedDoubleProperty *GetInputSpacingModel(int index)
+    { return m_InputSpacingModel[index]; }
+
+  AbstractRangedUIntProperty *GetInputDimensionsModel(int index)
+    { return m_InputDimensionsModel[index]; }
+
+  AbstractRangedDoubleProperty *GetOutputSpacingModel(int index)
+    { return m_OutputSpacingModel[index]; }
+
+  AbstractRangedUIntProperty *GetOutputDimensionsModel(int index)
+    { return m_OutputDimensionsModel[index]; }
+
+  irisSimplePropertyAccessMacro(FixedAspectRatio, bool)
+
+  typedef SNAPSegmentationROISettings::InterpolationMethod InterpolationMode;
+  typedef SimpleItemSetDomain<InterpolationMode, std::string> InterpolationModeDomain;
+  typedef AbstractPropertyModel<InterpolationMode, InterpolationModeDomain> AbstractInterpolationModeModel;
+
+  irisGetMacro(InterpolationModeModel, AbstractInterpolationModeModel *)
+
+  void SetParentModel(GlobalUIModel *model);
+
+  /** Reset to default (no scaling) */
+  void Reset();
+
+  /** Accept the user's changes */
+  void Accept();
+
+  /** Availabel quick presets */
+  enum ResamplePreset {
+    SUPER_2, SUB_2, SUPER_ISO, SUB_ISO
+  };
+
+  void ApplyPreset(ResamplePreset preset);
+
+protected:
+
+  SnakeROIResampleModel();
+  virtual ~SnakeROIResampleModel() {}
+
+  GlobalUIModel *m_Parent;
+  AbstractPropertyModel<SNAPSegmentationROISettings> *m_ROISettingsModel;
+
+  SmartPtr<AbstractRangedDoubleProperty> m_InputSpacingModel[3];
+  bool GetInputSpacingValueAndRange(int index, double &value, NumericValueRange<double> *domain);
+
+  SmartPtr<AbstractRangedUIntProperty> m_InputDimensionsModel[3];
+  bool GetInputDimensionsValueAndRange(int index, unsigned int &value, NumericValueRange<unsigned int > *domain);
+
+  SmartPtr<AbstractRangedDoubleProperty> m_OutputSpacingModel[3];
+  bool GetOutputSpacingValueAndRange(int index, double &value, NumericValueRange<double> *domain);
+  void SetOutputSpacingValue(int index, double value);
+
+  SmartPtr<AbstractRangedUIntProperty> m_OutputDimensionsModel[3];
+  bool GetOutputDimensionsValueAndRange(int index, unsigned int &value, NumericValueRange<unsigned int> *domain);
+  void SetOutputDimensionsValue(int index, unsigned int value);
+
+  SmartPtr<ConcreteSimpleBooleanProperty> m_FixedAspectRatioModel;
+
+  void ComputeCachedDomains();
+
+  void EnforceAspectRatio(int source_idx);
+
+  virtual void OnUpdate();
+
+  // Cached information about the ROI. This is where this model stores its
+  // state until the user says 'ok'
+  Vector3ui m_ResampleDimensions;
+
+  // Cached domain values - to avoid recomputing all the time
+  NumericValueRange<double> m_SpacingDomain[3];
+  NumericValueRange<unsigned int> m_DimensionsDomain[3];
+
+  // Map for interpolation modes
+  InterpolationModeDomain m_InterpolationModeDomain;
+
+  // Model for the interpolation modes
+  typedef ConcretePropertyModel<InterpolationMode, InterpolationModeDomain> ConcreteInterpolationModeModel;
+  SmartPtr<ConcreteInterpolationModeModel> m_InterpolationModeModel;
+};
+
+#endif // SNAKEROIRESAMPLEMODEL_H
diff --git a/GUI/Model/SnakeWizardModel.cxx b/GUI/Model/SnakeWizardModel.cxx
new file mode 100644
index 0000000..865d28e
--- /dev/null
+++ b/GUI/Model/SnakeWizardModel.cxx
@@ -0,0 +1,1579 @@
+#include "SnakeWizardModel.h"
+#include "GlobalUIModel.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "GlobalState.h"
+#include "GenericImageData.h"
+#include "SNAPImageData.h"
+#include "SmoothBinaryThresholdImageFilter.h"
+#include "EdgePreprocessingImageFilter.h"
+#include "ColorMap.h"
+#include "SlicePreviewFilterWrapper.h"
+#include "UnsupervisedClustering.h"
+#include "PreprocessingFilterConfigTraits.h"
+#include "GMMClassifyImageFilter.h"
+#include "RFClassificationEngine.h"
+#include "RandomForestClassifier.h"
+#include "RandomForestClassifyImageFilter.h"
+
+SnakeWizardModel::SnakeWizardModel()
+{
+  // Set up the child models
+  m_ThresholdUpperModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetThresholdUpperValueAndRange,
+        &Self::SetThresholdUpperValue,
+        ThresholdSettingsUpdateEvent(),
+        ThresholdSettingsUpdateEvent());
+
+  m_ThresholdLowerModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetThresholdLowerValueAndRange,
+        &Self::SetThresholdLowerValue,
+        ThresholdSettingsUpdateEvent(),
+        ThresholdSettingsUpdateEvent());
+
+  m_ThresholdSmoothnessModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetThresholdSmoothnessValueAndRange,
+        &Self::SetThresholdSmoothnessValue,
+        ThresholdSettingsUpdateEvent(),
+        ThresholdSettingsUpdateEvent());
+
+  m_ThresholdModeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetThresholdModeValue,
+        &Self::SetThresholdModeValue,
+        ThresholdSettingsUpdateEvent(),
+        ThresholdSettingsUpdateEvent());
+
+  m_ThresholdActiveLayerModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetThresholdActiveLayerValueAndRange,
+        &Self::SetThresholdActiveLayerValue,
+        ThresholdSettingsUpdateEvent(),
+        ThresholdSettingsUpdateEvent());
+
+  m_ThresholdActiveScalarRepModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetThresholdActiveScalarRepValueAndRange,
+        &Self::SetThresholdActiveScalarRepValue,
+        ThresholdSettingsUpdateEvent(),
+        ThresholdSettingsUpdateEvent());
+
+  m_PreviewModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetPreviewValue,
+        &Self::SetPreviewValue);
+
+  m_BlueWhiteSpeedModeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetBlueWhiteSpeedModeValue,
+        &Self::SetBlueWhiteSpeedModeValue);
+
+  m_RedTransparentSpeedModeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetRedTransparentSpeedModeValue,
+        &Self::SetRedTransparentSpeedModeValue);
+
+  // TODO: which events from the parent model should be rebroadcast by the
+  // preview model?
+
+  // EdgePreprocessingSettingsUpdateEvent(),
+  // EdgePreprocessingSettingsUpdateEvent()
+
+  m_EdgePreprocessingSigmaModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetEdgePreprocessingSigmaValueAndRange,
+        &Self::SetEdgePreprocessingSigmaValue,
+        EdgePreprocessingSettingsUpdateEvent(),
+        EdgePreprocessingSettingsUpdateEvent());
+
+  m_EdgePreprocessingKappaModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetEdgePreprocessingKappaValueAndRange,
+        &Self::SetEdgePreprocessingKappaValue,
+        EdgePreprocessingSettingsUpdateEvent(),
+        EdgePreprocessingSettingsUpdateEvent());
+
+  m_EdgePreprocessingExponentModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetEdgePreprocessingExponentValueAndRange,
+        &Self::SetEdgePreprocessingExponentValue,
+        EdgePreprocessingSettingsUpdateEvent(),
+        EdgePreprocessingSettingsUpdateEvent());
+
+  m_SnakeTypeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetSnakeTypeValueAndRange,
+        &Self::SetSnakeTypeValue);
+
+  // Preprocessing mode model initialization
+  m_PreprocessingModeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetPreprocessingModeValueAndRange,
+        &Self::SetPreprocessingModeValue);
+
+  m_ActiveBubbleModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetActiveBubbleValue,
+        &Self::SetActiveBubbleValue,
+        ActiveBubbleUpdateEvent());
+
+  m_BubbleRadiusModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetBubbleRadiusValueAndRange,
+        &Self::SetBubbleRadiusValue,
+        BubbleDefaultRadiusUpdateEvent(),
+        BubbleDefaultRadiusUpdateEvent());
+
+  m_StepSizeModel = NewRangedConcreteProperty(1, 1, 100, 1);
+
+  // Need to define a null setter function
+  void (Self::*nullsetter)(int) = NULL;
+
+  m_EvolutionIterationModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetEvolutionIterationValue,
+        nullsetter,
+        EvolutionIterationEvent());
+
+  m_NumberOfClustersModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetNumberOfClustersValueAndRange,
+        &Self::SetNumberOfClustersValue,
+        GMMModifiedEvent(),
+        GMMModifiedEvent());
+
+  m_NumberOfGMMSamplesModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetNumberOfGMMSamplesValueAndRange,
+        &Self::SetNumberOfGMMSamplesValue,
+        GMMModifiedEvent(),
+        GMMModifiedEvent());
+
+  m_ForegroundClusterModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetForegroundClusterValueAndRange,
+        &Self::SetForegroundClusterValue,
+        GMMModifiedEvent(),
+        GMMModifiedEvent());
+
+  m_ForegroundClassColorLabelModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetForegroundClassColorLabelValueAndRange,
+        &Self::SetForegroundClassColorLabelValue,
+        RFClassifierModifiedEvent(),
+        RFClassifierModifiedEvent());
+
+  m_ForestSizeModel = wrapGetterSetterPairAsProperty(
+        this,
+        &Self::GetForestSizeValueAndRange,
+        &Self::SetForestSizeValue,
+        RFClassifierModifiedEvent(),
+        RFClassifierModifiedEvent());
+
+  // The domain of the foreground cluster model depends on the number of clusters
+  m_ForegroundClusterModel->Rebroadcast(
+        m_NumberOfClustersModel, ValueChangedEvent(), DomainChangedEvent());
+
+  m_ClusterPlottedComponentModel = ComponentIndexModel::New();
+  this->UpdateClusterPlottedComponentModel();
+
+  m_InteractionMode = MODE_NONE;
+}
+
+void SnakeWizardModel::SetParentModel(GlobalUIModel *model)
+{
+  m_Parent = model;
+  m_Driver = m_Parent->GetDriver();
+  m_GlobalState = m_Driver->GetGlobalState();
+
+  // Layer changes are rebroadcast as model changes, causing all child
+  // models to update themselves.
+  Rebroadcast(m_Driver, LayerChangeEvent(), ModelUpdateEvent());
+
+  // Model update events are the "big events", and are rebroadcast
+  // as the specialized events as well.
+  Rebroadcast(this, ModelUpdateEvent(), ThresholdSettingsUpdateEvent());
+
+  // Changes to the threshold settings are rebroadcast as own own events
+  Rebroadcast(m_Driver,
+              WrapperProcessingSettingsChangeEvent(), ThresholdSettingsUpdateEvent());
+
+  // Changes to the preview pipeline (preview status) are broadcast as events
+  Rebroadcast(m_Driver->GetPreprocessingFilterPreviewer(PREPROCESS_THRESHOLD),
+              itk::ModifiedEvent(), ThresholdSettingsUpdateEvent());
+
+  // Repeat the same code for the edge preprocessing
+  Rebroadcast(this, ModelUpdateEvent(), EdgePreprocessingSettingsUpdateEvent());
+
+  Rebroadcast(m_Driver->GetEdgePreprocessingSettings(),
+              itk::ModifiedEvent(), EdgePreprocessingSettingsUpdateEvent());
+
+  Rebroadcast(m_Driver->GetPreprocessingFilterPreviewer(PREPROCESS_EDGE),
+              itk::ModifiedEvent(), EdgePreprocessingSettingsUpdateEvent());
+
+  Rebroadcast(m_Driver->GetPreprocessingFilterPreviewer(PREPROCESS_GMM),
+              itk::ModifiedEvent(), GMMModifiedEvent());
+
+  Rebroadcast(m_Driver->GetPreprocessingFilterPreviewer(PREPROCESS_RF),
+              itk::ModifiedEvent(), RFClassifierModifiedEvent());
+
+  // Changes to the snake mode are cast as model update events
+  Rebroadcast(m_GlobalState->GetSnakeTypeModel(),
+              ValueChangedEvent(), ModelUpdateEvent());
+
+  // We also need to rebroadcast these events as state change events
+  Rebroadcast(this, ThresholdSettingsUpdateEvent(), StateMachineChangeEvent());
+  Rebroadcast(this, EdgePreprocessingSettingsUpdateEvent(), StateMachineChangeEvent());
+  Rebroadcast(this, ModelUpdateEvent(), StateMachineChangeEvent());
+  Rebroadcast(this, ActiveBubbleUpdateEvent(), StateMachineChangeEvent());
+  Rebroadcast(this, RFClassifierModifiedEvent(), StateMachineChangeEvent());
+
+  // The two appearance mode models depend on changes to the color map and
+  // the metadata of the speed image wrapper
+  m_BlueWhiteSpeedModeModel->Rebroadcast(
+        m_Driver, WrapperChangeEvent(), ValueChangedEvent());
+
+  m_RedTransparentSpeedModeModel->Rebroadcast(
+        m_Driver, WrapperChangeEvent(), ValueChangedEvent());
+}
+
+
+bool SnakeWizardModel::CheckState(SnakeWizardModel::UIState state)
+{
+  ThresholdSettings *ts = this->GetThresholdSettings();
+  switch(state)
+    {
+    case UIF_BUBBLE_MODE:
+      return m_InteractionMode == MODE_BUBBLES;
+    case UIF_THESHOLDING_ENABLED:
+      return AreThresholdModelsActive();
+    case UIF_LOWER_THRESHOLD_ENABLED:
+      return ts && ts->IsLowerThresholdEnabled();
+    case UIF_UPPER_THRESHOLD_ENABLED:
+      return ts && ts->IsUpperThresholdEnabled();
+    case UIF_EDGEPROCESSING_ENABLED:
+      return AreEdgePreprocessingModelsActive();
+    case UIF_CAN_GENERATE_SPEED:
+      return CanGenerateSpeedVolume();
+    case UIF_SPEED_AVAILABLE:
+      return m_GlobalState->GetSpeedValid();
+    case UIF_PREPROCESSING_ACTIVE:
+      return m_Driver->GetPreprocessingMode() != PREPROCESS_NONE;
+    case UIF_BUBBLE_SELECTED:
+      return m_GlobalState->GetActiveBubble() >= 0;
+    case UIF_INITIALIZATION_VALID:
+      return m_GlobalState->GetSnakeInitializedWithManualSegmentation()
+          || m_Driver->GetBubbleArray().size() > 0;
+    }
+
+  return false;
+}
+
+
+void SnakeWizardModel::OnUpdate()
+{
+  // If there is a change in available layers, we must rebuild the list
+  // of available components.
+  if(m_EventBucket->HasEvent(LayerChangeEvent()))
+    {
+    m_ComponentInfo.clear();
+    LayerIterator it = m_Driver->GetSNAPImageData()->GetLayers(
+          MAIN_ROLE | OVERLAY_ROLE);
+    for(; !it.IsAtEnd(); ++it)
+      {
+      if(VectorImageWrapperBase *viw = it.GetLayerAsVector())
+        {
+        for(int comp = 0; comp < it.GetLayerAsVector()->GetNumberOfComponents(); ++comp)
+          {
+          ComponentInfo ci;
+          ci.ImageWrapper = viw;
+          ci.ComponentWrapper = viw->GetScalarRepresentation(
+                SCALAR_REP_COMPONENT, comp);
+          ci.ComponentIndex = comp;
+          m_ComponentInfo.push_back(ci);
+          }
+        }
+      else
+        {
+        ComponentInfo ci;
+        ci.ImageWrapper = ci.ComponentWrapper = it.GetLayerAsScalar();
+        ci.ComponentIndex = 0;
+        m_ComponentInfo.push_back(ci);
+        }
+      }
+
+    this->UpdateClusterPlottedComponentModel();
+    }
+}
+
+ScalarImageWrapperBase *SnakeWizardModel::GetActiveScalarLayer(PreprocessingMode mode)
+{
+  return m_Driver->GetPreprocessingFilterPreviewer(mode)->GetActiveScalarLayer();
+}
+
+void SnakeWizardModel::OnBubbleModeBack()
+{
+  SetInteractionMode(MODE_PREPROCESSING);
+
+  // Set the current preprocessing mode.
+  PreprocessingMode lastMode = m_GlobalState->GetLastUsedPreprocessingMode();
+  m_PreprocessingModeModel->SetValue(lastMode);
+}
+
+void SnakeWizardModel::UpdateClusterPlottedComponentModel()
+{
+  this->m_ClusterPlottedComponentModel->SetValue(0);
+  ComponentDomain cd;
+  for(int i = 0; i < m_ComponentInfo.size(); i++)
+    {
+    std::ostringstream oss;
+    oss << (i+1) << " : " << m_ComponentInfo[i].ImageWrapper->GetNickname();
+    cd[i] = oss.str();
+    }
+  this->m_ClusterPlottedComponentModel->SetDomain(cd);
+}
+
+bool SnakeWizardModel::GetForegroundClassColorLabelValueAndRange(
+    LabelType &value, SnakeWizardModel::ForegroundClassDomain *range)
+{
+  // Must have a classification engine
+  RFClassificationEngine *rfe = m_Driver->GetClassificationEngine();
+  if(!rfe)
+    return false;
+
+  // Must have a classifier
+  RandomForestClassifier *rfc = rfe->GetClassifier();
+  if(!rfc)
+    return false;
+
+  // The classifier must be valid (2 or more classes)
+  if(!rfc->IsValidClassifier())
+    return false;
+
+  // Set the class label to the one stored in the classifier
+  value = rfc->GetForegroundClassLabel();
+
+  // Set the range to the correct range
+  if(range)
+    range->SetWrappedMap(&m_ActiveClasses);
+
+  return true;
+}
+
+void SnakeWizardModel::SetForegroundClassColorLabelValue(LabelType value)
+{
+  RFClassificationEngine *rfe = m_Driver->GetClassificationEngine();
+  assert(rfe);
+
+  RandomForestClassifier *rfc = rfe->GetClassifier();
+  assert(rfc);
+
+  rfc->SetForegroundClassLabel(value);
+
+  InvokeEvent(RFClassifierModifiedEvent());
+
+  // TODO: this is a hack!
+  TagRFPreprocessingFilterModified();
+
+}
+
+bool SnakeWizardModel::GetForestSizeValueAndRange(int &value, NumericValueRange<int> *range)
+{
+  // Must have a classification engine
+  RFClassificationEngine *rfe = m_Driver->GetClassificationEngine();
+  if(!rfe)
+    return false;
+
+  value = rfe->GetForestSize();
+  if(range)
+    range->Set(10, 500, 10);
+
+  return true;
+}
+
+void SnakeWizardModel::SetForestSizeValue(int value)
+{
+  RFClassificationEngine *rfe = m_Driver->GetClassificationEngine();
+  assert(rfe);
+
+  rfe->SetForestSize(value);
+}
+
+void SnakeWizardModel::OnBubbleModeEnter()
+{
+  // When entering bubble mode, we should not use the overlay display of the
+  // speed image, as tht clashes with bubble placement visually
+  if(this->GetRedTransparentSpeedModeModel()->GetValue())
+    this->SetBlueWhiteSpeedModeValue(true);
+
+  // In bubble mode, we want the main toolbar to be in crosshairs mode
+  m_GlobalState->SetToolbarMode(CROSSHAIRS_MODE);
+
+  // We are in bubble mode
+  SetInteractionMode(MODE_BUBBLES);
+}
+
+
+bool SnakeWizardModel::AreThresholdModelsActive()
+{
+  return (m_Driver->IsSnakeModeActive() &&
+          m_Driver->GetPreprocessingMode() == PREPROCESS_THRESHOLD);
+}
+
+bool SnakeWizardModel::AreEdgePreprocessingModelsActive()
+{
+  return (m_Driver->IsSnakeModeActive() &&
+          m_Driver->GetPreprocessingMode() == PREPROCESS_EDGE);
+}
+
+bool SnakeWizardModel::CanGenerateSpeedVolume()
+{
+  // The answer depends on the proprocessing mode
+  switch(m_Driver->GetPreprocessingMode())
+    {
+    case PREPROCESS_NONE:
+      return false;
+    case PREPROCESS_THRESHOLD:
+      return true;
+    case PREPROCESS_EDGE:
+      return true;
+    case PREPROCESS_GMM:
+      return true;
+    case PREPROCESS_RF:
+      {
+      RFClassificationEngine *cfe = m_Driver->GetClassificationEngine();
+      RandomForestClassifier *rfc = cfe->GetClassifier();
+      return rfc->IsValidClassifier();
+      }
+    }
+}
+
+ScalarImageWrapperBase *SnakeWizardModel::GetSelectedScalarLayer()
+{
+  // TODO: this should be set by the wizard through user interaction.
+  // This is just a placeholder
+  return m_Driver->GetCurrentImageData()->GetMain()->GetDefaultScalarRepresentation();
+}
+
+bool SnakeWizardModel
+::GetThresholdUpperValueAndRange(
+    double &x, NumericValueRange<double> *range)
+{
+  if(!AreThresholdModelsActive())
+    return false;
+
+  ScalarImageWrapperBase *iw = this->GetActiveScalarLayer(PREPROCESS_THRESHOLD);
+  ThresholdSettings *ts = this->GetThresholdSettings();
+
+  // The thresholds are stored in internal image representation, but are
+  // presented to the user in native image representation.
+  x = iw->GetNativeIntensityMapping()->MapInternalToNative(ts->GetUpperThreshold());
+
+  if(range)
+    {
+    range->Minimum = iw->GetImageMinNative();
+    range->Maximum = iw->GetImageMaxNative();
+    range->StepSize = CalculatePowerOfTenStepSize(range->Minimum, range->Maximum, 1000);
+    }
+
+  return true;
+}
+
+bool SnakeWizardModel
+::GetThresholdLowerValueAndRange(
+    double &x, NumericValueRange<double> *range)
+{
+  if(!AreThresholdModelsActive())
+    return false;
+
+  ScalarImageWrapperBase *iw = this->GetActiveScalarLayer(PREPROCESS_THRESHOLD);
+  ThresholdSettings *ts = this->GetThresholdSettings();
+
+  // The thresholds are stored in internal image representation, but are
+  // presented to the user in native image representation.
+  x = iw->GetNativeIntensityMapping()->MapInternalToNative(ts->GetLowerThreshold());
+
+  if(range)
+    {
+    range->Minimum = iw->GetImageMinNative();
+    range->Maximum = iw->GetImageMaxNative();
+    range->StepSize = CalculatePowerOfTenStepSize(range->Minimum, range->Maximum, 1000);
+    }
+
+  return true;
+}
+
+void SnakeWizardModel
+::SetThresholdUpperValue(double x)
+{
+  // Map the value to internal format
+  ScalarImageWrapperBase *iw = this->GetActiveScalarLayer(PREPROCESS_THRESHOLD);
+  float z = (float) iw->GetNativeIntensityMapping()->MapNativeToInternal(x);
+
+  // Get the current settings
+  ThresholdSettings *ts = this->GetThresholdSettings();
+  if(z < ts->GetLowerThreshold())
+    ts->SetLowerThreshold(z);
+
+  ts->SetUpperThreshold(z);
+}
+
+void SnakeWizardModel
+::SetThresholdLowerValue(double x)
+{
+  // Map the value to internal format
+  ScalarImageWrapperBase *iw = this->GetActiveScalarLayer(PREPROCESS_THRESHOLD);
+  float z = (float) iw->GetNativeIntensityMapping()->MapNativeToInternal(x);
+
+  // Get the current settings
+  ThresholdSettings *ts = this->GetThresholdSettings();
+  if(z > ts->GetUpperThreshold())
+    ts->SetUpperThreshold(z);
+
+  ts->SetLowerThreshold(z);
+}
+
+bool
+SnakeWizardModel
+::GetThresholdSmoothnessValueAndRange(double &x, NumericValueRange<double> *range)
+{
+  if(!AreThresholdModelsActive())
+    return false;
+
+  ThresholdSettings *ts = this->GetThresholdSettings();
+  x = ts->GetSmoothness();
+  if(range)
+    range->Set(0, 10, 0.1);
+  return true;
+}
+
+void SnakeWizardModel::SetThresholdSmoothnessValue(double x)
+{
+  ThresholdSettings *ts = this->GetThresholdSettings();
+  ts->SetSmoothness(x);
+}
+
+bool SnakeWizardModel::GetThresholdModeValue(ThresholdSettings::ThresholdMode &x)
+{
+  if(!AreThresholdModelsActive())
+    return false;
+
+  ThresholdSettings *ts = this->GetThresholdSettings();
+  x = ts->GetThresholdMode();
+  return true;
+}
+
+void SnakeWizardModel::SetThresholdModeValue(ThresholdSettings::ThresholdMode x)
+{
+  ThresholdSettings *ts = this->GetThresholdSettings();
+  ts->SetThresholdMode(x);
+}
+
+bool SnakeWizardModel::GetThresholdActiveLayerValueAndRange(unsigned long &value, SnakeWizardModel::LayerSelectionDomain *range)
+{
+  // Get the currently selected layer
+  ScalarImageWrapperBase *active = GetActiveScalarLayer(PREPROCESS_THRESHOLD);
+
+  if(active)
+    {
+    // Figure out the top level wrapper for the selected component
+    ImageWrapperBase *parent = active->GetParentWrapper();
+    if(parent)
+      value = parent->GetUniqueId();
+    else
+      value = active->GetUniqueId();
+
+    // Set up the domain
+    if(range)
+      {
+      range->clear();
+      for(LayerIterator it = m_Driver->GetSNAPImageData()->GetLayers(
+            MAIN_ROLE | OVERLAY_ROLE);
+          !it.IsAtEnd(); ++it)
+        {
+        (*range)[it.GetLayer()->GetUniqueId()] = it.GetLayer()->GetNickname();
+        }
+      }
+
+    return true;
+    }
+
+  return false;
+}
+
+void SnakeWizardModel::SetThresholdActiveLayerValue(unsigned long value)
+{
+  // Find the layer
+  ImageWrapperBase *layer = m_Driver->GetSNAPImageData()->FindLayer(value, false);
+  if(layer)
+    {
+    m_Driver->GetPreprocessingFilterPreviewer(PREPROCESS_THRESHOLD)->SetActiveScalarLayer(
+          layer->GetDefaultScalarRepresentation());
+    }
+}
+
+bool
+SnakeWizardModel
+::GetThresholdActiveScalarRepValueAndRange(
+    SnakeWizardModel::LayerScalarRepIndex &value, SnakeWizardModel::ScalarRepSelectionDomain *range)
+{
+  // Get the currently selected scalar layer
+  ScalarImageWrapperBase *active = GetActiveScalarLayer(PREPROCESS_THRESHOLD);
+  VectorImageWrapperBase *parent =
+      (active) ? dynamic_cast<VectorImageWrapperBase*>(active->GetParentWrapper()) : NULL;
+
+  // If the scalar layer is its own parent, there should be nothing selected
+  if(active && parent && parent->GetNumberOfComponents() > 1)
+    {
+    // Now we must figure out the index of the layer in the parent
+    if(parent->FindScalarRepresentation(active, value.first, value.second))
+      {
+      // Configure the domain
+      if(range)
+        {
+        range->clear();
+        for(int sr = SCALAR_REP_COMPONENT; sr < NUMBER_OF_SCALAR_REPS; sr++)
+          {
+          (*range)[std::make_pair(SCALAR_REP_MAGNITUDE, 0)] = "Magnitude of Components";
+          (*range)[std::make_pair(SCALAR_REP_MAX, 0)] = "Maximum Component";
+          (*range)[std::make_pair(SCALAR_REP_AVERAGE, 0)] = "Average Component";
+
+          for(int k = 0; k < parent->GetNumberOfComponents(); k++)
+            {
+            std::ostringstream oss;
+            oss << "Component " << (k+1);
+            (*range)[std::make_pair(SCALAR_REP_COMPONENT, k)] = oss.str();
+            }
+          }
+        }
+
+      return true;
+      }
+    }
+
+  return false;
+}
+
+void
+SnakeWizardModel
+::SetThresholdActiveScalarRepValue(LayerScalarRepIndex value)
+{
+  // Get the currently selected scalar layer
+  ScalarImageWrapperBase *active =GetActiveScalarLayer(PREPROCESS_THRESHOLD);
+  VectorImageWrapperBase *parent =
+      (active) ? dynamic_cast<VectorImageWrapperBase*>(active->GetParentWrapper()) : NULL;
+
+  // The parent should be not null!
+  assert(parent);
+
+  // Set the component within the parent
+  ScalarImageWrapperBase *comp = parent->GetScalarRepresentation(value.first, value.second);
+  m_Driver->GetPreprocessingFilterPreviewer(PREPROCESS_THRESHOLD)->SetActiveScalarLayer(comp);
+}
+
+
+
+
+
+bool SnakeWizardModel::GetPreviewValue(bool &value)
+{
+  PreprocessingMode mode = m_Driver->GetPreprocessingMode();
+  if(mode != PREPROCESS_NONE)
+    {
+    value = m_Driver->GetPreprocessingFilterPreviewer(mode)->IsPreviewMode();
+    return true;
+    }
+  return false;
+}
+
+void SnakeWizardModel::SetPreviewValue(bool value)
+{
+  PreprocessingMode mode = m_Driver->GetPreprocessingMode();
+  if(mode != PREPROCESS_NONE)
+    {
+    m_Driver->GetPreprocessingFilterPreviewer(mode)->SetPreviewMode(value);
+    }
+}
+
+bool SnakeWizardModel::GetBlueWhiteSpeedModeValue(bool &value)
+{
+  PreprocessingMode mode = m_Driver->GetPreprocessingMode();
+  if(mode != PREPROCESS_NONE)
+    {
+    SpeedImageWrapper *speed = m_Driver->GetSNAPImageData()->GetSpeed();
+    if(speed->GetColorMap()->GetSystemPreset() == ColorMap::COLORMAP_SPEED
+       && !speed->IsSticky() && speed->GetAlpha() == 1.0)
+      {
+      value = true;
+      }
+    else
+      {
+      value = false;
+      }
+    return true;
+    }
+  return false;
+}
+
+void SnakeWizardModel::SetBlueWhiteSpeedModeValue(bool value)
+{
+  SpeedImageWrapper *speed = m_Driver->GetSNAPImageData()->GetSpeed();
+  if(value)
+    {
+    speed->GetColorMap()->SetToSystemPreset(ColorMap::COLORMAP_SPEED);
+    speed->SetSticky(false);
+    speed->SetAlpha(1.0);
+    }
+}
+
+bool SnakeWizardModel::GetRedTransparentSpeedModeValue(bool &value)
+{
+  PreprocessingMode mode = m_Driver->GetPreprocessingMode();
+  if(mode != PREPROCESS_NONE)
+    {
+    SpeedImageWrapper *speed = m_Driver->GetSNAPImageData()->GetSpeed();
+    if(speed->GetColorMap()->GetSystemPreset() == ColorMap::COLORMAP_SPEED_OVERLAY
+       && speed->IsSticky() && speed->GetAlpha() == 0.5)
+      {
+      value = true;
+      }
+    else
+      {
+      value = false;
+      }
+    return true;
+    }
+  return false;
+}
+
+void SnakeWizardModel::SetRedTransparentSpeedModeValue(bool value)
+{
+  SpeedImageWrapper *speed = m_Driver->GetSNAPImageData()->GetSpeed();
+  if(value)
+    {
+    speed->GetColorMap()->SetToSystemPreset(ColorMap::COLORMAP_SPEED_OVERLAY);
+    speed->SetSticky(true);
+    speed->SetAlpha(0.5);
+    }
+}
+
+
+
+void SnakeWizardModel
+::EvaluateThresholdFunction(unsigned int n, float *x, float *y)
+{
+  assert(m_Driver->IsSnakeModeActive());
+
+  ScalarImageWrapperBase *grey = this->GetActiveScalarLayer(PREPROCESS_THRESHOLD);
+  ThresholdSettings *ts = this->GetThresholdSettings();
+  SpeedImageWrapper *speed = m_Driver->GetSNAPImageData()->GetSpeed();
+
+  double imin = grey->GetImageMinAsDouble();
+  double imax = grey->GetImageMaxAsDouble();
+
+  SmoothBinaryThresholdFunctor<float> functor;
+  functor.SetParameters(ts, imin, imax);
+
+  for(int i = 0; i < n; i++)
+    {
+    float t = i * 1.0 / (n - 1);
+    float x_internal = imin + t * (imax - imin);
+    x[i] = grey->GetNativeIntensityMapping()->MapInternalToNative(x_internal);
+    y[i] = speed->GetNativeIntensityMapping()->MapInternalToNative(functor(x_internal));
+
+    // We are actually plotting the threshold function itself, not the speed
+    // function, so we will scale further to the range [0 1]
+    y[i] = 0.5 * (y[i] + 1.0);
+    }
+}
+
+bool
+SnakeWizardModel
+::GetEdgePreprocessingSigmaValueAndRange(
+    double &x, NumericValueRange<double> *range)
+{
+  if(!AreEdgePreprocessingModelsActive())
+    return false;
+
+  EdgePreprocessingSettings *eps = m_Driver->GetEdgePreprocessingSettings();
+  x = eps->GetGaussianBlurScale();
+  if(range)
+    range->Set(0.1, 3, 0.01);
+
+  return true;
+}
+
+void
+SnakeWizardModel
+::SetEdgePreprocessingSigmaValue(double x)
+{
+  EdgePreprocessingSettings *eps = m_Driver->GetEdgePreprocessingSettings();
+  eps->SetGaussianBlurScale(x);
+}
+
+bool
+SnakeWizardModel
+::GetEdgePreprocessingKappaValueAndRange(
+    double &x, NumericValueRange<double> *range)
+{
+  if(!AreEdgePreprocessingModelsActive())
+    return false;
+
+  EdgePreprocessingSettings *eps = m_Driver->GetEdgePreprocessingSettings();
+  x = eps->GetRemappingSteepness();
+  if(range)
+    range->Set(0.001, 0.2, 0.001);
+
+  return true;
+}
+
+void
+SnakeWizardModel
+::SetEdgePreprocessingKappaValue(double x)
+{
+  EdgePreprocessingSettings *eps = m_Driver->GetEdgePreprocessingSettings();
+  eps->SetRemappingSteepness(x);
+}
+
+
+bool
+SnakeWizardModel
+::GetEdgePreprocessingExponentValueAndRange(
+    double &x, NumericValueRange<double> *range)
+{
+  if(!AreEdgePreprocessingModelsActive())
+    return false;
+
+  EdgePreprocessingSettings *eps = m_Driver->GetEdgePreprocessingSettings();
+  x = eps->GetRemappingExponent();
+  if(range)
+    range->Set(1, 4, 0.01);
+
+  return true;
+}
+
+void
+SnakeWizardModel
+::SetEdgePreprocessingExponentValue(double x)
+{
+  EdgePreprocessingSettings *eps = m_Driver->GetEdgePreprocessingSettings();
+  eps->SetRemappingExponent(x);
+}
+
+
+void SnakeWizardModel
+::EvaluateEdgePreprocessingFunction(unsigned int n, float *x, float *y)
+{
+  assert(m_Driver->IsSnakeModeActive());
+
+  EdgePreprocessingSettings *eps = m_Driver->GetEdgePreprocessingSettings();
+  ScalarImageWrapperBase *grey = this->GetSelectedScalarLayer();
+  SpeedImageWrapper *speed = m_Driver->GetSNAPImageData()->GetSpeed();
+
+  // Get the range of gradient magnitude in native units
+  double xlim = grey->GetImageGradientMagnitudeUpperLimitNative();
+  EdgeRemappingFunctor<float> functor;
+  functor.SetParameters(0, xlim,
+                        eps->GetRemappingExponent(),
+                        eps->GetRemappingSteepness());
+
+  for(int i = 0; i < n; i++)
+    {
+    float t = i * 1.0 / (n - 1);
+    float x_internal = t * xlim;
+    x[i] = x_internal;
+    y[i] = speed->GetNativeIntensityMapping()->MapInternalToNative(functor(x_internal));
+    }
+}
+
+void SnakeWizardModel::ApplyPreprocessing()
+{
+  // Compute the speed image
+  m_Driver->ApplyCurrentPreprocessingModeToSpeedVolume(m_Parent->GetProgressCommand());
+
+  // Invoke an event so we get a screen update
+  InvokeEvent(ModelUpdateEvent());
+}
+
+bool SnakeWizardModel::GetSnakeTypeValueAndRange(
+    SnakeType &value, GlobalState::SnakeTypeDomain *range)
+{
+  return m_GlobalState->GetSnakeTypeModel()->GetValueAndDomain(value, range);
+}
+
+void SnakeWizardModel::SetSnakeTypeValue(SnakeType value)
+{
+  m_Driver->SetSnakeMode(value);
+}
+
+bool SnakeWizardModel::GetPreprocessingModeValueAndRange(PreprocessingMode &value, SnakeWizardModel::PreprocessingModeDomain *range)
+{
+  PreprocessingMode mode = m_Driver->GetPreprocessingMode();
+  if(mode == PREPROCESS_NONE)
+    return false;
+
+  value = mode;
+
+  if(range)
+    {
+    (*range)[PREPROCESS_THRESHOLD] = "Thresholding";
+    (*range)[PREPROCESS_EDGE] = "Edge Attraction";
+    (*range)[PREPROCESS_GMM] = "Clustering";
+    (*range)[PREPROCESS_RF] = "Classification";
+    }
+  return true;
+}
+
+void SnakeWizardModel::SetPreprocessingModeValue(PreprocessingMode value)
+{
+  m_Driver->EnterPreprocessingMode(value);
+  InvokeEvent(ModelUpdateEvent());
+  InvokeEvent(GMMModifiedEvent());
+  InvokeEvent(RFClassifierModifiedEvent());
+}
+
+void SnakeWizardModel::CompletePreprocessing()
+{
+  // If we are in classification pre-segmentation mode, set the active drawing label
+  // to match the foreground class - otherwise it's confusing to the user
+  if(m_Driver->GetPreprocessingMode() == PREPROCESS_RF)
+    m_Parent->GetGlobalState()->SetDrawingColorLabel(
+          this->GetForegroundClassColorLabel());
+
+  // Disconnect preview pipeline
+  m_Driver->EnterPreprocessingMode(PREPROCESS_NONE);
+  InvokeEvent(ModelUpdateEvent());
+}
+
+bool
+SnakeWizardModel
+::GetActiveBubbleValue(int &value)
+{
+  // This is irrelevant when the snake is inactive
+  if(!m_Driver->IsSnakeModeActive())
+    return false;
+
+  // This may be -1 if no bubbles are selected
+  value = m_GlobalState->GetActiveBubble();
+  return true;
+}
+
+void
+SnakeWizardModel
+::SetActiveBubbleValue(int value)
+{
+  m_GlobalState->SetActiveBubble(value);
+  InvokeEvent(ActiveBubbleUpdateEvent());
+}
+
+void SnakeWizardModel::AddBubbleAtCursor()
+{
+  // Create a new bubble, using the default radius value
+  Bubble bub;
+  bub.center = to_int(m_Driver->GetCursorPosition());
+  bub.radius = m_BubbleRadiusDefaultValue;
+
+  // Add the bubble to the global state
+  m_Driver->GetBubbleArray().push_back(bub);
+
+  // Set the bubble's position
+  m_GlobalState->SetActiveBubble(m_Driver->GetBubbleArray().size() - 1);
+
+  // Update the bubble list in the GUI
+  InvokeEvent(ActiveBubbleUpdateEvent());
+  InvokeEvent(BubbleListUpdateEvent());
+  InvokeEvent(BubbleDefaultRadiusUpdateEvent());
+}
+
+void SnakeWizardModel::RemoveBubbleAtCursor()
+{
+  int ibub = m_GlobalState->GetActiveBubble();
+  IRISApplication::BubbleArray &ba = m_Driver->GetBubbleArray();
+
+  if(ibub >= 0 && ibub < (int) ba.size())
+    {
+    // Remove the bubble from the global state
+    ba.erase(ba.begin() + ibub);
+
+    // Update the active bubble
+    if(ibub == (int) ba.size())
+      m_GlobalState->SetActiveBubble(ibub - 1);
+
+    // Update the bubble list in the GUI
+    InvokeEvent(ActiveBubbleUpdateEvent());
+    InvokeEvent(BubbleListUpdateEvent());
+    InvokeEvent(BubbleDefaultRadiusUpdateEvent());
+    }
+  else
+    {
+    throw IRISException("Invalid bubble index %d selected for removal.", ibub);
+    }
+}
+
+bool SnakeWizardModel::UpdateBubble(int index, Bubble bubble)
+{
+  if(m_Driver->GetCurrentImageData()->GetImageRegion().IsInside(
+       to_itkIndex(bubble.center)))
+    {
+    m_Driver->GetBubbleArray()[index] = bubble;
+    InvokeEvent(BubbleDefaultRadiusUpdateEvent());
+    return true;
+    }
+  return false;
+}
+
+void SnakeWizardModel::OnSnakeModeEnter()
+{
+  // Initialize the image data
+  m_Driver->InitializeSNAPImageData(
+        m_Driver->GetGlobalState()->GetSegmentationROISettings(),
+        m_Parent->GetProgressCommand());
+
+  m_Driver->SetCurrentImageDataToSNAP();
+
+  // Some preparatory stuff
+  this->ComputeBubbleRadiusDefaultAndRange();
+
+  // Reset the bubbles
+  m_Driver->GetBubbleArray().clear();
+  m_GlobalState->UnsetActiveBubble();
+
+  // We begin in preprocessing mode
+  SetInteractionMode(MODE_PREPROCESSING);
+
+  // Set the current preprocessing mode.
+  PreprocessingMode lastMode = m_GlobalState->GetLastUsedPreprocessingMode();
+  m_PreprocessingModeModel->SetValue(lastMode);
+}
+
+void SnakeWizardModel::ComputeBubbleRadiusDefaultAndRange()
+{
+  // Set bubble radius range according to volume dimensions (world dimensions)
+  Vector3ui size = m_Driver->GetSNAPImageData()->GetVolumeExtents();
+  Vector3d voxdims = m_Driver->GetSNAPImageData()->GetImageSpacing();
+  double mindim =
+      vector_multiply_mixed<double,unsigned int,3>(voxdims, size).min_value();
+
+  // The largest value of the bubble radius is mindim / 2
+  double xBubbleMax = 0.5 * mindim ;
+
+  // The unit step should be equal or smaller than the smallest voxel edge length
+  // divided by two, and should be a power of 10. Since FLTK accepts rational step
+  // size, we compute it as a ratio two numbers
+  double xMinVoxelEdge = 0.5 * voxdims.min_value();
+  int xBubbleStepA = 1, xBubbleStepB = 1;
+  int xLogVoxelEdge = (int) floor(log10(xMinVoxelEdge));
+  if(xLogVoxelEdge > 0)
+    xBubbleStepA = (int)(0.5 + pow(10.0, xLogVoxelEdge));
+  else if(xLogVoxelEdge < 0)
+    xBubbleStepB = (int)(0.5 + pow(10.0, -xLogVoxelEdge));
+
+  // It is likely however that 0.1 is not an appropriate step size when min
+  // voxel size is 0.99, so we try 0.5 and 0.2 as candidates
+  if(xBubbleStepA * 5.0 / xBubbleStepB <= xMinVoxelEdge)
+    xBubbleStepA *= 5;
+  else if(xBubbleStepA * 2.0 / xBubbleStepB <= xMinVoxelEdge)
+    xBubbleStepA *= 2;
+
+  // Set the bubble min value
+  double xBubbleStep = xBubbleStepA * 1.0 / xBubbleStepB;
+  double xBubbleMin = xBubbleStep;
+
+  // Set the default value so that it falls on the step boundary
+  m_BubbleRadiusDefaultValue = floor(0.25 * xBubbleMax / xBubbleStep) * xBubbleStep;
+
+  // Set the domain and value for the radius slider
+  m_BubbleRadiusDomain.Set(xBubbleMin, xBubbleMax, xBubbleStep);
+
+  // Let the GUI know that the values have changed
+  InvokeEvent(BubbleDefaultRadiusUpdateEvent());
+}
+
+void SnakeWizardModel::SetInteractionMode(SnakeWizardModel::InteractionMode mode)
+{
+  m_InteractionMode = mode;
+  InvokeEvent(StateMachineChangeEvent());
+}
+
+
+bool
+SnakeWizardModel
+::GetBubbleRadiusValueAndRange(
+    double &value, NumericValueRange<double> *range)
+{
+  // Bail out if not in snake mode
+  if(!m_Driver->IsSnakeModeActive())
+    return false;
+
+  int activeBubble;
+  if(m_ActiveBubbleModel->GetValueAndDomain(activeBubble, NULL)
+     && activeBubble >= 0)
+    {
+    // If a bubble is currently selected, we change the value of the
+    // currently selected bubble
+    value = m_Driver->GetBubbleArray()[activeBubble].radius;
+    }
+  else
+    {
+    // Otherwise, we return the default value computed for this image
+    value = m_BubbleRadiusDefaultValue;
+    }
+
+  // Set the range as well
+  if(range)
+    *range = m_BubbleRadiusDomain;
+
+  return true;
+}
+
+void
+SnakeWizardModel
+::SetBubbleRadiusValue(double value)
+{
+  int activeBubble;
+  if(m_ActiveBubbleModel->GetValueAndDomain(activeBubble, NULL)
+     && activeBubble >= 0)
+    {
+    // There is an active bubble - change its radius
+    m_Driver->GetBubbleArray()[activeBubble].radius = value;
+    InvokeEvent(BubbleListUpdateEvent());
+    }
+
+  // Always store as the default value
+  m_BubbleRadiusDefaultValue = value;
+
+  // Radius has updated
+  InvokeEvent(BubbleDefaultRadiusUpdateEvent());
+}
+
+void SnakeWizardModel::OnEvolutionPageEnter()
+{
+  // We are no longer bubble
+  SetInteractionMode(MODE_EVOLUTION);
+
+  // Initialize the segmentation
+  if(!m_Driver->InitializeActiveContourPipeline())
+    {
+    throw IRISException("Failed to initialize the active contour. "
+                        "Check that the initialization bubbles are "
+                        "present and cover the image region.");
+    }
+}
+
+bool SnakeWizardModel::PerformEvolutionStep()
+{
+  // Do the segmentation step!
+  m_Driver->GetSNAPImageData()->RunSegmentation(m_StepSizeModel->GetValue());
+
+  // Fire an event
+  InvokeEvent(EvolutionIterationEvent());
+
+  // Return the status. In the future, this should check for convergence, but
+  // the way the parallel sparse filter is behaving in the more recent versions
+  // of ITK, the RMSChange flag is just meaningless.
+  return false;
+}
+
+int SnakeWizardModel::GetEvolutionIterationValue()
+{
+  if(m_Driver->IsSnakeModeActive() &&
+     m_Driver->GetSNAPImageData()->IsSegmentationActive())
+    {
+    return m_Driver->GetSNAPImageData()->GetElapsedSegmentationIterations();
+    }
+  else return 0;
+}
+
+ThresholdSettings *SnakeWizardModel::GetThresholdSettings()
+{
+  // Get the layer currently being thresholded
+  ScalarImageWrapperBase *layer = GetActiveScalarLayer(PREPROCESS_THRESHOLD);
+
+  // Get the threshold settings from that layer
+  return layer
+      ? dynamic_cast<ThresholdSettings *>(layer->GetUserData("ThresholdSettings"))
+      : NULL;
+}
+
+void SnakeWizardModel::OnEvolutionPageBack()
+{
+
+  // Abort the segmentation (stops segmentation and resets the snake
+  SNAPImageData *sid = m_Driver->GetSNAPImageData();
+  if(sid->IsSegmentationActive())
+    {
+    sid->TerminateSegmentation();
+    sid->ClearSnake();
+    }
+
+  SetInteractionMode(MODE_BUBBLES);
+}
+
+void SnakeWizardModel::OnEvolutionPageFinish()
+{
+  // Stop the segmentation pipeline
+  if(m_Driver->GetSNAPImageData()->IsSegmentationActive())
+    m_Driver->GetSNAPImageData()->TerminateSegmentation();
+
+  // Update IRIS with SNAP images
+  m_Driver->UpdateIRISWithSnapImageData(NULL);
+
+  // Set an undo point
+  m_Driver->StoreUndoPoint("Automatic Segmentation");
+
+  // Return to IRIS mode
+  m_Driver->SetCurrentImageDataToIRIS();
+  m_Driver->ReleaseSNAPImageData();
+}
+
+void SnakeWizardModel::OnCancelSegmentation()
+{
+  // Stop the segmentation pipeline
+  if(m_Driver->GetSNAPImageData()->IsSegmentationActive())
+    m_Driver->GetSNAPImageData()->TerminateSegmentation();
+
+  // Leave the preprocessing mode
+  m_PreprocessingModeModel->SetValue(PREPROCESS_NONE);
+
+  // Return to IRIS mode
+  m_Driver->SetCurrentImageDataToIRIS();
+  m_Driver->ReleaseSNAPImageData();
+}
+
+void SnakeWizardModel::RewindEvolution()
+{
+  if(m_Driver->GetSNAPImageData()->IsSegmentationActive())
+    m_Driver->GetSNAPImageData()->RestartSegmentation();
+
+  // Fire an event
+  InvokeEvent(EvolutionIterationEvent());
+}
+
+
+bool SnakeWizardModel
+::GetNumberOfClustersValueAndRange(
+    int &value, NumericValueRange<int> *range)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  if(uc)
+    {
+    value = uc->GetNumberOfClusters();
+    if(range)
+      range->Set(2, 20, 1);
+    return true;
+    }
+
+  return false;
+}
+
+void SnakeWizardModel
+::SetNumberOfClustersValue(
+    int value)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  assert(uc);
+
+  uc->SetNumberOfClusters(value);
+  uc->InitializeClusters();
+  this->TagGMMPreprocessingFilterModified();
+  this->InvokeEvent(GMMModifiedEvent());
+}
+
+bool SnakeWizardModel::GetNumberOfGMMSamplesValueAndRange(int &value, NumericValueRange<int> *range)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  if(uc)
+    {
+    value = uc->GetNumberOfSamples();
+    if(range)
+      {
+      int nvox = m_Driver->GetCurrentImageData()->GetMain()->GetNumberOfVoxels();
+      range->Set(std::min(nvox, 5000), nvox, 5000);
+      }
+
+    return true;
+    }
+
+  return false;
+}
+
+void SnakeWizardModel::SetNumberOfGMMSamplesValue(int value)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  assert(uc);
+
+  uc->SetNumberOfSamples(value);
+  uc->InitializeClusters();
+  this->TagGMMPreprocessingFilterModified();
+  this->InvokeEvent(GMMModifiedEvent());
+}
+
+bool SnakeWizardModel::GetForegroundClusterValueAndRange(int &value, NumericValueRange<int> *range)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  if(!uc)
+    return false;
+
+  // Go through the clusters, and find which cluster is marked as foreground
+  int foreCluster = -1;
+  for(int i = 0; i < uc->GetNumberOfClusters(); i++)
+    {
+    if(uc->GetMixtureModel()->IsForeground(i))
+      {
+      if(foreCluster >= 0)
+        // Oops! more than one foreground cluster!
+        return false;
+      else
+        foreCluster = i;
+      }
+    }
+
+  // Set the value
+  value = foreCluster + 1;
+
+  // Set the range
+  if(range)
+    {
+    range->Set(1, uc->GetNumberOfClusters(), 1);
+    }
+
+  return true;
+}
+
+void SnakeWizardModel::SetForegroundClusterValue(int value)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  assert(uc);
+
+  // Go through the clusters, and find which cluster is marked as foreground
+  int foreCluster = value - 1;
+  for(int i = 0; i < uc->GetNumberOfClusters(); i++)
+    {
+    if(i == foreCluster)
+      uc->GetMixtureModel()->SetForeground(i);
+    else
+      uc->GetMixtureModel()->SetBackground(i);
+    }
+
+  this->TagGMMPreprocessingFilterModified();
+  InvokeEvent(GMMModifiedEvent());
+}
+
+void SnakeWizardModel::TagGMMPreprocessingFilterModified()
+{
+  // TODO: this is not the right way to do this! Make MixtureModel an itkObject
+  // and an inout to the filter, so we don't have to update the filter itself!!
+  // THIS IS HACKY!!!
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  typedef SlicePreviewFilterWrapper<GMMPreprocessingFilterConfigTraits>
+                                            GMMPreprocessingPreviewWrapperType;
+  GMMPreprocessingPreviewWrapperType *junk =
+      (GMMPreprocessingPreviewWrapperType *) m_Driver->GetPreprocessingFilterPreviewer(PREPROCESS_GMM);
+  junk->SetParameters(uc->GetMixtureModel());
+}
+
+void SnakeWizardModel::TagRFPreprocessingFilterModified()
+{
+  // TODO: this is not the right way to do this! Make RandomForestClassifier an itkObject
+  // and an inout to the filter, so we don't have to update the filter itself!!
+  // THIS IS HACKY!!!
+  RFClassificationEngine *ce = m_Driver->GetClassificationEngine();
+  typedef SlicePreviewFilterWrapper<RFPreprocessingFilterConfigTraits>
+                                            RFPreprocessingPreviewWrapperType;
+  RFPreprocessingPreviewWrapperType *junk =
+      (RFPreprocessingPreviewWrapperType *) m_Driver->GetPreprocessingFilterPreviewer(PREPROCESS_RF);
+  junk->SetParameters(ce->GetClassifier());
+
+}
+
+
+void SnakeWizardModel::PerformClusteringIteration()
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  assert(uc);
+
+  uc->Iterate();
+  this->InvokeEvent(GMMModifiedEvent());
+
+  TagGMMPreprocessingFilterModified();
+}
+
+bool SnakeWizardModel::SetClusterForegroundState(int cluster, bool state)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  assert(uc);
+
+  GaussianMixtureModel *gmm = uc->GetMixtureModel();
+
+  // Currently this implements mutually exclusive behavior
+  if(state && !gmm->IsForeground(cluster))
+    {
+    for(int i = 0; i < gmm->GetNumberOfGaussians(); i++)
+      {
+      if(cluster == i)
+        gmm->SetForeground(i);
+      else
+        gmm->SetBackground(i);
+      }
+
+    TagGMMPreprocessingFilterModified();
+    this->InvokeEvent(GMMModifiedEvent());
+    return true;
+    }
+  else
+    {
+    return false;
+    }
+}
+
+double SnakeWizardModel::GetClusterWeight(int cluster)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  GaussianMixtureModel *gmm = uc->GetMixtureModel();
+  return gmm->GetWeight(cluster);
+}
+
+bool SnakeWizardModel::SetClusterWeight(int cluster, double weight)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  assert(uc);
+
+  GaussianMixtureModel *gmm = uc->GetMixtureModel();
+
+  if(weight != gmm->GetWeight(cluster))
+    {
+    gmm->SetWeightAndRenormalize(cluster, weight);
+
+    TagGMMPreprocessingFilterModified();
+    this->InvokeEvent(GMMModifiedEvent());
+    return true;
+    }
+  else
+    return false;
+}
+
+double SnakeWizardModel::GetClusterNativeMean(int cluster, int component)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  GaussianMixtureModel *gmm = uc->GetMixtureModel();
+  ImageWrapperBase *aiw = this->GetLayerAndIndexForNthComponent(component).ImageWrapper;
+  const AbstractNativeIntensityMapping *nim = aiw->GetNativeIntensityMapping();
+  return nim->MapInternalToNative(gmm->GetMean(cluster)[component]);
+}
+
+bool SnakeWizardModel::SetClusterNativeMean(int cluster, int component, double x)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  GaussianMixtureModel *gmm = uc->GetMixtureModel();
+  ImageWrapperBase *aiw = this->GetLayerAndIndexForNthComponent(component).ImageWrapper;
+  const AbstractNativeIntensityMapping *nim = aiw->GetNativeIntensityMapping();
+
+  vnl_vector<double> mean_raw = gmm->GetMean(cluster);
+  double mk = nim->MapNativeToInternal(x);
+  if(mk != mean_raw[component])
+    {
+    mean_raw[component] = mk;
+    gmm->SetMean(cluster, mean_raw);
+
+    TagGMMPreprocessingFilterModified();
+    this->InvokeEvent(GMMModifiedEvent());
+
+    return true;
+    }
+
+  return false;
+}
+
+double SnakeWizardModel::GetClusterNativeCovariance(int cluster, int comp1, int comp2)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  GaussianMixtureModel *gmm = uc->GetMixtureModel();
+
+  const AbstractNativeIntensityMapping *nim1 =
+      this->GetLayerAndIndexForNthComponent(comp1).ImageWrapper->GetNativeIntensityMapping();
+
+  const AbstractNativeIntensityMapping *nim2 =
+      this->GetLayerAndIndexForNthComponent(comp2).ImageWrapper->GetNativeIntensityMapping();
+
+  double cov_raw = gmm->GetGaussian(cluster)->GetCovariance()(comp1, comp2);
+  return cov_raw * nim1->GetScale() * nim2->GetScale();
+}
+
+double SnakeWizardModel::GetClusterNativeTotalVariance(int cluster)
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  GaussianMixtureModel *gmm = uc->GetMixtureModel();
+  int ng = gmm->GetNumberOfGaussians();
+  double var = 0;
+  for(int i = 0; i < gmm->GetNumberOfComponents(); i++)
+    var += this->GetClusterNativeCovariance(cluster, i, i);
+  return var;
+}
+
+void SnakeWizardModel::ReinitializeClustering()
+{
+  UnsupervisedClustering *uc = m_Driver->GetClusteringEngine();
+  assert(uc);
+
+  uc->InitializeClusters();
+  this->InvokeEvent(GMMModifiedEvent());
+
+  TagGMMPreprocessingFilterModified();
+}
+
+
+int SnakeWizardModel::GetNumberOfComponentsForSegmentation()
+{
+  this->Update();
+  return m_ComponentInfo.size();
+}
+
+SnakeWizardModel::ComponentInfo
+SnakeWizardModel::GetLayerAndIndexForNthComponent(int n)
+{
+  this->Update();
+  assert(n < m_ComponentInfo.size());
+  return m_ComponentInfo[n];
+}
+
+void SnakeWizardModel::TrainClassifier()
+{
+  // Get the classification engine
+  RFClassificationEngine *rfengine = m_Driver->GetClassificationEngine();
+
+  // Perform the classification
+  rfengine->TrainClassifier();
+
+  // Get the current foreground label
+  LabelType curr_foreground;
+  bool fg_valid =
+      m_ForegroundClassColorLabelModel->GetValueAndDomain(curr_foreground, NULL);
+
+  // Populate the available labels for the foreground label
+  m_ActiveClasses.clear();
+  const RandomForestClassifier::MappingType &mapping =
+      rfengine->GetClassifier()->GetClassToLabelMapping();
+  for(RandomForestClassifier::MappingType::const_iterator it = mapping.begin();
+      it != mapping.end(); ++it)
+    {
+    m_ActiveClasses[it->second] =
+        m_Driver->GetColorLabelTable()->GetColorLabel(it->second);
+    }
+
+  // Fire the appropriate event
+  InvokeEvent(RFClassifierModifiedEvent());
+
+  // TODO: this is a hack!
+  TagRFPreprocessingFilterModified();
+}
+
+void SnakeWizardModel::ClearSegmentation()
+{
+  m_Driver->ResetSNAPSegmentationImage();
+}
+
+
+
diff --git a/GUI/Model/SnakeWizardModel.h b/GUI/Model/SnakeWizardModel.h
new file mode 100644
index 0000000..077af80
--- /dev/null
+++ b/GUI/Model/SnakeWizardModel.h
@@ -0,0 +1,446 @@
+#ifndef SNAKEWIZARDMODEL_H
+#define SNAKEWIZARDMODEL_H
+
+#include "SNAPCommon.h"
+#include "AbstractModel.h"
+#include "PropertyModel.h"
+#include "ThresholdSettings.h"
+#include "GlobalState.h"
+#include "ImageWrapperBase.h"
+
+class GlobalUIModel;
+class IRISApplication;
+class ImageWrapperBase;
+
+
+class SnakeWizardModel : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(SnakeWizardModel, AbstractModel)
+
+
+  // This is a complex model, so there is some granularization over
+  // the model update events that it fires.
+  itkEventMacro(ThresholdSettingsUpdateEvent, IRISEvent)
+  itkEventMacro(EdgePreprocessingSettingsUpdateEvent, IRISEvent)
+
+  itkEventMacro(ActiveBubbleUpdateEvent, IRISEvent)
+  itkEventMacro(BubbleListUpdateEvent, IRISEvent)
+  itkEventMacro(BubbleDefaultRadiusUpdateEvent, IRISEvent)
+  itkEventMacro(EvolutionIterationEvent, IRISEvent)
+  itkEventMacro(GMMModifiedEvent, IRISEvent)
+  itkEventMacro(RFClassifierModifiedEvent, IRISEvent)
+
+  FIRES(ThresholdSettingsUpdateEvent)
+  FIRES(EdgePreprocessingSettingsUpdateEvent)
+  FIRES(ActiveBubbleUpdateEvent)
+  FIRES(BubbleListUpdateEvent)
+  FIRES(BubbleDefaultRadiusUpdateEvent)
+  FIRES(EvolutionIterationEvent)
+  FIRES(GMMModifiedEvent)
+
+  void SetParentModel(GlobalUIModel *model);
+  irisGetMacro(Parent, GlobalUIModel *)
+
+  virtual void OnUpdate();
+
+  // Interaction modes (correspond to wizard pages)
+  enum InteractionMode {
+    MODE_PREPROCESSING,
+    MODE_BUBBLES,
+    MODE_EVOLUTION,
+    MODE_NONE
+  };
+
+  // State machine enums
+  enum UIState {
+    UIF_THESHOLDING_ENABLED,
+    UIF_LOWER_THRESHOLD_ENABLED,
+    UIF_UPPER_THRESHOLD_ENABLED,
+    UIF_EDGEPROCESSING_ENABLED,
+    UIF_CAN_GENERATE_SPEED,
+    UIF_SPEED_AVAILABLE,              // Has speed volume been computed?
+    UIF_PREPROCESSING_ACTIVE,         // Is the preprocessing dialog open?
+    UIF_BUBBLE_SELECTED,
+    UIF_INITIALIZATION_VALID,          // Do we have data to start snake evol?
+    UIF_BUBBLE_MODE
+    };
+
+  // Model for the threshold mode
+  typedef AbstractPropertyModel<ThresholdSettings::ThresholdMode>
+    AbstractThresholdModeModel;
+
+  // Model for the snake mode
+  typedef AbstractPropertyModel<SnakeType, GlobalState::SnakeTypeDomain>
+    AbstractSnakeTypeModel;
+
+  // Model describing the current preprocessing mode
+  typedef SimpleItemSetDomain<PreprocessingMode, std::string> PreprocessingModeDomain;
+  typedef AbstractPropertyModel<PreprocessingMode, PreprocessingModeDomain> AbstractPreprocessingModeModel;
+
+  // Model for layer selection
+  typedef SimpleItemSetDomain<unsigned long, std::string> LayerSelectionDomain;
+  typedef AbstractPropertyModel<unsigned long, LayerSelectionDomain> AbstractLayerSelectionModel;
+
+  // Model for scalar representation selection within a layer
+  typedef std::pair<ScalarRepresentation, int> LayerScalarRepIndex;
+  typedef SimpleItemSetDomain<LayerScalarRepIndex, std::string> ScalarRepSelectionDomain;
+  typedef AbstractPropertyModel<LayerScalarRepIndex, ScalarRepSelectionDomain> AbstractScalarRepSelectionModel;
+
+  // Model for the bubble selection
+  // typedef STLVectorWrapperItemSetDomain<int, Bubble> BubbleDomain;
+  // typedef AbstractPropertyModel<int, BubbleDomain> AbstractActiveBubbleProperty;
+
+  // Model for whether the current pre-processing model is in preview mode or not
+  irisGetMacro(PreviewModel, AbstractSimpleBooleanProperty *)
+
+  // Get the active layer for single-layer processing modes
+  ScalarImageWrapperBase *GetActiveScalarLayer(PreprocessingMode mode);
+
+  // Models for the current speed rendering style. These are true if the speed
+  // is displayed using the selected style, false otherwise
+  irisGetMacro(BlueWhiteSpeedModeModel, AbstractSimpleBooleanProperty *)
+  irisGetMacro(RedTransparentSpeedModeModel, AbstractSimpleBooleanProperty *)
+
+  // Models for the threshold-based preprocessing
+  irisGetMacro(ThresholdLowerModel, AbstractRangedDoubleProperty *)
+  irisGetMacro(ThresholdUpperModel, AbstractRangedDoubleProperty *)
+  irisGetMacro(ThresholdSmoothnessModel, AbstractRangedDoubleProperty *)
+  irisGetMacro(ThresholdModeModel, AbstractThresholdModeModel *)
+
+  // Model for selecting which image layer is used for thresholding
+  irisGetMacro(ThresholdActiveLayerModel, AbstractLayerSelectionModel *)
+  irisGetMacro(ThresholdActiveScalarRepModel, AbstractScalarRepSelectionModel *)
+
+  // Models for the edge-based preprocessing
+  irisGetMacro(EdgePreprocessingSigmaModel, AbstractRangedDoubleProperty *)
+  irisGetMacro(EdgePreprocessingKappaModel, AbstractRangedDoubleProperty *)
+  irisGetMacro(EdgePreprocessingExponentModel, AbstractRangedDoubleProperty *)
+
+
+  // Called when entering proprocessing mode (i.e., back from button page)
+  void OnBubbleModeBack();
+
+  // What happens when we enter bubble mode
+  void OnBubbleModeEnter();
+
+  // Model for bubble selection
+  irisGetMacro(ActiveBubbleModel, AbstractSimpleIntProperty *)
+
+  // Model for bubble radius
+  irisGetMacro(BubbleRadiusModel, AbstractRangedDoubleProperty *)
+
+  // Get the model for the snake type
+  irisGetMacro(SnakeTypeModel, AbstractSnakeTypeModel *)
+
+  // Get the model for the current preprocessing mode
+  irisGetMacro(PreprocessingModeModel, AbstractPreprocessingModeModel *)
+
+  // The models for the evolution page
+  irisGetMacro(StepSizeModel, AbstractRangedIntProperty *)
+  irisGetMacro(EvolutionIterationModel, AbstractSimpleIntProperty *)
+
+  /** Check the state flags above */
+  bool CheckState(UIState state);
+
+  /** A reference to a component used in automatic segmentation */
+  struct ComponentInfo
+  {
+    ImageWrapperBase *ImageWrapper;
+    ScalarImageWrapperBase *ComponentWrapper;
+    int ComponentIndex;
+  };
+
+  /**
+   * This method allows a quick lookup between components involved in
+   * multi-variate segmentation algorithms and corresponding layers. For
+   * example, snake mode may be launched with a six-component main image
+   * and a single-component overlay. Then there are seven components used
+   * in total, and calling this method with 0-5 will return the main image,
+   * and calling it with 6 will return the overlay
+   */
+  ComponentInfo GetLayerAndIndexForNthComponent(int n);
+
+  /**
+   * Returns the total number of components available for multi-variate
+   * segmentation methods. \see GetLayerAndIndexForNthComponent().
+   */
+  int GetNumberOfComponentsForSegmentation();
+
+  /** Evaluate the threshold function so it can be plotted for the user */
+  void EvaluateThresholdFunction(unsigned int n, float *x, float *y);
+
+  /** Evaluate the threshold function so it can be plotted for the user */
+  void EvaluateEdgePreprocessingFunction(unsigned int n, float *x, float *y);
+
+  /** Perform the preprocessing based on thresholds */
+  void ApplyPreprocessing();
+
+  /** Do some cleanup when the preprocessing dialog closes */
+  void CompletePreprocessing();
+
+  /** Called when first displaying the snake wizard */
+  void OnSnakeModeEnter();
+
+  /** Add bubble at cursor */
+  void AddBubbleAtCursor();
+
+  /** Remove bubble at cursor */
+  void RemoveBubbleAtCursor();
+
+  /** Update a bubble */
+  bool UpdateBubble(int index, Bubble bubble);
+
+  /** Called when entering the evolution page */
+  void OnEvolutionPageEnter();
+
+  /** Called when entering the evolution page */
+  void OnEvolutionPageBack();
+
+  /** Called when entering the evolution page */
+  void OnEvolutionPageFinish();
+
+  /**
+   * Perform a single step of snake evolution. Returns true if the evolution
+   * has converged
+   */
+  bool PerformEvolutionStep();
+
+  /** Rewind the evolution */
+  void RewindEvolution();
+
+  /** Cancel segmentation and return to IRIS */
+  void OnCancelSegmentation();
+
+  /* ===================================================================
+   * CLUSTERING SUPPORT (GMM)
+   * =================================================================== */
+
+  /** Model controlling the number of clusters in the GMM */
+  irisRangedPropertyAccessMacro(NumberOfClusters, int)
+
+  /** Model controlling the number of sampled for GMM optimization */
+  irisRangedPropertyAccessMacro(NumberOfGMMSamples, int)
+
+  /** Model controlling the cluster used for the foreground probability */
+  irisRangedPropertyAccessMacro(ForegroundCluster, int)
+
+  typedef SimpleItemSetDomain<int, std::string> ComponentDomain;
+  typedef ConcretePropertyModel<int, ComponentDomain> ComponentIndexModel;
+
+  irisGetMacro(ClusterPlottedComponentModel, ComponentIndexModel *)
+
+  void ReinitializeClustering();
+
+  void PerformClusteringIteration();
+
+  // TODO: get rid of this?
+  bool SetClusterForegroundState(int cluster, bool state);
+
+  // TODO: get rid of this?
+  double GetClusterWeight(int cluster);
+  bool SetClusterWeight(int cluster, double weight);
+
+  double GetClusterNativeMean(int cluster, int component);
+  bool SetClusterNativeMean(int cluster, int component, double x);
+
+  double GetClusterNativeCovariance(int cluster, int comp1, int comp2);
+  double GetClusterNativeTotalVariance(int cluster);
+
+  double EvaluateClusterMarginalUnivariatePDF(int cluster, int component, double x);
+
+  /* ===================================================================
+   * SUPERVISED CLASSIFICATION SUPPORT (RANDOM FORESTS)
+   * =================================================================== */
+
+  /** Model controlling the class/label used for the foreground probability */
+  typedef STLMapWrapperItemSetDomain<LabelType, ColorLabel> ForegroundClassDomain;
+  irisGenericPropertyAccessMacro(ForegroundClassColorLabel, LabelType, ForegroundClassDomain)
+
+  /** Model for the forest size */
+  irisRangedPropertyAccessMacro(ForestSize, int)
+
+  /** Train the random forest classifier when the user hits the 'train' button */
+  void TrainClassifier();
+
+  /** Clear the classification examples (i.e., clear the classification) */
+  void ClearSegmentation();
+
+protected:
+  SnakeWizardModel();
+  virtual ~SnakeWizardModel() {}
+
+  SmartPtr<AbstractRangedDoubleProperty> m_ThresholdUpperModel;
+  bool GetThresholdUpperValueAndRange(double &x, NumericValueRange<double> *range);
+  void SetThresholdUpperValue(double x);
+
+  SmartPtr<AbstractRangedDoubleProperty> m_ThresholdLowerModel;
+  bool GetThresholdLowerValueAndRange(double &x, NumericValueRange<double> *range);
+  void SetThresholdLowerValue(double x);
+
+  SmartPtr<AbstractRangedDoubleProperty> m_ThresholdSmoothnessModel;
+  bool GetThresholdSmoothnessValueAndRange(double &x, NumericValueRange<double> *range);
+  void SetThresholdSmoothnessValue(double x);
+
+  SmartPtr<AbstractThresholdModeModel> m_ThresholdModeModel;
+  bool GetThresholdModeValue(ThresholdSettings::ThresholdMode &x);
+  void SetThresholdModeValue(ThresholdSettings::ThresholdMode x);
+
+  SmartPtr<AbstractLayerSelectionModel> m_ThresholdActiveLayerModel;
+  bool GetThresholdActiveLayerValueAndRange(unsigned long &value, LayerSelectionDomain *range);
+  void SetThresholdActiveLayerValue(unsigned long value);
+
+  SmartPtr<AbstractScalarRepSelectionModel> m_ThresholdActiveScalarRepModel;
+  bool GetThresholdActiveScalarRepValueAndRange(LayerScalarRepIndex &value, ScalarRepSelectionDomain *range);
+  void SetThresholdActiveScalarRepValue(LayerScalarRepIndex value);
+
+  SmartPtr<AbstractSimpleBooleanProperty> m_PreviewModel;
+  bool GetPreviewValue(bool &value);
+  void SetPreviewValue(bool value);
+
+  SmartPtr<AbstractSimpleBooleanProperty> m_BlueWhiteSpeedModeModel;
+  bool GetBlueWhiteSpeedModeValue(bool &value);
+  void SetBlueWhiteSpeedModeValue(bool value);
+
+  SmartPtr<AbstractSimpleBooleanProperty> m_RedTransparentSpeedModeModel;
+  bool GetRedTransparentSpeedModeValue(bool &value);
+  void SetRedTransparentSpeedModeValue(bool value);
+
+  SmartPtr<AbstractRangedDoubleProperty> m_EdgePreprocessingSigmaModel;
+  bool GetEdgePreprocessingSigmaValueAndRange(double &x, NumericValueRange<double> *range);
+  void SetEdgePreprocessingSigmaValue(double x);
+
+  SmartPtr<AbstractRangedDoubleProperty> m_EdgePreprocessingExponentModel;
+  bool GetEdgePreprocessingExponentValueAndRange(double &x, NumericValueRange<double> *range);
+  void SetEdgePreprocessingExponentValue(double x);
+
+  SmartPtr<AbstractRangedDoubleProperty> m_EdgePreprocessingKappaModel;
+  bool GetEdgePreprocessingKappaValueAndRange(double &x, NumericValueRange<double> *range);
+  void SetEdgePreprocessingKappaValue(double x);
+
+  SmartPtr<AbstractSnakeTypeModel> m_SnakeTypeModel;
+  bool GetSnakeTypeValueAndRange(SnakeType &value, GlobalState::SnakeTypeDomain *range);
+  void SetSnakeTypeValue(SnakeType value);
+
+  SmartPtr<AbstractPreprocessingModeModel> m_PreprocessingModeModel;
+  bool GetPreprocessingModeValueAndRange(PreprocessingMode &value, PreprocessingModeDomain *range);
+  void SetPreprocessingModeValue(PreprocessingMode value);
+
+  SmartPtr<AbstractSimpleIntProperty> m_ActiveBubbleModel;
+  bool GetActiveBubbleValue(int &value);
+  void SetActiveBubbleValue(int value);
+
+  SmartPtr<AbstractRangedDoubleProperty> m_BubbleRadiusModel;
+  bool GetBubbleRadiusValueAndRange(double &value, NumericValueRange<double> *range);
+  void SetBubbleRadiusValue(double value);
+
+  SmartPtr<ConcreteRangedIntProperty> m_StepSizeModel;
+
+  SmartPtr<AbstractSimpleIntProperty> m_EvolutionIterationModel;
+  int GetEvolutionIterationValue();
+
+  // Get the threshold settings for the active layer
+  ThresholdSettings *GetThresholdSettings();
+
+  // Helper function to check if particular set of models is active
+  bool AreThresholdModelsActive();
+  bool AreEdgePreprocessingModelsActive();
+
+  // Helper function to check if we can generate a speed image given the
+  // current pre-segmentation settings.
+  bool CanGenerateSpeedVolume();
+
+  // For models that work on only a single scalar image layer, report which
+  // layer is currently selected as the target layer
+  ScalarImageWrapperBase *GetSelectedScalarLayer();
+
+  // Compute range and def value of radius based on ROI dimensions
+  void ComputeBubbleRadiusDefaultAndRange();
+
+  // Range for the bubble radius variable
+  NumericValueRange<double> m_BubbleRadiusDomain;
+
+  // Default value for the bubble radius (when there is no selection)
+  double m_BubbleRadiusDefaultValue;
+
+  // Are we in bubble mode
+  InteractionMode m_InteractionMode;
+
+  void SetInteractionMode(InteractionMode mode);
+
+  /* ===================================================================
+   * CLUSTERING SUPPORT (GMM)
+   * =================================================================== */
+
+  // Model for the number of clusters
+  SmartPtr<AbstractRangedIntProperty> m_NumberOfClustersModel;
+  bool GetNumberOfClustersValueAndRange(int &value, NumericValueRange<int> *range);
+  void SetNumberOfClustersValue(int value);
+
+  // Model for the number of clusters
+  SmartPtr<AbstractRangedIntProperty> m_NumberOfGMMSamplesModel;
+  bool GetNumberOfGMMSamplesValueAndRange(int &value, NumericValueRange<int> *range);
+  void SetNumberOfGMMSamplesValue(int value);
+
+  // Model for the active cluster
+  SmartPtr<AbstractRangedIntProperty> m_ForegroundClusterModel;
+  bool GetForegroundClusterValueAndRange(int &value, NumericValueRange<int> *range);
+  void SetForegroundClusterValue(int value);
+
+  // Model for the selected component
+  SmartPtr<ComponentIndexModel> m_ClusterPlottedComponentModel;
+
+  // TODO: this should be handled through the ITK modified mechanism
+  void TagGMMPreprocessingFilterModified();
+
+  // A list of all components available to clustering and other multi-variate
+  // segmentation code. This list is updated in OnUpdate() in response to any
+  // events that change the number of available layers.
+  std::vector<ComponentInfo> m_ComponentInfo;
+
+  // Update the model for component selection
+  void UpdateClusterPlottedComponentModel();
+
+
+  /* ===================================================================
+   * SUPERVISED CLASSIFICATION SUPPORT (Random Forest)
+   * =================================================================== */
+
+  // A mapping of currently defined classes to color label descriptors
+  std::map<LabelType, ColorLabel> m_ActiveClasses;
+
+  // Model for the foreground color label
+  typedef AbstractPropertyModel<LabelType, ForegroundClassDomain>
+    AbstractForegroundClassPropertyModel;
+
+  // A list of suggested labels, from which the user can choose one to draw
+  // These labels are the N most recently used labels
+  std::map<LabelType, ColorLabel> m_ClassifyQuickLabels;
+
+  // The size of the suggested label list (static)
+  static unsigned int m_ClassifyQuickLabelsCount;
+
+  // Model for the suggested labels from which the user can choose one to draw
+
+
+  SmartPtr<AbstractForegroundClassPropertyModel> m_ForegroundClassColorLabelModel;
+  bool GetForegroundClassColorLabelValueAndRange(LabelType &value, ForegroundClassDomain *range);
+  void SetForegroundClassColorLabelValue(LabelType value);
+
+  SmartPtr<AbstractRangedIntProperty> m_ForestSizeModel;
+  bool GetForestSizeValueAndRange(int &value, NumericValueRange<int> *range);
+  void SetForestSizeValue(int value);
+
+  // TODO: this should be handled through the ITK modified mechanism
+  void TagRFPreprocessingFilterModified();
+
+  // Parent model
+  GlobalUIModel *m_Parent;
+  IRISApplication *m_Driver;
+  GlobalState *m_GlobalState;
+
+
+};
+
+#endif // SNAKEWIZARDMODEL_H
diff --git a/GUI/Model/StateManagement.cxx b/GUI/Model/StateManagement.cxx
new file mode 100644
index 0000000..dbded0d
--- /dev/null
+++ b/GUI/Model/StateManagement.cxx
@@ -0,0 +1,79 @@
+#include "StateManagement.h"
+#include "SNAPEvents.h"
+#include "SNAPEventListenerCallbacks.h"
+
+void BooleanCondition
+::OnStateChange()
+{
+  InvokeEvent(StateMachineChangeEvent());
+}
+
+BinaryBooleanCondition
+::BinaryBooleanCondition(BooleanCondition *a, BooleanCondition *b)
+{
+  m_A = a;
+  m_B = b;
+
+  // Make sure events propagate up
+  AddListener<BooleanCondition>(m_A, StateMachineChangeEvent(),
+                                this, &BooleanCondition::OnStateChange);
+
+  AddListener<BooleanCondition>(m_B, StateMachineChangeEvent(),
+                                this, &BinaryBooleanCondition::OnStateChange);
+}
+
+AndCondition::AndCondition(BooleanCondition *a, BooleanCondition *b)
+  : BinaryBooleanCondition(a,b)
+{
+}
+
+bool AndCondition::operator ()() const
+{
+  return (*m_A)() && (*m_B)();
+}
+
+SmartPtr<AndCondition>
+AndCondition::New(BooleanCondition *a, BooleanCondition *b)
+{
+  SmartPtr<AndCondition> p = new AndCondition(a, b);
+  p->UnRegister();
+  return p;
+}
+
+OrCondition::OrCondition(BooleanCondition *a, BooleanCondition *b)
+  : BinaryBooleanCondition(a,b)
+{
+}
+
+bool OrCondition::operator ()() const
+{
+  return (*m_A)() || (*m_B)();
+}
+
+SmartPtr<OrCondition>
+OrCondition::New(BooleanCondition *a, BooleanCondition *b)
+{
+  SmartPtr<OrCondition> p = new OrCondition(a, b);
+  p->UnRegister();
+  return p;
+}
+
+NotCondition::NotCondition(BooleanCondition *a)
+{
+  m_A = a;
+  AddListener<BooleanCondition>(m_A, StateMachineChangeEvent(),
+                                this, &BooleanCondition::OnStateChange);
+}
+
+bool NotCondition::operator ()() const
+{
+  return ! (*m_A)();
+}
+
+SmartPtr<NotCondition>
+NotCondition::New(BooleanCondition *a)
+{
+  SmartPtr<NotCondition> p = new NotCondition(a);
+  p->UnRegister();
+  return p;
+}
diff --git a/GUI/Model/StateManagement.h b/GUI/Model/StateManagement.h
new file mode 100644
index 0000000..494edd8
--- /dev/null
+++ b/GUI/Model/StateManagement.h
@@ -0,0 +1,134 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef STATEMANAGEMENT_H
+#define STATEMANAGEMENT_H
+
+#include <itkObject.h>
+#include <SNAPCommon.h>
+#include <SNAPEvents.h>
+
+/**
+  An abstract condition that returns true or false. Used to create dynamic
+  boolean operators for widget activation and state management.
+
+  These conditions can be used in the following form
+
+  SmartPtr<BooleanCondition> p =
+    AndCondition::New(
+      MyCondition::New(BLAH), NotCondition::New(MyCondition::New(FOO)));
+
+  (*p)() // BLAH && (!FOO)
+  */
+class BooleanCondition : public itk::Object
+{
+public:
+
+  FIRES(StateMachineChangeEvent)
+
+  virtual bool operator () () const = 0;
+
+  virtual void OnStateChange();
+
+protected:
+  BooleanCondition() {}
+  virtual ~BooleanCondition() {}
+
+};
+
+class BinaryBooleanCondition : public BooleanCondition
+{
+public:
+
+protected:
+  BinaryBooleanCondition(BooleanCondition *a, BooleanCondition *b);
+
+  SmartPtr<BooleanCondition> m_A, m_B;
+};
+
+class AndCondition : public BinaryBooleanCondition
+{  
+public:
+  typedef AndCondition Self;
+  typedef BinaryBooleanCondition Superclass;
+
+  itkTypeMacro(Self, Superclass)
+
+  static SmartPtr<Self> New(BooleanCondition *a, BooleanCondition *b);
+
+  bool operator() () const;
+
+protected:
+
+  AndCondition(BooleanCondition *a, BooleanCondition *b);
+  virtual ~AndCondition() {}
+
+};
+
+class OrCondition : public BinaryBooleanCondition
+{
+public:
+  typedef OrCondition Self;
+  typedef BinaryBooleanCondition Superclass;
+
+  itkTypeMacro(Self, Superclass)
+
+  static SmartPtr<Self> New(BooleanCondition *a, BooleanCondition *b);
+
+  bool operator() () const;
+
+protected:
+
+  OrCondition(BooleanCondition *a, BooleanCondition *b);
+  virtual ~OrCondition() {}
+
+};
+
+class NotCondition : public BooleanCondition
+{
+public:
+  typedef NotCondition Self;
+  typedef BooleanCondition Superclass;
+
+  itkTypeMacro(Self, Superclass)
+
+  static SmartPtr<Self> New(BooleanCondition *a);
+
+  bool operator () () const;
+
+protected:
+
+  NotCondition(BooleanCondition *a);
+
+  virtual ~NotCondition() {}
+
+
+private:
+  SmartPtr<BooleanCondition> m_A;
+
+};
+
+#endif // STATEMANAGEMENT_H
diff --git a/GUI/Model/SynchronizationModel.cxx b/GUI/Model/SynchronizationModel.cxx
new file mode 100644
index 0000000..d8a12e8
--- /dev/null
+++ b/GUI/Model/SynchronizationModel.cxx
@@ -0,0 +1,221 @@
+#include "SynchronizationModel.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "SystemInterface.h"
+#include "GenericSliceModel.h"
+#include "GenericImageData.h"
+#include "ImageWrapperBase.h"
+#include "SliceWindowCoordinator.h"
+#include "Generic3DModel.h"
+#include "Generic3DRenderer.h"
+#include "vtkCamera.h"
+#include "vtkCommand.h"
+#include "IPCHandler.h"
+
+/** Structure passed on to IPC */
+struct IPCMessage
+{
+  // The cursor position in world coordinates
+  Vector3d cursor;
+
+  // The zoom factor (screen pixels / mm)
+  double zoom_level[3];
+
+  // The position of the viewport center relative to cursor
+  // in all three slice views
+  Vector2f viewPositionRelative[3];
+
+  // 3D camera state
+  CameraState camera;
+
+  // Version of the data structure
+  enum VersionEnum { VERSION = 0x1005 };
+};
+
+
+SynchronizationModel::SynchronizationModel()
+{
+  // Create the models
+  m_SyncEnabledModel = NewSimpleConcreteProperty(true);
+  m_SyncCursorModel = NewSimpleConcreteProperty(true);
+  m_SyncZoomModel = NewSimpleConcreteProperty(true);
+  m_SyncPanModel = NewSimpleConcreteProperty(true);
+  m_SyncCameraModel = NewSimpleConcreteProperty(true);
+
+  m_SyncChannelModel = NewRangedConcreteProperty(1, 1, 99, 1);
+
+  // Create an IPC handler
+  m_IPCHandler = new IPCHandler();
+
+  // Broadcast state
+  m_CanBroadcast = false;
+}
+
+SynchronizationModel::~SynchronizationModel()
+{
+  if(m_IPCHandler->IsAttached())
+    m_IPCHandler->Close();
+  delete m_IPCHandler;
+}
+
+void SynchronizationModel::SetParentModel(GlobalUIModel *parent)
+{
+  // Set the parent
+  m_Parent = parent;
+  m_SystemInterface = m_Parent->GetDriver()->GetSystemInterface();
+
+  // Initialize the IPC handler
+  m_IPCHandler->Attach(
+        m_SystemInterface->GetUserPreferencesFileName(),
+        (short) IPCMessage::VERSION, sizeof(IPCMessage));
+
+  // TODO: the defaults should be read from global preferences
+
+  // Listen to the events from the parent that correspond to changes that
+  // need to be broadcast, and send them downstream as model update events
+
+  // Cursor changes
+  Rebroadcast(m_Parent->GetDriver(), CursorUpdateEvent(), ModelUpdateEvent());
+
+  // Viewpoint geometry changes
+  for(int i = 0; i < 3; i++)
+    {
+    GenericSliceModel *gsm = m_Parent->GetSliceModel(i);
+    Rebroadcast(gsm, SliceModelGeometryChangeEvent(), ModelUpdateEvent());
+    }
+
+  // Changes to the 3D viewpoint (stored in a vtkCamera object)
+  Rebroadcast(m_Parent->GetModel3D()->GetRenderer(),
+              Generic3DRenderer::CameraUpdateEvent(), ModelUpdateEvent());
+}
+
+
+void SynchronizationModel::OnUpdate()
+{
+  // If there is no synchronization or no image, get out
+  IRISApplication *app = m_Parent->GetDriver();
+  if(!app->IsMainImageLoaded()
+     || !m_SyncEnabledModel->GetValue()
+     || !m_CanBroadcast)
+    return;
+
+  // Figure out what to broadcast
+  bool bc_cursor =
+      m_EventBucket->HasEvent(CursorUpdateEvent())
+      && m_SyncCursorModel->GetValue();
+
+  bool bc_zoom =
+      m_EventBucket->HasEvent(SliceModelGeometryChangeEvent())
+      && m_SyncZoomModel->GetValue();
+
+  bool bc_pan =
+      (m_EventBucket->HasEvent(SliceModelGeometryChangeEvent())
+       || m_EventBucket->HasEvent(CursorUpdateEvent()))
+      && m_SyncPanModel->GetValue();
+
+  bool bc_camera =
+      m_EventBucket->HasEvent(Generic3DRenderer::CameraUpdateEvent())
+      && m_SyncCameraModel->GetValue();
+
+  // Read the contents of shared memory into the local message object
+  IPCMessage message;
+  m_IPCHandler->Read(static_cast<void *>(&message));
+
+  // Cursor change
+  if(bc_cursor)
+    {
+    // Map the cursor to NIFTI coordinates
+    ImageWrapperBase *iw = app->GetCurrentImageData()->GetMain();
+    message.cursor =
+        iw->TransformVoxelIndexToNIFTICoordinates(
+          to_double(app->GetCursorPosition()));
+    }
+
+  // Zoom/Pan change
+  for(int i = 0; i < 3; i++)
+    {
+    GenericSliceModel *gsm = m_Parent->GetSliceModel(i);
+    AnatomicalDirection dir = app->GetAnatomicalDirectionForDisplayWindow(i);
+
+    if(bc_zoom)
+      message.zoom_level[dir] = gsm->GetViewZoom();
+    if(bc_pan)
+      message.viewPositionRelative[dir] = gsm->GetViewPositionRelativeToCursor();
+    }
+
+  // 3D viewpoint
+  if(bc_camera)
+    {
+    // Get the camera state
+    CameraState cs = m_Parent->GetModel3D()->GetRenderer()->GetCameraState();
+    message.camera = cs;
+    }
+
+  // Broadcast the new message
+  m_IPCHandler->Broadcast(static_cast<void *>(&message));
+}
+
+void SynchronizationModel::ReadIPCState()
+{
+  IRISApplication *app = m_Parent->GetDriver();
+  if(!app->IsMainImageLoaded() || !m_SyncCursorModel->GetValue())
+    return;
+
+  // Read the IPC message
+  IPCMessage message;
+  if(m_IPCHandler->ReadIfNew(static_cast<void *>(&message)))
+    {
+    if(m_SyncCursorModel->GetValue())
+      {
+      // Map the cursor position to the image coordinates
+      GenericImageData *id = app->GetCurrentImageData();
+      Vector3d vox =
+          id->GetMain()->TransformNIFTICoordinatesToVoxelIndex(message.cursor);
+
+      // Round the cursor to integer value
+      itk::Index<3> pos; Vector3ui vpos;
+      pos[0] = vpos[0] = (unsigned int) (vox[0] + 0.5);
+      pos[1] = vpos[1] = (unsigned int) (vox[1] + 0.5);
+      pos[2] = vpos[2] = (unsigned int) (vox[2] + 0.5);
+
+      // Check if the voxel position is inside the image region
+      if(vpos != app->GetCursorPosition() && id->GetImageRegion().IsInside(pos))
+        {
+        app->SetCursorPosition(vpos);
+        }
+      }
+
+    // Set the zoom/pan levels
+    for(int i = 0; i < 3; i++)
+      {
+      GenericSliceModel *gsm = m_Parent->GetSliceModel(i);
+      AnatomicalDirection dir = app->GetAnatomicalDirectionForDisplayWindow(i);
+
+      if(m_SyncZoomModel->GetValue()
+         && gsm->IsSliceInitialized()
+         && gsm->GetViewZoom() != message.zoom_level[dir])
+        {
+          gsm->SetViewZoom(message.zoom_level[dir]);
+        }
+
+      if(m_SyncPanModel->GetValue()
+         && gsm->IsSliceInitialized()
+         && gsm->GetViewPositionRelativeToCursor() != message.viewPositionRelative[dir])
+        {
+        gsm->SetViewPositionRelativeToCursor(message.viewPositionRelative[dir]);
+        }
+      }
+
+    // Set the camera state
+    if(m_SyncCameraModel->GetValue())
+      {
+      // Get the currently used 3D camera
+      CameraState cs = message.camera;
+      m_Parent->GetModel3D()->GetRenderer()->SetCameraState(message.camera);
+      }
+    }
+}
+
+
+
+
diff --git a/GUI/Model/SynchronizationModel.h b/GUI/Model/SynchronizationModel.h
new file mode 100644
index 0000000..9797c50
--- /dev/null
+++ b/GUI/Model/SynchronizationModel.h
@@ -0,0 +1,60 @@
+#ifndef SYNCHRONIZATIONMODEL_H
+#define SYNCHRONIZATIONMODEL_H
+
+#include "PropertyModel.h"
+
+class GlobalUIModel;
+class SystemInterface;
+class IPCHandler;
+
+/**
+ * @brief Model that interfaces with the GUI controls that handle
+ * synchronization
+ */
+class SynchronizationModel : public AbstractModel
+{
+public:
+  irisITKObjectMacro(SynchronizationModel, AbstractModel)
+
+  void SetParentModel(GlobalUIModel *parent);
+
+  /** Models controlling sync state */
+  irisSimplePropertyAccessMacro(SyncEnabled, bool)
+  irisRangedPropertyAccessMacro(SyncChannel, int)
+  irisSimplePropertyAccessMacro(SyncCursor, bool)
+  irisSimplePropertyAccessMacro(SyncZoom, bool)
+  irisSimplePropertyAccessMacro(SyncPan, bool)
+  irisSimplePropertyAccessMacro(SyncCamera, bool)
+
+  /**
+   * Whether the model should be broadcasting. The GUI should toggle this
+   * flag depending on whether the window is active or not */
+  irisGetSetMacro(CanBroadcast, bool)
+
+  /** This method should be called by UI at regular intervals to read IPC state */
+  void ReadIPCState();
+
+protected:
+
+  SynchronizationModel();
+  virtual ~SynchronizationModel();
+
+  virtual void OnUpdate();
+
+  SmartPtr<ConcreteSimpleBooleanProperty> m_SyncEnabledModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_SyncCursorModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_SyncZoomModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_SyncPanModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_SyncCameraModel;
+
+  SmartPtr<ConcreteRangedIntProperty> m_SyncChannelModel;
+
+  GlobalUIModel *m_Parent;
+  SystemInterface *m_SystemInterface;
+
+  IPCHandler *m_IPCHandler;
+
+  bool m_CanBroadcast;
+};
+
+#endif // SYNCHRONIZATIONMODEL_H
diff --git a/GUI/Model/UIAction.cxx b/GUI/Model/UIAction.cxx
new file mode 100644
index 0000000..d91d457
--- /dev/null
+++ b/GUI/Model/UIAction.cxx
@@ -0,0 +1,9 @@
+#include "UIAction.h"
+#include <cstdarg>
+
+
+void UIAbstractAction::Initialize(GlobalUIModel *model)
+{
+  this->m_Model = model;
+}
+
diff --git a/GUI/Model/UIAction.h b/GUI/Model/UIAction.h
new file mode 100644
index 0000000..210d080
--- /dev/null
+++ b/GUI/Model/UIAction.h
@@ -0,0 +1,51 @@
+#ifndef UIACTION_H
+#define UIACTION_H
+
+#include "itkObject.h"
+#include "IRISException.h"
+#include <list>
+
+class GlobalUIModel;
+class IRISException;
+
+
+
+/**
+  A UI action is an object used to perform complex actions in SNAP. This
+  includes any actions that are undoable.
+  */
+class UIAbstractAction : public itk::Object
+{
+public:
+  typedef std::list<IRISWarning> WarningList;
+  typedef std::list<IRISWarning>::const_iterator WarningIter;
+
+  virtual void Execute() = 0;
+
+  virtual void Initialize(GlobalUIModel *model);
+
+  bool HasWarnings() const
+    { return m_Warnings.size() > 0; }
+
+  const WarningList &GetWarnings() const
+    { return m_Warnings; }
+
+
+protected:
+
+  GlobalUIModel *m_Model;
+
+  std::list<IRISWarning> m_Warnings;
+
+};
+
+
+
+class UIUndoableAction : public UIAbstractAction
+{
+public:
+  virtual void Undo() = 0;
+
+};
+
+#endif // UIACTION_H
diff --git a/GUI/Model/UIReporterDelegates.cxx b/GUI/Model/UIReporterDelegates.cxx
new file mode 100644
index 0000000..1982911
--- /dev/null
+++ b/GUI/Model/UIReporterDelegates.cxx
@@ -0,0 +1,5 @@
+#include "UIReporterDelegates.h"
+
+UIReporterDelegates::UIReporterDelegates()
+{
+}
diff --git a/GUI/Model/UIReporterDelegates.h b/GUI/Model/UIReporterDelegates.h
new file mode 100644
index 0000000..53451e3
--- /dev/null
+++ b/GUI/Model/UIReporterDelegates.h
@@ -0,0 +1,90 @@
+#ifndef UIREPORTERDELEGATES_H
+#define UIREPORTERDELEGATES_H
+
+#include "SNAPCommon.h"
+#include "SNAPEvents.h"
+#include "itkObject.h"
+#include "itkObjectFactory.h"
+
+namespace itk
+{
+template <class TPixel, unsigned int VDim> class Image;
+}
+
+class Registry;
+
+/**
+  An interface used by models to request the viewport size from the GUI and
+  for the GUI to notify models of changes in the viewport size.
+  */
+class ViewportSizeReporter : public itk::Object
+{
+public:
+  itkEventMacro(ViewportResizeEvent,IRISEvent)
+
+  /** Child classes are expected to fire this event when viewport resizes */
+  FIRES(ViewportResizeEvent)
+
+  virtual bool CanReportSize() = 0;
+  virtual Vector2ui GetViewportSize() = 0;
+
+  /** For retina displays, report the ratio of actual GL pixels to logical pixels */
+  virtual float GetViewportPixelRatio() = 0;
+
+  /** Get the viewport size in logical units (for retina-like displays) */
+  virtual Vector2ui GetLogicalViewportSize() = 0;
+
+
+protected:
+  virtual ~ViewportSizeReporter() {}
+};
+
+
+/**
+  This is a progress reporter delegate that allows the SNAP model classes
+  to report progress without knowing what GUI toolkit actually implements
+  the progress dialog.
+  */
+class ProgressReporterDelegate
+{
+public:
+
+  /** Set the progress value between 0 and 1 */
+  virtual void SetProgressValue(double) = 0;
+
+
+
+};
+
+/**
+ This is a delegate that renders text into a bitmap. This is used with
+ OpenGL code that needs to draw text
+ */
+class TextRenderingDelegate
+{
+public:
+  virtual void RenderTextInOpenGL(
+      const char *text,
+      int x, int y, int w, int h,
+      int font_size,
+      int align_horiz, int align_vert,
+      unsigned char rgba[]) = 0;
+};
+
+/**
+ This delegate is used to obtain system-specific information
+ */
+class SystemInfoDelegate
+{
+public:
+  virtual std::string GetApplicationDirectory() = 0;
+  virtual std::string GetApplicationFile() = 0;
+
+  virtual std::string GetApplicationPermanentDataLocation() = 0;
+
+  typedef itk::Image<unsigned char, 2> GrayscaleImage;
+  virtual void LoadResourceAsImage2D(std::string tag, GrayscaleImage *image) = 0;
+  virtual void LoadResourceAsRegistry(std::string tag, Registry &reg) = 0;
+};
+
+#endif // UIREPORTERDELEGATES_H
diff --git a/GUI/Model/UIState.h b/GUI/Model/UIState.h
new file mode 100644
index 0000000..3024486
--- /dev/null
+++ b/GUI/Model/UIState.h
@@ -0,0 +1,22 @@
+#ifndef UISTATE_H
+#define UISTATE_H
+
+/** A list of states that the Global UI may be in. Whenever any of these
+  states changes, the UI issues a StateChangedEvent */
+enum UIState {
+  UIF_BASEIMG_LOADED,            // i.e., Gray or RGB loaded
+  UIF_OVERLAY_LOADED,            // i.e., Baseimg loaded and at least one overlay
+  UIF_IRIS_MODE,                 // Not in snake mode (or other future such mode)
+  UIF_IRIS_WITH_BASEIMG_LOADED,  // i.e., system in main interaction mode
+  UIF_IRIS_WITH_OVERLAY_LOADED,  // i.e., system in main interaction mode
+  UIF_ROI_VALID,
+  UIF_LINKED_ZOOM,
+  UIF_UNDO_POSSIBLE,
+  UIF_REDO_POSSIBLE,
+  UIF_UNSAVED_CHANGES,
+  UIF_MESH_SAVEABLE,
+  UIF_SNAKE_MODE,
+  UIF_LEVEL_SET_ACTIVE
+};
+
+#endif // UISTATE_H
diff --git a/GUI/Qt/Components/.DS_Store b/GUI/Qt/Components/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/GUI/Qt/Components/.DS_Store differ
diff --git a/GUI/Qt/Components/CollapsableGroupBox.cxx b/GUI/Qt/Components/CollapsableGroupBox.cxx
new file mode 100644
index 0000000..c821610
--- /dev/null
+++ b/GUI/Qt/Components/CollapsableGroupBox.cxx
@@ -0,0 +1,35 @@
+#include "CollapsableGroupBox.h"
+#include "ui_CollapsableGroupBox.h"
+#include "QLayout"
+
+CollapsableGroupBox::CollapsableGroupBox(QWidget *parent) :
+  QWidget(parent),
+  ui(new Ui::CollapsableGroupBox)
+{
+  ui->setupUi(this);
+}
+
+CollapsableGroupBox::~CollapsableGroupBox()
+{
+  delete ui;
+}
+
+QString CollapsableGroupBox::title() const
+{
+  return ui->pushButton->text();
+}
+
+void CollapsableGroupBox::setTitle(QString title)
+{
+  ui->pushButton->setText(title);
+}
+
+void CollapsableGroupBox::addWidget(QWidget *widget)
+{
+  ui->body->layout()->addWidget(widget);
+}
+
+void CollapsableGroupBox::collapse(bool flag)
+{
+  ui->body->setMaximumHeight(flag ? 0 : 999999);
+}
diff --git a/GUI/Qt/Components/CollapsableGroupBox.h b/GUI/Qt/Components/CollapsableGroupBox.h
new file mode 100644
index 0000000..c3071cc
--- /dev/null
+++ b/GUI/Qt/Components/CollapsableGroupBox.h
@@ -0,0 +1,31 @@
+#ifndef COLLAPSABLEGROUPBOX_H
+#define COLLAPSABLEGROUPBOX_H
+
+#include <QWidget>
+
+namespace Ui {
+class CollapsableGroupBox;
+}
+
+class CollapsableGroupBox : public QWidget
+{
+  Q_OBJECT
+  Q_PROPERTY(QString title READ title WRITE setTitle USER true)
+  
+public:
+  explicit CollapsableGroupBox(QWidget *parent = 0);
+  ~CollapsableGroupBox();
+
+  QString title() const;
+  void setTitle(QString title);
+
+  void addWidget(QWidget *widget);
+
+public slots:
+  void collapse(bool flag);
+  
+private:
+  Ui::CollapsableGroupBox *ui;
+};
+
+#endif // COLLAPSABLEGROUPBOX_H
diff --git a/GUI/Qt/Components/CollapsableGroupBox.ui b/GUI/Qt/Components/CollapsableGroupBox.ui
new file mode 100644
index 0000000..d0c611d
--- /dev/null
+++ b/GUI/Qt/Components/CollapsableGroupBox.ui
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CollapsableGroupBox</class>
+ <widget class="QWidget" name="CollapsableGroupBox">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>214</width>
+    <height>309</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QWidget#body
+{
+	border-left: 1px solid gray;
+  	border-right: 1px solid gray;
+    background-color: gray;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QPushButton" name="pushButton">
+     <property name="focusPolicy">
+      <enum>Qt::NoFocus</enum>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">QPushButton {
+  border-radius:0px;
+  border-top: 1px solid gray;
+  border-bottom: 1px solid gray;
+  background-color: qlineargradient(spread:pad, x1:0.123, y1:0.125, x2:0.108, y2:1, stop:0 rgba(204, 204,   204, 255), stop:1 rgba(255, 255, 255, 255));
+  margin:0px;
+  padding: 0px;
+  text-align:left;
+  font:12px;
+}</string>
+     </property>
+     <property name="text">
+      <string>Main Image</string>
+     </property>
+     <property name="icon">
+      <iconset resource="../Resources/SNAPResources.qrc">
+       <normaloff>:/root/triangle_small_down_16.png</normaloff>
+       <normalon>:/root/triangle_small_right_16.png</normalon>:/root/triangle_small_down_16.png</iconset>
+     </property>
+     <property name="checkable">
+      <bool>true</bool>
+     </property>
+     <property name="flat">
+      <bool>false</bool>
+     </property>
+    </widget>
+   </item>
+   <item alignment="Qt::AlignTop">
+    <widget class="QWidget" name="body" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>1</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>pushButton</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>CollapsableGroupBox</receiver>
+   <slot>collapse(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>113</x>
+     <y>7</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>119</x>
+     <y>189</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+ <slots>
+  <slot>collapse(bool)</slot>
+ </slots>
+</ui>
diff --git a/GUI/Qt/Components/ColorLabelQuickListWidget.cxx b/GUI/Qt/Components/ColorLabelQuickListWidget.cxx
new file mode 100644
index 0000000..377a7ea
--- /dev/null
+++ b/GUI/Qt/Components/ColorLabelQuickListWidget.cxx
@@ -0,0 +1,124 @@
+#include "ColorLabelQuickListWidget.h"
+
+#include <QToolBar>
+#include <QAction>
+#include <QActionGroup>
+#include <QBoxLayout>
+
+#include "GlobalUIModel.h"
+#include "GlobalState.h"
+#include "IRISApplication.h"
+#include "ColorLabelQuickListModel.h"
+#include "ColorLabelTable.h"
+#include "SNAPQtCommon.h"
+#include "QtToolbarCoupling.h"
+
+ColorLabelQuickListWidget::ColorLabelQuickListWidget(QWidget *parent) :
+  SNAPComponent(parent)
+{
+  // There is no model
+  m_Model = NULL;
+
+  // Create and configure the toolbar
+  m_Toolbar = new QToolBar();
+  m_Toolbar->setIconSize(QSize(16,16));
+  m_Toolbar->setMovable(false);
+  m_Toolbar->setFloatable(false);
+  m_Toolbar->setStyleSheet("padding: 0px; spacing: 0px;");
+  m_Toolbar->setContentsMargins(0,0,0,0);
+
+  // Create and configure the action group
+  m_ActionGroup = new QActionGroup(m_Toolbar);
+
+  // Add toolbar via layout
+  QVBoxLayout *layout = new QVBoxLayout(this);
+  layout->setContentsMargins(0,0,0,0);
+  layout->addWidget(m_Toolbar);
+  this->setLayout(layout);
+
+  // RE-emit the signal from the toolbar
+  connect(m_Toolbar, SIGNAL(actionTriggered(QAction*)), this, SIGNAL(actionTriggered(QAction*)));
+
+  // Define the maximum label count
+  m_MaximumLabelCount = 6;
+}
+
+void ColorLabelQuickListWidget::SetModel(GlobalUIModel *model)
+{
+  // Grab a copy of the model
+  m_Model = model;
+
+  // Listen to changes in the label quicklist
+  ColorLabelQuickListModel *qlm = m_Model->GetColorLabelQuickListModel();
+  connectITK(qlm, ModelUpdateEvent());
+
+  // Use the coupling mechanism to handle label selection.
+  makeCoupling(m_Toolbar, qlm->GetActiveComboModel());
+}
+
+void ColorLabelQuickListWidget::setMaximumLabelCount(int value)
+{
+  // Change the maximum label count
+  m_MaximumLabelCount = value;
+
+  // We need to update the toolbar, but only if already there is a model
+  if(m_Model)
+    this->UpdateToolbar();
+}
+
+void ColorLabelQuickListWidget::onModelUpdate(const EventBucket &bucket)
+{
+  ColorLabelQuickListModel *qlm = m_Model->GetColorLabelQuickListModel();
+
+  // If there is an event from the quick list model, we need to rebuild
+  if(bucket.HasEvent(ModelUpdateEvent(), qlm))
+    {
+    this->UpdateToolbar();
+    }
+}
+
+void ColorLabelQuickListWidget::UpdateToolbar()
+{
+  // Get the color label table
+  ColorLabelTable *clt = m_Model->GetDriver()->GetColorLabelTable();
+
+  // Update the source of the label quick-list
+  ColorLabelQuickListModel *qlm = m_Model->GetColorLabelQuickListModel();
+  qlm->Update();
+
+  // Get the updated list of recent labels
+  const ColorLabelQuickListModel::ComboList &qlist = qlm->GetRecentCombos();
+
+  // Remove every action from the toolbar
+  foreach(QAction *action, m_ActionGroup->actions())
+    m_ActionGroup->removeAction(action);
+
+  m_Toolbar->clear();
+
+  // Add an action for each item
+  for(int i = 0; i < qlist.size(); i++)
+    {
+    // Create the action
+    QAction *action = new QAction(m_Toolbar);
+
+    // Get the foreground/background
+    LabelType fg = qlist[i].first;
+    DrawOverFilter bg = qlist[i].second;
+
+    // Configure action apperance
+    action->setIcon(CreateLabelComboIcon(16, 16, fg, bg, clt));
+    action->setToolTip(CreateLabelComboTooltip(fg, bg, clt));
+
+    // Set the action's data
+    action->setData(i);
+
+    // Make action checkable
+    action->setCheckable(true);
+
+    // Add the action to the action group
+    action->setActionGroup(m_ActionGroup);
+
+    // Add the action to the toolbar
+    m_Toolbar->addAction(action);
+    }
+}
diff --git a/GUI/Qt/Components/ColorLabelQuickListWidget.h b/GUI/Qt/Components/ColorLabelQuickListWidget.h
new file mode 100644
index 0000000..374f1d7
--- /dev/null
+++ b/GUI/Qt/Components/ColorLabelQuickListWidget.h
@@ -0,0 +1,57 @@
+#ifndef COLORLABELQUICKLISTWIDGET_H
+#define COLORLABELQUICKLISTWIDGET_H
+
+#include "SNAPCommon.h"
+#include "SNAPComponent.h"
+
+class QToolBar;
+class GlobalUIModel;
+class QAction;
+class QActionGroup;
+
+/**
+ * This is a widget holding a toolbar with a list of buttons, each corresponding
+ * to a color label. When the user clicks the buttons, that label is assigned
+ * to be the foreground label. Right clicking the label gives a context menu.
+ */
+class ColorLabelQuickListWidget : public SNAPComponent
+{
+  Q_OBJECT
+public:
+  explicit ColorLabelQuickListWidget(QWidget *parent = 0);
+  
+  /** Initialize the widget by assigning it a model */
+  void SetModel(GlobalUIModel *model);
+
+  /** Set the number of labels to display */
+  void setMaximumLabelCount(int value);
+
+signals:
+
+  void actionTriggered(QAction *);
+  
+public slots:
+
+protected:
+
+  // The widget contains a toolbar with a list of actions
+  QToolBar *m_Toolbar;
+
+  // An action group controlling action behavior
+  QActionGroup *m_ActionGroup;
+
+  // A pointer to the model
+  GlobalUIModel *m_Model;
+
+  // The number of labels to display
+  int m_MaximumLabelCount;
+
+  // Handle an update from the model
+  virtual void onModelUpdate(const EventBucket &bucket);
+
+  // Populate the toolbar from the model
+  void UpdateToolbar();
+
+};
+
+#endif // COLORLABELQUICKLISTWIDGET_H
diff --git a/GUI/Qt/Components/ColorMapInspector.cxx b/GUI/Qt/Components/ColorMapInspector.cxx
new file mode 100644
index 0000000..1ad2d1e
--- /dev/null
+++ b/GUI/Qt/Components/ColorMapInspector.cxx
@@ -0,0 +1,180 @@
+#include "ColorMapInspector.h"
+#include "ui_ColorMapInspector.h"
+#include "ColorMapModel.h"
+#include "QtReporterDelegates.h"
+#include "QtDoubleSpinBoxCoupling.h"
+#include "QtSpinBoxCoupling.h"
+#include "QtRadioButtonCoupling.h"
+#include "QtWidgetActivator.h"
+#include <QColorDialog>
+#include <QInputDialog>
+#include "SNAPQtCommon.h"
+
+ColorMapInspector::ColorMapInspector(QWidget *parent) :
+  SNAPComponent(parent),
+  ui(new Ui::ColorMapInspector)
+{
+  ui->setupUi(this);
+
+  m_PresetsUpdating = false;
+
+  // Create the viewport reporter
+  m_ColorMapBoxViewportReporter = QtViewportReporter::New();
+  m_ColorMapBoxViewportReporter->SetClientWidget(ui->boxColorMap);
+
+  // Connect the interactor on the colormap box to this object
+  ui->boxColorMap->GetDelegate()->SetInspectorWidget(this);
+}
+
+ColorMapInspector::~ColorMapInspector()
+{
+  delete ui;
+}
+
+void ColorMapInspector::SetModel(ColorMapModel *model)
+{
+  // Set the model
+  m_Model = model;
+
+  // Pass the model to the colormap box
+  ui->boxColorMap->SetModel(model);
+
+  // Connect the viewport reporter
+  model->SetViewportReporter(m_ColorMapBoxViewportReporter);
+
+  // Listen to model update events
+  connectITK(m_Model, ModelUpdateEvent());
+  connectITK(m_Model, ColorMapModel::PresetUpdateEvent());
+
+  // Connect widgets to the corresponding sub-models
+  makeCoupling(ui->inControlX, m_Model->GetMovingControlPositionModel());
+  makeCoupling(ui->inControlOpacity, m_Model->GetMovingControlOpacityModel());
+  makeCoupling(ui->inControlIndex, m_Model->GetMovingControlIndexModel());
+
+  // Connect radio button groups to corresponding enums
+  makeRadioGroupCoupling(ui->grpRadioCont,
+                         m_Model->GetMovingControlContinuityModel());
+
+  makeRadioGroupCoupling(ui->grpRadioSide,
+                         m_Model->GetMovingControlSideModel());
+
+  // Set up activations
+  activateOnFlag(this, m_Model,
+                 ColorMapModel::UIF_LAYER_ACTIVE);
+
+  activateOnFlag(ui->inControlX, m_Model,
+                 ColorMapModel::UIF_CONTROL_SELECTED_IS_NOT_ENDPOINT);
+  activateOnFlag(ui->inControlIndex, m_Model,
+                 ColorMapModel::UIF_CONTROL_SELECTED);
+  activateOnFlag(ui->btnControlColor, m_Model,
+                 ColorMapModel::UIF_CONTROL_SELECTED);
+  activateOnFlag(ui->btnDeleteControl, m_Model,
+                 ColorMapModel::UIF_CONTROL_SELECTED_IS_NOT_ENDPOINT);
+  activateOnFlag(ui->inControlOpacity, m_Model,
+                 ColorMapModel::UIF_CONTROL_SELECTED);
+  activateOnFlag(ui->btnCont, m_Model,
+                 ColorMapModel::UIF_CONTROL_SELECTED_IS_NOT_ENDPOINT);
+  activateOnFlag(ui->btnDiscont, m_Model,
+                 ColorMapModel::UIF_CONTROL_SELECTED_IS_NOT_ENDPOINT);
+  activateOnFlag(ui->btnLeft, m_Model,
+                 ColorMapModel::UIF_CONTROL_SELECTED_IS_DISCONTINUOUS);
+  activateOnFlag(ui->btnRight, m_Model,
+                 ColorMapModel::UIF_CONTROL_SELECTED_IS_DISCONTINUOUS);
+  activateOnNotFlag(ui->btnAddPreset, m_Model,
+                    ColorMapModel::UIF_PRESET_SELECTED);
+  activateOnFlag(ui->btnDelPreset, m_Model,
+                 ColorMapModel::UIF_USER_PRESET_SELECTED);
+
+  // Populate the presets
+  PopulatePresets();
+}
+
+void ColorMapInspector::onModelUpdate(const EventBucket &b)
+{
+  // Get the model to update itself
+  m_Model->Update();
+
+  if(b.HasEvent(ColorMapModel::PresetUpdateEvent()))
+    {
+    this->PopulatePresets();
+    }
+  if(b.HasEvent(ModelUpdateEvent()))
+    {
+    // We don't have a coupling for the color button, so we assign the
+    // color to it directly
+    Vector3ui rgb = to_unsigned_int(m_Model->GetSelectedColor() * 255.0);
+    ui->btnControlColor->setIcon(CreateColorBoxIcon(25,25,rgb));
+    }
+
+  // Also we don't have a coupling for the current preset, so we will
+  // update it too
+  if(m_Model->GetLayer())
+    {
+    m_PresetsUpdating = true;
+    std::string sel = m_Model->GetSelectedPreset();
+    int index = ui->inPreset->findText(sel.c_str());
+    ui->inPreset->setCurrentIndex(index);
+    m_PresetsUpdating = false;
+    }
+}
+
+void ColorMapInspector::PromptUserForColor()
+{
+  Vector3d clr = m_Model->GetSelectedColor();
+  QColor qc; qc.setRgbF(clr(0), clr(1), clr(2));
+  QColor color = QColorDialog::getColor(qc, this);
+  m_Model->SetSelectedColor(Vector3d(color.redF(), color.greenF(), color.blueF()));
+}
+
+void ColorMapInspector::on_btnControlColor_clicked()
+{
+  this->PromptUserForColor();
+}
+
+// TODO: this should be done using a combo box coupling!
+void ColorMapInspector::PopulatePresets()
+{
+  // Add the presets to the list
+  m_PresetsUpdating = true;
+
+  // Populte the combo box (for now, we don't have a coupling for this)
+  PopulateColorMapPresetCombo(ui->inPreset, m_Model);
+
+  // Done updating
+  m_PresetsUpdating = false;
+}
+
+void ColorMapInspector::on_inPreset_currentIndexChanged(int index)
+{
+  // Set the preset
+  if(!m_PresetsUpdating)
+    m_Model->SelectPreset(to_utf8(ui->inPreset->itemText(index)));
+}
+
+void ColorMapInspector::on_btnAddPreset_clicked()
+{
+  // Prompt the user for input
+  bool ok;
+  QString input = QInputDialog::getText(
+        this, tr("Preset Name"),
+        tr("Enter the name for the new preset:"),
+        QLineEdit::Normal, "", &ok);
+
+  if(ok && !input.isEmpty())
+    {
+    m_Model->SaveAsPreset(to_utf8(input));
+    }
+}
+
+void ColorMapInspector::on_btnDelPreset_clicked()
+{
+  int sel = ui->inPreset->currentIndex();
+  QString seltext = ui->inPreset->itemText(sel);
+  m_Model->DeletePreset(to_utf8(seltext));
+}
+
+
+void ColorMapInspector::on_btnDeleteControl_clicked()
+{
+  m_Model->DeleteSelectedControl();
+}
diff --git a/GUI/Qt/Components/ColorMapInspector.h b/GUI/Qt/Components/ColorMapInspector.h
new file mode 100644
index 0000000..4f5dfab
--- /dev/null
+++ b/GUI/Qt/Components/ColorMapInspector.h
@@ -0,0 +1,61 @@
+#ifndef COLORMAPINSPECTOR_H
+#define COLORMAPINSPECTOR_H
+
+#include "SNAPCommon.h"
+#include "SNAPComponent.h"
+#include <map>
+
+class QtViewportReporter;
+class ColorMapModel;
+
+namespace Ui {
+    class ColorMapInspector;
+}
+
+class ColorMapInspector : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit ColorMapInspector(QWidget *parent = 0);
+  ~ColorMapInspector();
+
+  void SetModel(ColorMapModel *model);
+
+  void PromptUserForColor();
+
+private slots:
+
+  // Slot for model updates
+  void onModelUpdate(const EventBucket &b);
+
+  void on_btnControlColor_clicked();
+
+  void on_inPreset_currentIndexChanged(int index);
+
+  void on_btnAddPreset_clicked();
+
+  void on_btnDelPreset_clicked();
+
+  void on_btnDeleteControl_clicked();
+
+private:
+
+  void PopulatePresets();
+
+  Ui::ColorMapInspector *ui;
+
+  // Model object
+  ColorMapModel *m_Model;
+
+  // Viewport reporter for the curve box
+  SmartPtr<QtViewportReporter> m_ColorMapBoxViewportReporter;
+
+  // Icons for the different presets
+  std::map<std::string, QIcon> m_PresetMap;
+
+  // Whether an update is being done to the presets
+  bool m_PresetsUpdating;
+};
+
+#endif // COLORMAPINSPECTOR_H
diff --git a/GUI/Qt/Components/ColorMapInspector.ui b/GUI/Qt/Components/ColorMapInspector.ui
new file mode 100644
index 0000000..43e55ee
--- /dev/null
+++ b/GUI/Qt/Components/ColorMapInspector.ui
@@ -0,0 +1,602 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ColorMapInspector</class>
+ <widget class="QWidget" name="ColorMapInspector">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>485</width>
+    <height>535</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QGroupBox {
+  background-origin: content;
+  margin-top: 15px;
+  font-weight: bold;
+  font-size: 12px;
+  font-family: helvetica;
+  color: rgb(30,30,160);
+  background-color: rgb(237,237,237);
+  padding: 5px;
+  border-radius: 4px;
+  border: 1px solid rgb(130,130,130);
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>12</number>
+   </property>
+   <property name="leftMargin">
+    <number>6</number>
+   </property>
+   <property name="topMargin">
+    <number>18</number>
+   </property>
+   <property name="rightMargin">
+    <number>6</number>
+   </property>
+   <property name="bottomMargin">
+    <number>6</number>
+   </property>
+   <item>
+    <widget class="QGroupBox" name="groupBox">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>40</height>
+      </size>
+     </property>
+     <property name="title">
+      <string>Presets:</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <property name="horizontalSpacing">
+       <number>6</number>
+      </property>
+      <property name="verticalSpacing">
+       <number>2</number>
+      </property>
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item row="0" column="0">
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Select a colormap: </string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QComboBox" name="inPreset">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>0</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="currentIndex">
+         <number>-1</number>
+        </property>
+        <property name="maxVisibleItems">
+         <number>16</number>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="2">
+       <widget class="QToolButton" name="btnAddPreset">
+        <property name="toolTip">
+         <string>Save the current color map as a new preset</string>
+        </property>
+        <property name="text">
+         <string>+</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="3">
+       <widget class="QToolButton" name="btnDelPreset">
+        <property name="toolTip">
+         <string>Delete the selected preset</string>
+        </property>
+        <property name="text">
+         <string>-</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <spacer name="horizontalSpacer_3">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>8</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Color Map Editor:</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item>
+       <widget class="ColorMapBox" name="boxColorMap" native="true">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>0</width>
+          <height>80</height>
+         </size>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="verticalSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>16</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QGroupBox" name="groupBox_4">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="styleSheet">
+         <string notr="true">QGroupBox {
+  background-origin: content;
+  margin-top: 15px;
+  font-weight: normal;
+  font-size: 12px;
+  font-family: helvetica;
+  color: black;
+  background-color: rgb(237,237,237);
+  padding: 5px;
+  border-radius: 0px;
+  border-top: 1px solid rgb(130,130,130);
+  border-left: none;
+  border-right:none;
+  border-bottom:none;
+}</string>
+        </property>
+        <property name="title">
+         <string>Selected Control Point Properties:</string>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout_4">
+         <property name="spacing">
+          <number>12</number>
+         </property>
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QWidget" name="grpControl" native="true">
+           <layout class="QGridLayout" name="gridLayout_2">
+            <item row="2" column="4">
+             <widget class="QLabel" name="label_6">
+              <property name="text">
+               <string>Side:</string>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+              </property>
+             </widget>
+            </item>
+            <item row="2" column="5">
+             <widget class="QWidget" name="grpRadioSide" native="true">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimumSize">
+               <size>
+                <width>0</width>
+                <height>0</height>
+               </size>
+              </property>
+              <layout class="QHBoxLayout" name="horizontalLayout_2">
+               <property name="spacing">
+                <number>12</number>
+               </property>
+               <property name="margin">
+                <number>0</number>
+               </property>
+               <item>
+                <widget class="QRadioButton" name="btnLeft">
+                 <property name="minimumSize">
+                  <size>
+                   <width>0</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="text">
+                  <string>Left</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QRadioButton" name="btnRight">
+                 <property name="minimumSize">
+                  <size>
+                   <width>0</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="text">
+                  <string>Right</string>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </widget>
+            </item>
+            <item row="0" column="5" rowspan="2">
+             <widget class="QWidget" name="grpRadioCont" native="true">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <layout class="QVBoxLayout" name="verticalLayout_3">
+               <property name="margin">
+                <number>0</number>
+               </property>
+               <item>
+                <widget class="QRadioButton" name="btnCont">
+                 <property name="minimumSize">
+                  <size>
+                   <width>100</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="text">
+                  <string>Continuous</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QRadioButton" name="btnDiscont">
+                 <property name="minimumSize">
+                  <size>
+                   <width>120</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="text">
+                  <string>Discontinuous</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <spacer name="verticalSpacer_3">
+                 <property name="orientation">
+                  <enum>Qt::Vertical</enum>
+                 </property>
+                 <property name="sizeHint" stdset="0">
+                  <size>
+                   <width>20</width>
+                   <height>40</height>
+                  </size>
+                 </property>
+                </spacer>
+               </item>
+              </layout>
+             </widget>
+            </item>
+            <item row="0" column="4">
+             <widget class="QLabel" name="label_5">
+              <property name="text">
+               <string>Style:</string>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+              </property>
+             </widget>
+            </item>
+            <item row="0" column="1">
+             <widget class="QSpinBox" name="inControlIndex">
+              <property name="keyboardTracking">
+               <bool>false</bool>
+              </property>
+              <property name="maximum">
+               <number>9</number>
+              </property>
+             </widget>
+            </item>
+            <item row="0" column="0">
+             <widget class="QLabel" name="label_9">
+              <property name="text">
+               <string>Index:</string>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="0">
+             <widget class="QLabel" name="label_4">
+              <property name="text">
+               <string>Position:</string>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+              </property>
+             </widget>
+            </item>
+            <item row="2" column="1" colspan="2">
+             <widget class="QDoubleSpinBox" name="inControlOpacity">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimumSize">
+               <size>
+                <width>96</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>9999</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:13px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11px;">The x-coordinate of the selected control point. The x-coordinate represents input image intensity.</span></p></body></html></string>
+              </property>
+              <property name="buttonSymbols">
+               <enum>QAbstractSpinBox::NoButtons</enum>
+              </property>
+              <property name="keyboardTracking">
+               <bool>false</bool>
+              </property>
+              <property name="decimals">
+               <number>0</number>
+              </property>
+             </widget>
+            </item>
+            <item row="2" column="0">
+             <widget class="QLabel" name="label_8">
+              <property name="text">
+               <string>Opacity:</string>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+              </property>
+             </widget>
+            </item>
+            <item row="5" column="0">
+             <widget class="QLabel" name="label_7">
+              <property name="text">
+               <string>Color:</string>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+              </property>
+             </widget>
+            </item>
+            <item row="5" column="1" colspan="2">
+             <widget class="QToolButton" name="btnControlColor">
+              <property name="minimumSize">
+               <size>
+                <width>96</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="text">
+               <string>Choose...</string>
+              </property>
+              <property name="toolButtonStyle">
+               <enum>Qt::ToolButtonTextBesideIcon</enum>
+              </property>
+             </widget>
+            </item>
+            <item row="5" column="5">
+             <widget class="QWidget" name="widget" native="true">
+              <layout class="QHBoxLayout" name="horizontalLayout_3">
+               <property name="spacing">
+                <number>0</number>
+               </property>
+               <property name="margin">
+                <number>0</number>
+               </property>
+              </layout>
+             </widget>
+            </item>
+            <item row="2" column="3">
+             <spacer name="horizontalSpacer_4">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeType">
+               <enum>QSizePolicy::Fixed</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item row="0" column="2">
+             <widget class="QToolButton" name="btnDeleteControl">
+              <property name="maximumSize">
+               <size>
+                <width>24</width>
+                <height>24</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:11px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Delete the selected control point</p></body></html></string>
+              </property>
+              <property name="text">
+               <string>Delete</string>
+              </property>
+              <property name="icon">
+               <iconset>
+                <normalon>:/root/popup_delete_16.png</normalon>
+               </iconset>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="1" colspan="2">
+             <widget class="QDoubleSpinBox" name="inControlX">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimumSize">
+               <size>
+                <width>96</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>9999</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:13px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11px;">The x-coordinate of the selected control point. The x-coordinate represents input image intensity.</span></p></body></html></string>
+              </property>
+              <property name="buttonSymbols">
+               <enum>QAbstractSpinBox::NoButtons</enum>
+              </property>
+              <property name="keyboardTracking">
+               <bool>false</bool>
+              </property>
+              <property name="decimals">
+               <number>0</number>
+              </property>
+             </widget>
+            </item>
+            <item row="2" column="6">
+             <spacer name="horizontalSpacer_5">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeType">
+               <enum>QSizePolicy::Expanding</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>2</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <spacer name="verticalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>2</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>ColorMapBox</class>
+   <extends>QWidget</extends>
+   <header>ColorMapBox.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/ContrastInspector.cxx b/GUI/Qt/Components/ContrastInspector.cxx
new file mode 100644
index 0000000..ce39c9b
--- /dev/null
+++ b/GUI/Qt/Components/ContrastInspector.cxx
@@ -0,0 +1,103 @@
+#include "ContrastInspector.h"
+#include "ui_ContrastInspector.h"
+#include "QtStyles.h"
+#include "IntensityCurveModel.h"
+#include "QtCheckBoxCoupling.h"
+#include "QtSpinBoxCoupling.h"
+#include "QtDoubleSpinBoxCoupling.h"
+#include "QtWidgetArrayCoupling.h"
+#include "QtReporterDelegates.h"
+#include "QtWidgetActivator.h"
+#include "IntensityCurveVTKRenderer.h"
+
+#include <QPalette>
+
+ContrastInspector::ContrastInspector(QWidget *parent) :
+    SNAPComponent(parent),
+    ui(new Ui::ContrastInspector)
+{
+  ui->setupUi(this);
+  ApplyCSS(this, ":/root/itksnap.css");
+
+  // Create the viewport reporter
+  m_CurveBoxViewportReporter = QtViewportReporter::New();
+  m_CurveBoxViewportReporter->SetClientWidget(ui->plotWidget);
+
+  // Set up the renderer
+  m_CurveRenderer = IntensityCurveVTKRenderer::New();
+  ui->plotWidget->SetRenderer(m_CurveRenderer);
+  m_CurveRenderer->SetBackgroundColor(Vector3d(1.0, 1.0, 1.0));
+}
+
+ContrastInspector::~ContrastInspector()
+{
+  delete ui;
+}
+
+void ContrastInspector::SetModel(IntensityCurveModel *model)
+{
+  // Set the model
+  m_Model = model;
+
+  // Set the model on the renderer
+  m_CurveRenderer->SetModel(model);
+
+  // Connect the viewport reporter to the model
+  model->SetViewportReporter(m_CurveBoxViewportReporter);
+
+  // Listen to model update events
+  connectITK(m_Model, ModelUpdateEvent());
+
+  // Set up the couplings. This is all we have to do to make the spin box
+  // play with the model! There are no callbacks to write, no event handlers
+  // to worry about! Yay!!!
+  makeArrayCoupling(ui->inControlX, ui->inControlY,
+                    m_Model->GetMovingControlXYModel());
+
+  // Set up couplings for window and level
+  makeCoupling(ui->inMin, m_Model->GetIntensityRangeModel(IntensityCurveModel::MINIMUM));
+  makeCoupling(ui->inMax, m_Model->GetIntensityRangeModel(IntensityCurveModel::MAXIMUM));
+  makeCoupling(ui->inLevel, m_Model->GetIntensityRangeModel(IntensityCurveModel::LEVEL));
+  makeCoupling(ui->inWindow, m_Model->GetIntensityRangeModel(IntensityCurveModel::WINDOW));
+
+  // Make coupling for the control point id
+  makeCoupling(ui->inControlId, m_Model->GetMovingControlIdModel());
+
+  // Histogram bin controls
+  makeCoupling(ui->inBinSize, m_Model->GetHistogramBinSizeModel());
+  makeCoupling(ui->inCutoff, m_Model->GetHistogramCutoffModel());
+  makeCoupling(ui->inLogScale, m_Model->GetHistogramScaleModel());
+
+  // Couple visibility of the GL widget to the model having a layer
+  makeWidgetVisibilityCoupling(ui->plotWidget, m_Model->GetHasLayerModel());
+
+  // Handle activations
+  activateOnFlag(this, m_Model,
+                 IntensityCurveModel::UIF_LAYER_ACTIVE);
+}
+
+void ContrastInspector::on_btnRemoveControl_clicked()
+{
+  m_Model->OnControlPointNumberDecreaseAction();
+}
+
+void ContrastInspector::on_btnAddControl_clicked()
+{
+  m_Model->OnControlPointNumberIncreaseAction();
+}
+
+void ContrastInspector::on_btnReset_clicked()
+{
+  m_Model->OnResetCurveAction();
+}
+
+void ContrastInspector::onModelUpdate(const EventBucket &b)
+{
+  m_Model->Update();
+}
+
+
+void ContrastInspector::on_btnAuto_clicked()
+{
+  m_Model->OnAutoFitWindow();
+}
diff --git a/GUI/Qt/Components/ContrastInspector.h b/GUI/Qt/Components/ContrastInspector.h
new file mode 100644
index 0000000..011164e
--- /dev/null
+++ b/GUI/Qt/Components/ContrastInspector.h
@@ -0,0 +1,51 @@
+#ifndef CONTRASTINSPECTOR_H
+#define CONTRASTINSPECTOR_H
+
+#include "SNAPComponent.h"
+#include "SNAPCommon.h"
+
+class IntensityCurveModel;
+class QtViewportReporter;
+class IntensityCurveVTKRenderer;
+
+namespace Ui {
+  class ContrastInspector;
+}
+
+class ContrastInspector : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit ContrastInspector(QWidget *parent = 0);
+  ~ContrastInspector();
+
+  void SetModel(IntensityCurveModel *model);
+
+
+private slots:
+  void on_btnRemoveControl_clicked();
+
+  void on_btnAddControl_clicked();
+
+  void on_btnReset_clicked();
+
+  // Slot for model updates
+  void onModelUpdate(const EventBucket &b);
+
+
+  void on_btnAuto_clicked();
+
+private:
+
+  IntensityCurveModel *m_Model;
+
+  Ui::ContrastInspector *ui;
+
+  // Viewport reporter for the curve box
+  SmartPtr<QtViewportReporter> m_CurveBoxViewportReporter;
+
+  SmartPtr<IntensityCurveVTKRenderer> m_CurveRenderer;
+};
+
+#endif // CONTRASTINSPECTOR_H
diff --git a/GUI/Qt/Components/ContrastInspector.ui b/GUI/Qt/Components/ContrastInspector.ui
new file mode 100644
index 0000000..81d576b
--- /dev/null
+++ b/GUI/Qt/Components/ContrastInspector.ui
@@ -0,0 +1,721 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ContrastInspector</class>
+ <widget class="QWidget" name="ContrastInspector">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>454</width>
+    <height>477</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QMainWindow {
+  background-color: rgb(248,248,248);
+}
+
+QGroupBox {
+  background-origin: content;
+  margin-top: 15px;
+  font-weight: bold;
+  font-size: 12px;
+  font-family: helvetica;
+  color: rgb(30,30,160);
+  background-color: rgb(237,237,237);
+  padding: 5px;
+  border-radius: 4px;
+  border: 1px solid rgb(130,130,130);
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+}
+
+</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>12</number>
+   </property>
+   <property name="leftMargin">
+    <number>6</number>
+   </property>
+   <property name="topMargin">
+    <number>18</number>
+   </property>
+   <property name="rightMargin">
+    <number>6</number>
+   </property>
+   <property name="bottomMargin">
+    <number>6</number>
+   </property>
+   <item>
+    <widget class="QGroupBox" name="grpWindow">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="title">
+      <string>Linear Contrast Adjustment:</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_4">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QWidget" name="widget_8" native="true">
+        <layout class="QGridLayout" name="gridLayout_2">
+         <property name="horizontalSpacing">
+          <number>12</number>
+         </property>
+         <property name="verticalSpacing">
+          <number>6</number>
+         </property>
+         <property name="margin">
+          <number>6</number>
+         </property>
+         <item row="1" column="3">
+          <widget class="QLabel" name="label_2">
+           <property name="text">
+            <string>Window:</string>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="4">
+          <widget class="QDoubleSpinBox" name="inWindow">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>64</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>80</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="keyboardTracking">
+            <bool>false</bool>
+           </property>
+           <property name="decimals">
+            <number>0</number>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="6">
+          <widget class="QToolButton" name="btnAuto">
+           <property name="minimumSize">
+            <size>
+             <width>60</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Auto</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="0">
+          <widget class="QLabel" name="label_8">
+           <property name="text">
+            <string>Minimum:</string>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="6">
+          <widget class="QToolButton" name="btnReset">
+           <property name="minimumSize">
+            <size>
+             <width>60</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Reset</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QDoubleSpinBox" name="inMin">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>64</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>80</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="focusPolicy">
+            <enum>Qt::WheelFocus</enum>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="keyboardTracking">
+            <bool>false</bool>
+           </property>
+           <property name="decimals">
+            <number>0</number>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="5">
+          <spacer name="horizontalSpacer">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item row="0" column="4">
+          <widget class="QDoubleSpinBox" name="inLevel">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>64</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>80</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="focusPolicy">
+            <enum>Qt::WheelFocus</enum>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="keyboardTracking">
+            <bool>false</bool>
+           </property>
+           <property name="decimals">
+            <number>0</number>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QLabel" name="label_10">
+           <property name="text">
+            <string>Maximum:</string>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QDoubleSpinBox" name="inMax">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>64</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>80</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="focusPolicy">
+            <enum>Qt::WheelFocus</enum>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="keyboardTracking">
+            <bool>false</bool>
+           </property>
+           <property name="decimals">
+            <number>0</number>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="3">
+          <widget class="QLabel" name="label">
+           <property name="text">
+            <string>Level:</string>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="2">
+          <spacer name="horizontalSpacer_2">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeType">
+            <enum>QSizePolicy::Fixed</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>5</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="grpCurve">
+     <property name="title">
+      <string>Curve-Based Contrast Adjustment:</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>10</number>
+      </property>
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item>
+       <widget class="QFrame" name="frame">
+        <property name="minimumSize">
+         <size>
+          <width>0</width>
+          <height>202</height>
+         </size>
+        </property>
+        <property name="frameShape">
+         <enum>QFrame::StyledPanel</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Raised</enum>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_3">
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QtVTKRenderWindowBox" name="plotWidget" native="true">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="styleSheet">
+            <string notr="true">background-color:white;</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget" native="true">
+        <layout class="QGridLayout" name="gridLayout">
+         <property name="horizontalSpacing">
+          <number>10</number>
+         </property>
+         <property name="verticalSpacing">
+          <number>4</number>
+         </property>
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item row="1" column="1">
+          <widget class="QWidget" name="widget_2" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout_3">
+            <property name="spacing">
+             <number>2</number>
+            </property>
+            <property name="margin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QLabel" name="label_6">
+              <property name="text">
+               <string>x:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QDoubleSpinBox" name="inControlX">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimumSize">
+               <size>
+                <width>80</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>80</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:13px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11px;">The x-coordinate of the selected control point. The x-coordinate represents input image intensity.</span></p></body></html></string>
+              </property>
+              <property name="buttonSymbols">
+               <enum>QAbstractSpinBox::NoButtons</enum>
+              </property>
+              <property name="keyboardTracking">
+               <bool>false</bool>
+              </property>
+              <property name="decimals">
+               <number>0</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item row="1" column="2">
+          <widget class="QWidget" name="widget_3" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout_4">
+            <property name="spacing">
+             <number>2</number>
+            </property>
+            <property name="margin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QLabel" name="label_7">
+              <property name="text">
+               <string>y:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QDoubleSpinBox" name="inControlY">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimumSize">
+               <size>
+                <width>80</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>80</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:13px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11px;">The y-coordinate of the selected control point. The y-coordinate represents the index into the color map used to display the image. Its values are in the range [0 1].</span></p></body></html></string>
+              </property>
+              <property name="buttonSymbols">
+               <enum>QAbstractSpinBox::NoButtons</enum>
+              </property>
+              <property name="keyboardTracking">
+               <bool>false</bool>
+              </property>
+              <property name="decimals">
+               <number>0</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item row="0" column="0" colspan="4">
+          <widget class="QWidget" name="widget_4" native="true">
+           <property name="minimumSize">
+            <size>
+             <width>20</width>
+             <height>0</height>
+            </size>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_5">
+            <property name="spacing">
+             <number>2</number>
+            </property>
+            <property name="margin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QLabel" name="label_5">
+              <property name="text">
+               <string>Selected control point:</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QWidget" name="widget_6" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout_8">
+            <property name="spacing">
+             <number>2</number>
+            </property>
+            <property name="margin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QLabel" name="label_9">
+              <property name="text">
+               <string>Id:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QSpinBox" name="inControlId">
+              <property name="maximumSize">
+               <size>
+                <width>48</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="keyboardTracking">
+               <bool>false</bool>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item row="1" column="5">
+          <widget class="QWidget" name="widget_7" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout_9">
+            <property name="spacing">
+             <number>4</number>
+            </property>
+            <property name="margin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QToolButton" name="btnAddControl">
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:12px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the number of control points on the curve</p></body></html></string>
+              </property>
+              <property name="text">
+               <string>+</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnRemoveControl">
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:12px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Reduce the number of control points on the curve</p></body></html></string>
+              </property>
+              <property name="text">
+               <string>-</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item row="1" column="3">
+          <spacer name="horizontalSpacer_3">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>10</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="grpHistogram">
+     <property name="title">
+      <string>Histogram Display Options:</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="spacing">
+       <number>2</number>
+      </property>
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Bin size:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QSpinBox" name="inBinSize">
+        <property name="keyboardTracking">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_4">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>5</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QLabel" name="label_4">
+        <property name="text">
+         <string>Cutoff:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QDoubleSpinBox" name="inCutoff">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>1</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="suffix">
+         <string> %</string>
+        </property>
+        <property name="decimals">
+         <number>0</number>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_5">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>5</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="inLogScale">
+        <property name="text">
+         <string>Log scale</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QtVTKRenderWindowBox</class>
+   <extends>QWidget</extends>
+   <header location="global">QtVTKRenderWindowBox.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>inMin</tabstop>
+  <tabstop>inMax</tabstop>
+  <tabstop>inLevel</tabstop>
+  <tabstop>inWindow</tabstop>
+  <tabstop>btnReset</tabstop>
+  <tabstop>btnAuto</tabstop>
+  <tabstop>inControlId</tabstop>
+  <tabstop>inControlX</tabstop>
+  <tabstop>inControlY</tabstop>
+  <tabstop>btnAddControl</tabstop>
+  <tabstop>btnRemoveControl</tabstop>
+  <tabstop>inBinSize</tabstop>
+  <tabstop>inCutoff</tabstop>
+  <tabstop>inLogScale</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/CursorInspector.cxx b/GUI/Qt/Components/CursorInspector.cxx
new file mode 100644
index 0000000..35a1a78
--- /dev/null
+++ b/GUI/Qt/Components/CursorInspector.cxx
@@ -0,0 +1,163 @@
+#ifdef WIN32
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif //_WIN32_WINNT
+#define _WIN32_WINNT	0x0501
+#endif //WIN32
+
+#include "CursorInspector.h"
+#include "ui_CursorInspector.h"
+#include <VoxelIntensityQTableModel.h>
+#include <QSpinBox>
+#include <GenericImageData.h>
+#include <IRISApplication.h>
+#include <CursorInspectionModel.h>
+#include <GlobalUIModel.h>
+#include <QtWidgetActivator.h>
+#include <QMenu>
+#include <IntensityCurveModel.h>
+#include <LayerSelectionModel.h>
+#include "SNAPQtCommon.h"
+
+#include <QtSpinBoxCoupling.h>
+#include <QtCheckBoxCoupling.h>
+#include <QtLineEditCoupling.h>
+#include <QtTableWidgetCoupling.h>
+#include <QtWidgetArrayCoupling.h>
+
+/**
+  This class provide the coupling properties for coupling the table of
+  voxel intensities to QTableWidget
+  */
+class LayerCurrentVoxelInfoRowDescriptionTraits
+{
+public:
+  typedef CurrentVoxelInfoItemSetDomain::ValueType ValueType;
+
+  static QString GetText(ValueType value,
+                         const LayerCurrentVoxelInfo &desc, int col)
+  {
+    if(col == 0)
+      return from_utf8(desc.LayerName);
+    else
+      return from_utf8(desc.IntensityValue);
+  }
+
+  static QIcon GetIcon(ValueType value,
+                       const LayerCurrentVoxelInfo &desc, int col)
+  {
+    return (col == 0)
+        ? QIcon()
+        : CreateColorBoxIcon(16, 16, desc.Color);
+  }
+
+  static QVariant GetIconSignature(ValueType value,
+                                   const LayerCurrentVoxelInfo &desc, int col)
+  {
+    // Get the RGB color
+    return (col == 0)
+        ? QVariant(0)
+        : QVariant(QColor(desc.Color[0], desc.Color[1], desc.Color[2]));
+  }
+};
+
+typedef TextAndIconTableWidgetRowTraits<
+  size_t, LayerCurrentVoxelInfo,
+  LayerCurrentVoxelInfoRowDescriptionTraits> LayerCurrentVoxelInfoTableWidgetRowTraits;
+
+/*
+typedef ItemSetWidgetDomainTraits<
+  CurrentVoxelInfoItemSetDomain,
+  QTableWidget,
+  LayerCurrentVoxelInfoTableWidgetRowTraits> LayerCurrentVoxelInfoDomainTraits;
+*/
+
+
+
+
+
+
+CursorInspector::CursorInspector(QWidget *parent) :
+    SNAPComponent(parent),
+    ui(new Ui::CursorInspector)
+{
+  ui->setupUi(this);
+
+  ui->tableVoxelUnderCursor->setAlternatingRowColors(true);
+  ui->tableVoxelUnderCursor->setFixedWidth(160);
+  ui->tableVoxelUnderCursor->setFixedHeight(120);
+  ui->tableVoxelUnderCursor->setContextMenuPolicy(Qt::CustomContextMenu);
+
+  m_ContextMenu = new QMenu(ui->tableVoxelUnderCursor);
+  m_ContextMenu->addAction(ui->actionAutoContrast);
+
+  // Hook up the context menu
+  connect(ui->tableVoxelUnderCursor, SIGNAL(customContextMenuRequested(QPoint)),
+          SLOT(onContextMenuRequested(QPoint)));
+
+}
+
+CursorInspector::~CursorInspector()
+{
+  delete ui;
+}
+
+void CursorInspector::SetModel(CursorInspectionModel *model)
+{
+  m_Model = model;
+
+  // Activators
+  activateOnFlag(this, m_Model->GetParent(), UIF_BASEIMG_LOADED);
+
+  // Couple to the model
+  makeCoupling(ui->outLabelId, m_Model->GetLabelUnderTheCursorIdModel());
+  makeCoupling(ui->outLabelText, m_Model->GetLabelUnderTheCursorTitleModel());
+
+  makeArrayCoupling(ui->inCursorX, ui->inCursorY, ui->inCursorZ,
+                    m_Model->GetCursorPositionModel());
+
+  makeMultiRowCoupling(ui->tableVoxelUnderCursor,
+                       m_Model->GetVoxelAtCursorModel(),
+                       LayerCurrentVoxelInfoTableWidgetRowTraits());
+}
+
+#include "MainImageWindow.h"
+#include "LayerInspectorDialog.h"
+
+void CursorInspector::onContextMenuRequested(QPoint pos)
+{
+  m_PopupRow = ui->tableVoxelUnderCursor->rowAt(pos.y());
+  if(m_PopupRow >= 0)
+    {
+    // Instead of creating a separate context menu here, we use a context menu
+    // from the corresponding row in the LayerInspector.
+    MainImageWindow *winmain = findParentWidget<MainImageWindow>(this);
+    LayerInspectorDialog *inspector = winmain->GetLayerInspector();
+
+    // Find the corresponding layer
+    LayerIterator it =
+        m_Model->GetParent()->GetLoadedLayersSelectionModel()->GetNthLayer(m_PopupRow);
+
+    // Get the menu
+    QMenu *menu = inspector->GetLayerContextMenu(it.GetLayer());
+
+    // Show the menu
+    if(menu)
+      menu->popup(QCursor::pos());
+    }
+}
+
+void CursorInspector::on_actionAutoContrast_triggered()
+{
+  LayerIterator it =
+      m_Model->GetParent()->GetLoadedLayersSelectionModel()->GetNthLayer(m_PopupRow);
+
+  if(it.GetLayer()->GetDisplayMapping()->GetIntensityCurve())
+    {
+    // Select the currently highlighted layer
+    m_Model->GetParent()->GetIntensityCurveModel()->SetLayer(it.GetLayer());
+
+    // Auto-adjust intensity in the selected layer
+    m_Model->GetParent()->GetIntensityCurveModel()->OnAutoFitWindow();
+    }
+}
diff --git a/GUI/Qt/Components/CursorInspector.h b/GUI/Qt/Components/CursorInspector.h
new file mode 100644
index 0000000..09b6dfa
--- /dev/null
+++ b/GUI/Qt/Components/CursorInspector.h
@@ -0,0 +1,47 @@
+#ifndef CURSORINSPECTOR_H
+#define CURSORINSPECTOR_H
+
+#include "SNAPComponent.h"
+
+
+class QMenu;
+class CursorInspectionModel;
+class QtScriptTest1;
+
+namespace Ui {
+    class CursorInspector;
+}
+
+class CursorInspector : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit CursorInspector(QWidget *parent = 0);
+
+  void SetModel(CursorInspectionModel *);
+
+  ~CursorInspector();
+
+public slots:
+
+  void onContextMenuRequested(QPoint pos);
+
+protected:
+
+
+private slots:
+  void on_actionAutoContrast_triggered();
+
+private:
+  Ui::CursorInspector *ui;
+  friend class QtScriptTest1;
+
+
+  CursorInspectionModel *m_Model;
+  QMenu *m_ContextMenu;
+
+  int m_PopupRow;
+};
+
+#endif // CURSORINSPECTOR_H
diff --git a/GUI/Qt/Components/CursorInspector.ui b/GUI/Qt/Components/CursorInspector.ui
new file mode 100644
index 0000000..612f1dd
--- /dev/null
+++ b/GUI/Qt/Components/CursorInspector.ui
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CursorInspector</class>
+ <widget class="QWidget" name="CursorInspector">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>179</width>
+    <height>527</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">* {
+font-size: 12px;
+}
+
+QSpinBox {
+font-size: 11px;
+}
+</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">font-weight:bold;</string>
+     </property>
+     <property name="text">
+      <string>Cursor position</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <property name="horizontalSpacing">
+      <number>6</number>
+     </property>
+     <property name="verticalSpacing">
+      <number>4</number>
+     </property>
+     <item row="1" column="0">
+      <widget class="QSpinBox" name="inCursorX">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+         <horstretch>1</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>64</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="buttonSymbols">
+        <enum>QAbstractSpinBox::NoButtons</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QSpinBox" name="inCursorY">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+         <horstretch>1</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>0</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>64</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="buttonSymbols">
+        <enum>QAbstractSpinBox::NoButtons</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="2">
+      <widget class="QSpinBox" name="inCursorZ">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+         <horstretch>1</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>64</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="buttonSymbols">
+        <enum>QAbstractSpinBox::NoButtons</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="0">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>x:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>y:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="label_4">
+       <property name="text">
+        <string>z:</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line">
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_5">
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">font-weight:bold;</string>
+     </property>
+     <property name="text">
+      <string>Intensity under cursor</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTableWidget" name="tableVoxelUnderCursor">
+     <property name="minimumSize">
+      <size>
+       <width>162</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>185</width>
+       <height>120</height>
+      </size>
+     </property>
+     <property name="contextMenuPolicy">
+      <enum>Qt::CustomContextMenu</enum>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">font-size:10px;</string>
+     </property>
+     <property name="editTriggers">
+      <set>QAbstractItemView::NoEditTriggers</set>
+     </property>
+     <property name="tabKeyNavigation">
+      <bool>false</bool>
+     </property>
+     <property name="selectionMode">
+      <enum>QAbstractItemView::SingleSelection</enum>
+     </property>
+     <property name="selectionBehavior">
+      <enum>QAbstractItemView::SelectRows</enum>
+     </property>
+     <attribute name="horizontalHeaderCascadingSectionResizes">
+      <bool>false</bool>
+     </attribute>
+     <attribute name="horizontalHeaderDefaultSectionSize">
+      <number>75</number>
+     </attribute>
+     <attribute name="horizontalHeaderStretchLastSection">
+      <bool>true</bool>
+     </attribute>
+     <attribute name="verticalHeaderVisible">
+      <bool>false</bool>
+     </attribute>
+     <attribute name="verticalHeaderDefaultSectionSize">
+      <number>16</number>
+     </attribute>
+     <column>
+      <property name="text">
+       <string>Layer</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Intensity</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line_3">
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_6">
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">font-weight:bold;</string>
+     </property>
+     <property name="text">
+      <string>Label under cursor</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout_2">
+     <property name="spacing">
+      <number>6</number>
+     </property>
+     <item row="1" column="1">
+      <widget class="QLineEdit" name="outLabelText">
+       <property name="readOnly">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="0">
+      <widget class="QLabel" name="label_7">
+       <property name="maximumSize">
+        <size>
+         <width>16777215</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Id:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QSpinBox" name="outLabelId">
+       <property name="maximumSize">
+        <size>
+         <width>60</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="readOnly">
+        <bool>true</bool>
+       </property>
+       <property name="buttonSymbols">
+        <enum>QAbstractSpinBox::NoButtons</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLabel" name="label_8">
+       <property name="font">
+        <font>
+         <pointsize>-1</pointsize>
+        </font>
+       </property>
+       <property name="styleSheet">
+        <string notr="true"/>
+       </property>
+       <property name="text">
+        <string>Description:</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+  <action name="actionAutoContrast">
+   <property name="text">
+    <string>Auto-Adjust Contrast</string>
+   </property>
+   <property name="toolTip">
+    <string>Sets the contrast of a grayscale image automatically.</string>
+   </property>
+  </action>
+ </widget>
+ <tabstops>
+  <tabstop>inCursorX</tabstop>
+  <tabstop>inCursorY</tabstop>
+  <tabstop>inCursorZ</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+ <slots>
+  <slot>onCursorEdit()</slot>
+ </slots>
+</ui>
diff --git a/GUI/Qt/Components/DisplayLayoutInspector.cxx b/GUI/Qt/Components/DisplayLayoutInspector.cxx
new file mode 100644
index 0000000..7a7f117
--- /dev/null
+++ b/GUI/Qt/Components/DisplayLayoutInspector.cxx
@@ -0,0 +1,35 @@
+#include "DisplayLayoutInspector.h"
+#include "ui_DisplayLayoutInspector.h"
+#include "DisplayLayoutModel.h"
+#include <QtRadioButtonCoupling.h>
+
+DisplayLayoutInspector::DisplayLayoutInspector(QWidget *parent) :
+  QWidget(parent),
+  ui(new Ui::DisplayLayoutInspector)
+{
+  ui->setupUi(this);
+}
+
+DisplayLayoutInspector::~DisplayLayoutInspector()
+{
+  delete ui;
+}
+
+void DisplayLayoutInspector::SetModel(DisplayLayoutModel *model)
+{
+  m_Model = model;
+
+  // Couple the view panel layout toolbar buttons to the model
+  std::map<DisplayLayoutModel::ViewPanelLayout, QAbstractButton *> rmap;
+  rmap[DisplayLayoutModel::VIEW_ALL] = ui->btnFourViews;
+  rmap[DisplayLayoutModel::VIEW_AXIAL] = ui->btnAxial;
+  rmap[DisplayLayoutModel::VIEW_CORONAL] = ui->btnCoronal;
+  rmap[DisplayLayoutModel::VIEW_SAGITTAL] = ui->btnSagittal;
+  rmap[DisplayLayoutModel::VIEW_3D] = ui->btn3D;
+  makeRadioGroupCoupling(ui->grpDisplayLayout, rmap,
+                         m_Model->GetViewPanelLayoutModel());
+
+  // Couple the radio buttons for layer layout
+  makeRadioGroupCoupling(ui->grpLayerLayout,
+                         m_Model->GetSliceViewLayerLayoutModel());
+}
diff --git a/GUI/Qt/Components/DisplayLayoutInspector.h b/GUI/Qt/Components/DisplayLayoutInspector.h
new file mode 100644
index 0000000..b7aa603
--- /dev/null
+++ b/GUI/Qt/Components/DisplayLayoutInspector.h
@@ -0,0 +1,28 @@
+#ifndef DISPLAYLAYOUTINSPECTOR_H
+#define DISPLAYLAYOUTINSPECTOR_H
+
+#include <QWidget>
+
+class DisplayLayoutModel;
+
+namespace Ui {
+class DisplayLayoutInspector;
+}
+
+class DisplayLayoutInspector : public QWidget
+{
+  Q_OBJECT
+  
+public:
+  explicit DisplayLayoutInspector(QWidget *parent = 0);
+  ~DisplayLayoutInspector();
+
+  void SetModel(DisplayLayoutModel *model);
+    
+private:
+  Ui::DisplayLayoutInspector *ui;
+
+  DisplayLayoutModel *m_Model;
+};
+
+#endif // DISPLAYLAYOUTINSPECTOR_H
diff --git a/GUI/Qt/Components/DisplayLayoutInspector.ui b/GUI/Qt/Components/DisplayLayoutInspector.ui
new file mode 100644
index 0000000..35aa408
--- /dev/null
+++ b/GUI/Qt/Components/DisplayLayoutInspector.ui
@@ -0,0 +1,339 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DisplayLayoutInspector</class>
+ <widget class="QWidget" name="DisplayLayoutInspector">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>172</width>
+    <height>498</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">* {
+font-size: 12px;
+}
+</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">font-weight:bold;</string>
+     </property>
+     <property name="text">
+      <string>Display Layout:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="grpDisplayLayout" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="spacing">
+       <number>4</number>
+      </property>
+      <property name="sizeConstraint">
+       <enum>QLayout::SetMaximumSize</enum>
+      </property>
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>12</number>
+      </property>
+      <item>
+       <widget class="QToolButton" name="btnFourViews">
+        <property name="maximumSize">
+         <size>
+          <width>26</width>
+          <height>26</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>All four views</string>
+        </property>
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="icon">
+         <iconset>
+          <normalon>:/root/dl_fourviews.png</normalon>
+         </iconset>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="autoExclusive">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnAxial">
+        <property name="maximumSize">
+         <size>
+          <width>26</width>
+          <height>26</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Axial view</string>
+        </property>
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="icon">
+         <iconset>
+          <normalon>:/root/dl_axial.png</normalon>
+         </iconset>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="autoExclusive">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnCoronal">
+        <property name="maximumSize">
+         <size>
+          <width>26</width>
+          <height>26</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Coronal view</string>
+        </property>
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="icon">
+         <iconset>
+          <normalon>:/root/dl_coronal.png</normalon>
+         </iconset>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="autoExclusive">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnSagittal">
+        <property name="maximumSize">
+         <size>
+          <width>26</width>
+          <height>26</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Sagittal view</string>
+        </property>
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="icon">
+         <iconset>
+          <normalon>:/root/dl_sagittal.png</normalon>
+         </iconset>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="autoExclusive">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btn3D">
+        <property name="maximumSize">
+         <size>
+          <width>26</width>
+          <height>26</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>3D view</string>
+        </property>
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="icon">
+         <iconset>
+          <normalon>:/root/dl_3d.png</normalon>
+         </iconset>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="autoExclusive">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>1</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_2">
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">font-weight:bold;</string>
+     </property>
+     <property name="text">
+      <string>Overlay Placement:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="grpLayerLayout" native="true">
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+      </font>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="spacing">
+       <number>4</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QToolButton" name="btnStack">
+        <property name="minimumSize">
+         <size>
+          <width>72</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Stack</string>
+        </property>
+        <property name="icon">
+         <iconset resource="../Resources/SNAPResources.qrc">
+          <normaloff>:/root/layout_overlay_16.png</normaloff>:/root/layout_overlay_16.png</iconset>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="autoExclusive">
+         <bool>true</bool>
+        </property>
+        <property name="toolButtonStyle">
+         <enum>Qt::ToolButtonTextBesideIcon</enum>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnTile">
+        <property name="minimumSize">
+         <size>
+          <width>72</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Tile</string>
+        </property>
+        <property name="icon">
+         <iconset resource="../Resources/SNAPResources.qrc">
+          <normaloff>:/root/layout_tile_16.png</normaloff>:/root/layout_tile_16.png</iconset>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="autoExclusive">
+         <bool>true</bool>
+        </property>
+        <property name="toolButtonStyle">
+         <enum>Qt::ToolButtonTextBesideIcon</enum>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>1</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>btnFourViews</tabstop>
+  <tabstop>btnAxial</tabstop>
+  <tabstop>btnCoronal</tabstop>
+  <tabstop>btnSagittal</tabstop>
+ </tabstops>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/FileChooserPanelWithHistory.cxx b/GUI/Qt/Components/FileChooserPanelWithHistory.cxx
new file mode 100644
index 0000000..f9d5189
--- /dev/null
+++ b/GUI/Qt/Components/FileChooserPanelWithHistory.cxx
@@ -0,0 +1,631 @@
+#include "FileChooserPanelWithHistory.h"
+#include "ui_FileChooserPanelWithHistory.h"
+
+#include <QMenu>
+#include <GlobalUIModel.h>
+#include <HistoryManager.h>
+#include <IRISApplication.h>
+#include <QFileInfo>
+#include <QKeyEvent>
+#include <QDir>
+#include <QFileDialog>
+#include <SNAPQtCommon.h>
+
+
+FileChooserPanelWithHistory::FileChooserPanelWithHistory(QWidget *parent) :
+  QWidget(parent),
+  ui(new Ui::FileChooserPanelWithHistory)
+{
+  ui->setupUi(this);
+
+  // INitialize vars
+  m_Model = NULL;
+  m_oracleTarget = NULL;
+
+  // History menu
+  QMenu *history = new QMenu("History", ui->btnHistory);
+  ui->btnHistory->setMenu(history);
+
+  // Set up an event filter
+  ui->inFilename->installEventFilter(this);
+
+  // Connect up the format selector to the filename
+  connect(ui->inFormat, SIGNAL(activated(QString)), this, SLOT(setActiveFormat(QString)));
+}
+
+FileChooserPanelWithHistory::~FileChooserPanelWithHistory()
+{
+  delete ui;
+}
+
+void FileChooserPanelWithHistory::populateHistory()
+{
+  // Get the history string lists
+  HistoryManager *hm =
+      m_Model->GetDriver()->GetSystemInterface()->GetHistoryManager();
+
+  QStringList local_history =
+      toQStringList(hm->GetLocalHistory(m_historyCategory.toStdString()));
+  QStringList global_history =
+      toQStringList(hm->GetGlobalHistory(m_historyCategory.toStdString()));
+
+  // Fill out the menu
+  QMenu *menu = ui->btnHistory->menu();
+  PopulateHistoryMenu(menu, this, SLOT(onHistorySelection()),
+                      local_history, global_history);
+  ui->btnHistory->setEnabled(menu->actions().size() > 0);
+}
+
+void FileChooserPanelWithHistory::parseFilters(const QString &activeFormat)
+{
+  // Clear the filters
+  m_Filter.clear();
+  ui->inFormat->clear();
+
+  m_defaultFormat = activeFormat;
+
+  // Split the pattern into pieces
+  QStringList pats = m_filePattern.split(";;", QString::SkipEmptyParts);
+
+  // Split each piece
+  foreach(QString pat, pats)
+    {
+    // Handle patterns in parentheses
+    QRegExp rx("(.*)\\((.*)\\)");
+    int pos = rx.indexIn(pat);
+    if(pos >= 0)
+      {
+      // Split into title and list of extensions
+      QString title = rx.cap(1).trimmed();
+      QString extliststr = rx.cap(2).trimmed();
+
+      // Store the extension
+      QStringList extlist = extliststr.split(" ");
+      QStringList extlistclean;
+
+      foreach (QString myext, extlist)
+        {
+        pos = myext.indexOf(".");
+        if(pos >= 0)
+          extlistclean.push_back(myext.mid(pos+1));
+        }
+
+      // Make sure every title has somethign!
+      if(extlistclean.size() == 0)
+        extlistclean.push_back(QString());
+
+      // Append this info
+      m_Filter[title] = extlistclean;
+
+      // Add the title to the format dropbox
+      ui->inFormat->addItem(title);
+
+      // Use this filter
+      if(m_defaultFormat.length() == 0)
+        m_defaultFormat = title;
+      }
+    }
+
+  // Update the combo box
+  ui->inFormat->setCurrentText(m_defaultFormat);
+
+  // Show or hide the format panel depending on the number of formats available
+  ui->panelFormat->setVisible(m_Filter.size() > 1);
+}
+
+
+QString FileChooserPanelWithHistory::fixExtension() const
+{
+  // This method appends the extension to the currently entered filename if the
+  // currently entered filename does not have an extension already. This is so
+  // that we can type in test and it gets saved as test.png
+  QString filename = ui->inFilename->text();
+  QString filenameAbs = this->absoluteFilenameKeepExtension();
+
+  // Cases when we don't append the extension
+  if(filename.length() == 0 ||                  // No filename entered
+     m_defaultFormat.length() == 0 ||           // No current format selected
+     m_Filter[m_defaultFormat].size() == 0 ||   // Current format does not have any extensions
+     QFileInfo(filenameAbs).isDir() ||          // Selected filename is a directory
+     m_forceExtension == false)                 // User asked not to do this
+    return filename;
+
+  // Check if the filename already has one of the extensions for the selected format
+  foreach(QString ext, m_Filter[m_defaultFormat])
+    {
+    if(ext.length())
+      {
+      QString eext = QString(".%1").arg(ext);
+      if(filename.endsWith(eext))
+        return filename;
+      }
+    }
+
+  // Default extension is the first extension in the accepted list
+  QString defaultExt = m_Filter[m_defaultFormat].front();
+
+  // Is the thing the user typed in ending with a dot? Avoid having two dots
+  if(filename.endsWith("."))
+    return filename + defaultExt;
+
+  // Otherwise, return the filename with the default extension
+  return filename + "." + defaultExt;
+}
+
+void FileChooserPanelWithHistory::initializeForOpenFile(
+    GlobalUIModel *model,
+    const QString &labelText,
+    const QString &historyCategory,
+    const QString &filePattern,
+    const QString &initialFile,
+    const QString &activeFormat)
+{
+  // State
+  m_Model = model;
+  m_openMode = true;
+  m_directoryMode = false;
+  m_filePattern = filePattern;
+  m_historyCategory = historyCategory;
+  m_forceExtension = false;
+
+  // Compute the suffix
+  parseFilters(activeFormat);
+
+  // Initial UI values
+  ui->label->setText(labelText);
+
+  // Populate the history
+  this->populateHistory();
+
+  // Clear the error fields
+  ui->outError->clear();
+  ui->outSavePath->clear();
+
+  // Get the working directory based on history or main image
+  m_workingDir = GetFileDialogPath(m_Model, m_historyCategory.toStdString().c_str());
+
+  // Set the initial file
+  if(initialFile.length())
+    {
+    this->updateFilename(initialFile);
+    }
+
+  // Update the display
+  on_inFilename_textChanged(ui->inFilename->text());
+}
+
+void FileChooserPanelWithHistory::initializeForSaveFile(
+    GlobalUIModel *model,
+    const QString &labelText,
+    const QString &historyCategory,
+    const QString &filePattern,
+    bool force_extension,
+    const QString &initialFile,
+    const QString &activeFormat)
+{
+  // State
+  m_Model = model;
+  m_openMode = false;
+  m_directoryMode = false;
+  m_filePattern = filePattern;
+  m_historyCategory = historyCategory;
+  m_forceExtension = force_extension;
+
+  // Compute the suffix
+  parseFilters(activeFormat);
+
+  // Initial UI values
+  ui->label->setText(labelText);
+
+  // Populate the history
+  this->populateHistory();
+
+  // Clear the error fields
+  ui->outError->clear();
+  ui->outSavePath->clear();
+
+  // Get the working directory based on history or main image
+  m_workingDir = GetFileDialogPath(m_Model, m_historyCategory.toStdString().c_str());
+
+  // Set the initial file
+  if(initialFile.length())
+    {
+    // Update the filename and working directory based on the initial file
+    this->updateFilename(initialFile);    
+    }
+  else
+    {
+    // Initialize the dialog with a default filename
+    QString default_basename = "Untitled";
+    ui->inFilename->setText(QString("%1.%2").arg(default_basename, m_Filter[m_defaultFormat].front()));
+    }
+
+  // Highlight just the filename
+  highlightFilename();
+
+  // Update the display
+  on_inFilename_textChanged(ui->inFilename->text());
+}
+
+void FileChooserPanelWithHistory::highlightFilename()
+{
+  // Select the part of the filename minus the extension
+  QString text = ui->inFilename->text();
+  foreach(QString ext, m_Filter[m_defaultFormat])
+    {
+    if(text.endsWith(ext, Qt::CaseInsensitive))
+      {
+      ui->inFilename->setSelection(0, text.length() - (1+ext.length()));
+      return;
+      }
+    }
+}
+
+void FileChooserPanelWithHistory::addButton(QWidget *button)
+{
+  ui->wButtonPanel->layout()->addWidget(button);
+}
+
+void FileChooserPanelWithHistory::setCustomFormatOracle(QObject *target, const char *slot)
+{
+  m_oracleTarget = target;
+  m_oracleSlot = slot;
+}
+
+void FileChooserPanelWithHistory::onHistorySelection()
+{
+  // Get the absolute filename
+  QAction *action = static_cast<QAction *>(this->sender());
+  this->updateFilename(action->text());
+}
+
+void FileChooserPanelWithHistory::updateFilename(QString filename)
+{
+  QFileInfo fi(filename);
+  QString new_file;
+
+  // If the filename given is relative, define it relative to the working directory
+  if(fi.isRelative())
+    fi = QFileInfo(m_workingDir, filename);
+
+  // If the path exists, use it as the new working directory
+  if(fi.absoluteDir().exists())
+    {
+    m_workingDir = fi.absolutePath();
+    new_file = fi.fileName();
+    }
+  else
+    {
+    new_file = fi.absoluteFilePath();
+    }
+
+  // Make sure the update code executes even if the text is not changed
+  if(new_file == ui->inFilename->text())
+    on_inFilename_textChanged(new_file);
+  else
+    ui->inFilename->setText(new_file);
+
+}
+
+QString FileChooserPanelWithHistory::absoluteFilename() const
+{
+  QString fix_ext = this->fixExtension();
+  QFileInfo fi(fix_ext);
+  if(fi.isAbsolute())
+    return fi.absoluteFilePath();
+
+  QFileInfo fi2(QDir(m_workingDir), fix_ext);
+  return fi2.absoluteFilePath();
+}
+
+QString FileChooserPanelWithHistory::absoluteFilenameKeepExtension() const
+{
+  QFileInfo fi(ui->inFilename->text());
+  if(fi.isAbsolute())
+    return fi.absoluteFilePath();
+
+  QFileInfo fi2(QDir(m_workingDir), ui->inFilename->text());
+  return fi2.absoluteFilePath();
+}
+
+QString FileChooserPanelWithHistory::activeFormat() const
+{
+  return m_defaultFormat;
+}
+
+QString FileChooserPanelWithHistory::errorText() const
+{
+  return ui->outError->text();
+}
+
+void FileChooserPanelWithHistory::setErrorText(const QString &text)
+{
+  ui->outError->setText(text);
+}
+
+void FileChooserPanelWithHistory::onFilenameAccept()
+{
+  QDir myDir = QFileInfo(this->absoluteFilename()).absoluteDir();
+  if(myDir.exists())
+    UpdateFileDialogPathForCategory(m_historyCategory.toStdString().c_str(),
+                                    myDir.absolutePath());
+}
+
+void FileChooserPanelWithHistory::setActiveFormat(QString format)
+{
+  if(format == m_defaultFormat)
+    return;
+
+  // Change the format
+  QString oldFormat = m_defaultFormat;
+  m_defaultFormat = format;
+
+  // In open mode, we don't tweak the extension
+  if(m_openMode)
+    return;
+
+  // Get the default new suffix
+  QString newSuffix = m_Filter[format].front();
+
+  // If the one of the recognized extensions is currently selected, replace it
+  QString fn = ui->inFilename->text();
+  foreach (QString ext, m_Filter[oldFormat])
+    {
+    QString eext = QString(".%1").arg(ext);
+    if(fn.endsWith(eext, Qt::CaseInsensitive))
+      {
+      fn = fn.mid(0, fn.length() - ext.length()) + newSuffix;
+      break;
+      }
+    }
+
+  // Modify the extension if it was not overridden
+  if(fn != ui->inFilename->text())
+    {
+    ui->inFilename->setText(fn);
+    }
+
+  // Highlight the filename
+  highlightFilename();
+}
+
+void FileChooserPanelWithHistory::on_btnBrowse_clicked()
+{
+  // Get the file name
+  QString sel;
+
+  // Where to open the dialog?
+  QFileInfo bfi(QDir(m_workingDir), ui->inFilename->text());
+  if(!bfi.absoluteDir().exists())
+    bfi = QFileInfo(m_workingDir);
+
+  QString browseDir = bfi.absoluteFilePath();
+
+  // Create a file dialog
+  QFileDialog dialog(this, ui->label->text());
+
+  if(m_openMode)
+    {
+    dialog.setFileMode(QFileDialog::ExistingFile);
+    dialog.setAcceptMode(QFileDialog::AcceptOpen);
+    }
+  else
+    {
+    dialog.setFileMode(QFileDialog::AnyFile);
+    dialog.setAcceptMode(QFileDialog::AcceptSave);
+    }
+
+  if(browseDir.length())
+    {
+    QFileInfo file_info(browseDir);
+    if(file_info.isDir())
+      {
+      dialog.setDirectory(file_info.absoluteFilePath() + "/");
+      }
+    else
+      {
+      dialog.setDirectory(file_info.absolutePath() + "/");
+      dialog.selectFile(file_info.fileName());
+      }
+    }
+
+  // Create a single filter that combines all of the extensions for all image types
+  // If any of the extensions is missing, there will be no filter at all
+  QStringList flatExtensionList;
+  QStringList formatList;
+  QString formatEntry;
+  bool have_empty = false;
+  foreach(QString format, m_Filter.keys())
+    {
+    QStringList formatExtensionList;
+    foreach(QString ext, m_Filter[format])
+      {
+#ifdef __APPLE__
+      // On MacOS, compound extensions are a problem
+      int pos = ext.lastIndexOf(".");
+      if(pos >= 0)
+        {
+        if(m_openMode)
+          ext = ext.replace('.','*');
+        }
+#endif
+      if(ext.length())
+        {
+        QString eext = QString("*.%1").arg(ext);
+        flatExtensionList << eext;
+        formatExtensionList << eext;
+        }
+      else
+        {
+        have_empty = true;
+        formatExtensionList << "*";
+        }
+      }
+
+    QString line = QString("%1 (%2)").arg(format).arg(formatExtensionList.join(" "));
+    formatList << line;
+
+    if(m_defaultFormat == format)
+      formatEntry = line;
+    }
+
+  if(m_openMode)
+    {
+    QString allext = flatExtensionList.join(" ");
+    if(!have_empty && allext.length())
+      {
+      dialog.setNameFilter(allext);
+      }
+    }
+  else
+    {
+    dialog.setNameFilters(formatList);
+    dialog.selectNameFilter(formatEntry);
+    }
+
+  if(dialog.exec() && dialog.selectedFiles().size())
+    sel = dialog.selectedFiles().first();
+
+  if(sel.length())
+    {
+    // Update the selection
+    this->updateFilename(sel);
+    }
+}
+
+QString FileChooserPanelWithHistory::guessFormat(const QString &text)
+{
+  QString newFormat;
+
+  // Try using the oracle
+  if(m_oracleTarget)
+    {
+    QMetaObject::invokeMethod(m_oracleTarget, m_oracleSlot, Qt::DirectConnection,
+                              Q_RETURN_ARG(QString, newFormat),
+                              Q_ARG(QString, text));
+    }
+
+  // If the oracle failed, try to guess
+  if(newFormat.isNull())
+    {
+    foreach(QString format, m_Filter.keys())
+      {
+      foreach(QString ext, m_Filter[format])
+        {
+        QString eext = QString(".%1").arg(ext);
+        if(ext.length() && text.endsWith(eext))
+          {
+          newFormat = format;
+          break;
+          }
+        }
+      }
+    }
+
+  return newFormat;
+}
+
+void FileChooserPanelWithHistory::on_inFilename_textChanged(const QString &text)
+{
+  // The filename has changed. The first thing we do is to see if the filename has
+  // an extension that matches one of our supported extensions. If it does, then
+  // we change the active format to be that format
+  QString format = guessFormat(absoluteFilenameKeepExtension());
+  if(format.length())
+    {
+    m_defaultFormat = format;
+    ui->inFormat->setCurrentText(format);
+    emit activeFormatChanged(format);
+    }
+
+  else if(m_openMode)
+    {
+    m_defaultFormat = QString();
+    ui->inFormat->setCurrentIndex(-1);
+    emit activeFormatChanged(format);
+    }
+
+  // At this point the format might have been changed to match the filename
+  // Get the fileinfo for this file
+  QString file_ext = this->fixExtension();
+  QFileInfo fi(file_ext), fiwd;
+  if(fi.isRelative())
+    fiwd = QFileInfo(m_workingDir, file_ext);
+  else
+    fiwd = fi;
+
+  // Clear the output messages
+  ui->outSavePath->clear();
+  ui->outError->clear();
+
+  // Changes to the text box will be used to populate the error text
+  if(m_openMode)
+    {
+    // Does the file exist?
+    if(text.length() && !fiwd.exists())
+      ui->outError->setText("The file does not exist");
+    else if(text.length() && !fiwd.isReadable())
+      ui->outError->setText("The file is not readable");
+    else if(ui->inFormat->currentIndex() == -1 && ui->inFilename->text().length())
+      ui->outError->setText("Unable to recognize file format");
+    else
+      ui->outError->setText("");
+
+    // For relative paths, inform the user where the file will be saved in
+    if(fi.isRelative() && !fi.isDir())
+      {
+      QString saveDir = fiwd.isDir() ? fiwd.absoluteFilePath() : fiwd.absolutePath();
+      ui->outSavePath->setText(QString("Path: %1").arg(saveDir));
+      }
+    }
+  else
+    {
+    if(text.length())
+      {
+      // Get the extension
+      QString saveFile = this->fixExtension();
+      QFileInfo fi(saveFile);
+
+      // If the file is a directory, we don't give any errors, as the user is probably just typing
+      if(fi.isDir())
+        return;
+
+      // For relative paths, inform the user where the file will be saved in
+      if(fi.isRelative())
+        {
+        QString saveDir = fiwd.isDir() ? fiwd.absoluteFilePath() : fiwd.absolutePath();
+        ui->outSavePath->setText(QString("Path: %1").arg(saveDir));
+        }
+
+      // Does the file exist?
+      if(fiwd.exists())
+        ui->outError->setText("Existing file will be overridden!");
+      }
+    }
+
+  emit absoluteFilenameChanged(absoluteFilename());
+}
+
+bool FileChooserPanelWithHistory::eventFilter(QObject *obj, QEvent *ev)
+{
+  /*
+  if(obj == ui->inFilename)
+    {
+    if(ev->type() == QEvent::KeyPress)
+      {
+      QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
+      if(keyEvent->key() == Qt::Key_Tab)
+        {
+        if(ui->inFilename->completer()->completionCount())
+          {
+          ui->inFilename->completer()->complete();
+          return true;
+          }
+        }
+      }
+    } */
+
+  return QObject::eventFilter(obj, ev);
+
+}
+
diff --git a/GUI/Qt/Components/FileChooserPanelWithHistory.h b/GUI/Qt/Components/FileChooserPanelWithHistory.h
new file mode 100644
index 0000000..e7fb53c
--- /dev/null
+++ b/GUI/Qt/Components/FileChooserPanelWithHistory.h
@@ -0,0 +1,125 @@
+#ifndef FILECHOOSERPANELWITHHISTORY_H
+#define FILECHOOSERPANELWITHHISTORY_H
+
+#include <QWidget>
+#include <QMap>
+
+namespace Ui {
+  class FileChooserPanelWithHistory;
+}
+
+class GlobalUIModel;
+
+/**
+ * This component is used by different ITK-SNAP dialogs to prompt the
+ * user for a filename, while presenting a history drop-down button and
+ * a browse button.
+ */
+class FileChooserPanelWithHistory : public QWidget
+{
+  Q_OBJECT
+
+  Q_PROPERTY(QString absoluteFilename READ absoluteFilename NOTIFY absoluteFilenameChanged)
+  Q_PROPERTY(QString activeFormat READ activeFormat NOTIFY activeFormatChanged)
+  Q_PROPERTY(QString errorTest READ errorText WRITE setErrorText)
+
+public:
+  explicit FileChooserPanelWithHistory(QWidget *parent = 0);
+  ~FileChooserPanelWithHistory();
+
+  // Initialize the panel for opening a file
+  void initializeForOpenFile(
+      GlobalUIModel *model,
+      const QString &labelText,
+      const QString &historyCategory,
+      const QString &filePattern,
+      const QString &initialFile = QString(),
+      const QString &activeFormat = QString());
+
+  // Initialize the panel for opening a file
+  void initializeForSaveFile(
+      GlobalUIModel *model,
+      const QString &labelText,
+      const QString &historyCategory,
+      const QString &filePattern,
+      bool force_extension,
+      const QString &initialFile = QString(),
+      const QString &activeFormat = QString());
+
+  // Add a button to the button panel (customization)
+  void addButton(QWidget *button);
+
+  // Provide a custom "oracle" to determine file format from filename
+  void setCustomFormatOracle(QObject *target, const char *slot);
+
+  // Get the filename selected
+  QString absoluteFilename() const;
+
+  // Get teh active format
+  QString activeFormat() const;
+
+  QString errorText() const;
+  void setErrorText(const QString &text);
+
+signals:
+
+  void absoluteFilenameChanged(QString text);
+  void activeFormatChanged(QString text);
+
+public slots:
+
+  // This slot should be envoked when the container dialog
+  // accepts the filename. The path of the filename will be
+  // recorded so the next time we invoke this dialog, the
+  // same path will be used
+  void onFilenameAccept();
+
+  void setActiveFormat(QString format);
+
+private slots:
+  void on_btnBrowse_clicked();
+
+  void onHistorySelection();
+
+  void on_inFilename_textChanged(const QString &text);
+
+protected:
+
+  // Populate the history
+  void populateHistory();
+
+  // Fix the extension of the file in the dialog
+  QString fixExtension() const;
+
+  virtual bool eventFilter(QObject *obj, QEvent *ev);
+
+  // Update filename based on history button or browse
+  void updateFilename(QString filename);
+
+private:
+  Ui::FileChooserPanelWithHistory *ui;
+
+  bool m_openMode;
+  bool m_directoryMode;
+  bool m_forceExtension;
+
+  QString m_historyCategory;
+  QString m_filePattern;
+  QString m_workingDir;
+  QString m_defaultFormat;
+
+  QMap<QString, QStringList> m_Filter;
+
+  GlobalUIModel *m_Model;
+  void parseFilters(const QString &activeFormat = QString());
+  void highlightFilename();
+
+  // Get the filename selected
+  QString absoluteFilenameKeepExtension() const;
+
+  QObject *m_oracleTarget;
+  const char *m_oracleSlot;
+  QString guessFormat(const QString &text);
+};
+
+#endif // FILECHOOSERPANELWITHHISTORY_H
diff --git a/GUI/Qt/Components/FileChooserPanelWithHistory.ui b/GUI/Qt/Components/FileChooserPanelWithHistory.ui
new file mode 100644
index 0000000..4d2f294
--- /dev/null
+++ b/GUI/Qt/Components/FileChooserPanelWithHistory.ui
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FileChooserPanelWithHistory</class>
+ <widget class="QWidget" name="FileChooserPanelWithHistory">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>444</width>
+    <height>155</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QMenu {
+font-size:12px;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>4</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget_2" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>TextLabel</string>
+        </property>
+       </widget>
+      </item>
+      <item alignment="Qt::AlignRight|Qt::AlignBottom">
+       <widget class="QLabel" name="outError">
+        <property name="styleSheet">
+         <string notr="true">font-size:10px; color: #7f0000;	</string>
+        </property>
+        <property name="text">
+         <string>TextLabel</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+        <property name="wordWrap">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLineEdit" name="inFilename"/>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_3">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item alignment="Qt::AlignTop">
+       <widget class="QLabel" name="outSavePath">
+        <property name="styleSheet">
+         <string notr="true">font-size:10px; color: rgb(91, 91, 91);</string>
+        </property>
+        <property name="text">
+         <string>TextLabel</string>
+        </property>
+        <property name="wordWrap">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="verticalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>28</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="wButtonPanel" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnBrowse">
+        <property name="text">
+         <string>Browse...</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnHistory">
+        <property name="text">
+         <string>History</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="panelFormat" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="labelFormat">
+        <property name="text">
+         <string>File Format:</string>
+        </property>
+       </widget>
+      </item>
+      <item alignment="Qt::AlignLeft">
+       <widget class="QComboBox" name="inFormat">
+        <property name="minimumSize">
+         <size>
+          <width>160</width>
+          <height>0</height>
+         </size>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>inFilename</tabstop>
+  <tabstop>btnBrowse</tabstop>
+  <tabstop>btnHistory</tabstop>
+  <tabstop>inFormat</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/GeneralLayerInspector.cxx b/GUI/Qt/Components/GeneralLayerInspector.cxx
new file mode 100644
index 0000000..d80886a
--- /dev/null
+++ b/GUI/Qt/Components/GeneralLayerInspector.cxx
@@ -0,0 +1,55 @@
+#include "GeneralLayerInspector.h"
+#include "ui_GeneralLayerInspector.h"
+
+#include "LayerGeneralPropertiesModel.h"
+
+#include "QtCheckBoxCoupling.h"
+#include "QtComboBoxCoupling.h"
+#include "QtSpinBoxCoupling.h"
+#include "QtSliderCoupling.h"
+#include "QtLineEditCoupling.h"
+
+#include "QtWidgetActivator.h"
+
+Q_DECLARE_METATYPE(LayerGeneralPropertiesModel::DisplayMode)
+
+GeneralLayerInspector::GeneralLayerInspector(QWidget *parent) :
+  QWidget(parent),
+  ui(new Ui::GeneralLayerInspector)
+{
+  ui->setupUi(this);
+}
+
+GeneralLayerInspector::~GeneralLayerInspector()
+{
+  delete ui;
+}
+
+void GeneralLayerInspector::SetModel(LayerGeneralPropertiesModel *model)
+{
+  m_Model = model;
+
+  // Couple the widgets
+  makeCoupling(ui->inMode, m_Model->GetDisplayModeModel());
+  makeCoupling(ui->inComponent, m_Model->GetSelectedComponentModel());
+  makeCoupling(ui->inComponentSlider, m_Model->GetSelectedComponentModel());
+  makeCoupling(ui->chkAnimate, m_Model->GetAnimateModel());
+
+  makeCoupling(ui->inOpacity, m_Model->GetLayerOpacityModel());
+  makeCoupling(ui->inOpacityValue, m_Model->GetLayerOpacityModel());
+  makeCoupling(ui->chkVisible, m_Model->GetLayerVisibilityModel());
+
+  makeCoupling(ui->outFilename, m_Model->GetFilenameModel());
+  makeCoupling(ui->inNickname, m_Model->GetNicknameModel());
+
+  activateOnFlag(ui->grpMulticomponent, m_Model,
+                 LayerGeneralPropertiesModel::UIF_MULTICOMPONENT);
+
+  activateOnFlag(ui->chkAnimate, m_Model,
+                 LayerGeneralPropertiesModel::UIF_CAN_SWITCH_COMPONENTS);
+  activateOnFlag(ui->inComponent, m_Model,
+                 LayerGeneralPropertiesModel::UIF_CAN_SWITCH_COMPONENTS);
+  activateOnFlag(ui->inComponentSlider, m_Model,
+                 LayerGeneralPropertiesModel::UIF_CAN_SWITCH_COMPONENTS);
+
+}
diff --git a/GUI/Qt/Components/GeneralLayerInspector.h b/GUI/Qt/Components/GeneralLayerInspector.h
new file mode 100644
index 0000000..cb33e7c
--- /dev/null
+++ b/GUI/Qt/Components/GeneralLayerInspector.h
@@ -0,0 +1,29 @@
+#ifndef MULTICOMPONENTINSPECTOR_H
+#define MULTICOMPONENTINSPECTOR_H
+
+#include <QWidget>
+
+namespace Ui {
+class GeneralLayerInspector;
+}
+
+class GlobalUIModel;
+class LayerGeneralPropertiesModel;
+
+class GeneralLayerInspector : public QWidget
+{
+  Q_OBJECT
+  
+public:
+  explicit GeneralLayerInspector(QWidget *parent = 0);
+  ~GeneralLayerInspector();
+
+  void SetModel(LayerGeneralPropertiesModel *model);
+  
+private:
+  Ui::GeneralLayerInspector *ui;
+
+  LayerGeneralPropertiesModel *m_Model;
+};
+
+#endif // MULTICHANNELINSPECTOR_H
diff --git a/GUI/Qt/Components/GeneralLayerInspector.ui b/GUI/Qt/Components/GeneralLayerInspector.ui
new file mode 100644
index 0000000..249b771
--- /dev/null
+++ b/GUI/Qt/Components/GeneralLayerInspector.ui
@@ -0,0 +1,208 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>GeneralLayerInspector</class>
+ <widget class="QWidget" name="GeneralLayerInspector">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>429</width>
+    <height>449</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QGroupBox {
+  background-origin: content;
+  margin-top: 15px;
+  font-weight: bold;
+  font-size: 12px;
+  font-family: helvetica;
+  color: rgb(30,30,160);
+  background-color: rgb(237,237,237);
+  padding: 5px;
+  border-radius: 4px;
+  border: 1px solid rgb(130,130,130);
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <property name="spacing">
+    <number>12</number>
+   </property>
+   <property name="leftMargin">
+    <number>6</number>
+   </property>
+   <property name="topMargin">
+    <number>18</number>
+   </property>
+   <property name="rightMargin">
+    <number>6</number>
+   </property>
+   <property name="bottomMargin">
+    <number>6</number>
+   </property>
+   <item>
+    <widget class="QGroupBox" name="grpInfo">
+     <property name="title">
+      <string>General Information</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item row="1" column="1">
+       <widget class="QLineEdit" name="inNickname">
+        <property name="toolTip">
+         <string>This is the name that is used when referring to the image in ITK-SNAP.</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_4">
+        <property name="text">
+         <string>Nickname:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QLineEdit" name="outFilename">
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QWidget" name="widget" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <property name="spacing">
+          <number>12</number>
+         </property>
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QSpinBox" name="inOpacityValue">
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="suffix">
+            <string>%</string>
+           </property>
+           <property name="maximum">
+            <number>100</number>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QSlider" name="inOpacity">
+           <property name="maximum">
+            <number>100</number>
+           </property>
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="tickPosition">
+            <enum>QSlider::TicksBelow</enum>
+           </property>
+           <property name="tickInterval">
+            <number>25</number>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="chkVisible">
+           <property name="text">
+            <string>Visible</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Filename:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="label_5">
+        <property name="text">
+         <string>Opacity:</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="grpMulticomponent">
+     <property name="title">
+      <string>Displaying Multiple Components per Voxel</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item row="0" column="0">
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>Display Mode:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1" colspan="3">
+       <widget class="QComboBox" name="inMode"/>
+      </item>
+      <item row="1" column="3" alignment="Qt::AlignRight">
+       <widget class="QCheckBox" name="chkAnimate">
+        <property name="text">
+         <string>Animate</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Component:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QSpinBox" name="inComponent"/>
+      </item>
+      <item row="1" column="2">
+       <widget class="QSlider" name="inComponentSlider">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/HistoryQListModel.cxx b/GUI/Qt/Components/HistoryQListModel.cxx
new file mode 100644
index 0000000..6c6d321
--- /dev/null
+++ b/GUI/Qt/Components/HistoryQListModel.cxx
@@ -0,0 +1,81 @@
+#include "HistoryQListModel.h"
+#include "HistoryManager.h"
+#include "SystemInterface.h"
+#include "IRISApplication.h"
+#include "GlobalUIModel.h"
+#include <itksys/SystemTools.hxx>
+#include <QIcon>
+#include "SNAPQtCommon.h"
+#include "LatentITKEventNotifier.h"
+
+HistoryQListModel::HistoryQListModel(QObject *parent) :
+  QAbstractListModel(parent)
+{
+  m_Model = NULL;
+}
+
+int HistoryQListModel::rowCount(const QModelIndex &parent) const
+{
+  // Display at most 12 entries in the history
+  return std::min((size_t) 12, m_CachedHistory.size());
+}
+
+QVariant HistoryQListModel::data(const QModelIndex &index, int role) const
+{
+  // Get the entry
+  std::string item = m_CachedHistory[m_CachedHistory.size() - (1 + index.row())];
+
+  // Display the appropriate item
+  if(role == Qt::DisplayRole)
+    {
+    // Get the shorter filename
+    std::string shorty = itksys::SystemTools::GetFilenameName(item.c_str());
+    return from_utf8(shorty);
+    }
+  else if(role == Qt::DecorationRole)
+    {
+    // Need to get an icon!
+    std::string iconfile = m_Model->GetDriver()->GetSystemInterface()
+        ->GetThumbnailAssociatedWithFile(item.c_str());
+
+    // Need to load the icon
+    QIcon icon;
+    icon.addFile(iconfile.c_str());
+    return icon;
+    }
+  else if(role == Qt::ToolTipRole || role == Qt::UserRole)
+    {
+    return from_utf8(item.c_str());
+    }
+  return QVariant();
+
+}
+
+void HistoryQListModel::Initialize(
+    GlobalUIModel *model, const std::string &category)
+{
+  m_Model = model;
+  m_HistoryName = category;
+
+  // Get the property models for the local and global histories
+  HistoryManager::AbstractHistoryModel *hmodel =
+      m_Model->GetDriver()->GetHistoryManager()->GetGlobalHistoryModel(category);
+
+  // Listen for updates from the history model
+  LatentITKEventNotifier::connect(hmodel, ValueChangedEvent(),
+                                  this, SLOT(onModelUpdate(EventBucket)));
+
+  // Cache the history
+  m_CachedHistory = hmodel->GetValue();
+}
+
+void HistoryQListModel::onModelUpdate(const EventBucket &bucket)
+{
+  this->beginResetModel();
+
+  // When history changes, we update
+  m_CachedHistory =
+      m_Model->GetDriver()->GetHistoryManager()->GetGlobalHistory(m_HistoryName);
+
+  this->endResetModel();
+}
diff --git a/GUI/Qt/Components/HistoryQListModel.h b/GUI/Qt/Components/HistoryQListModel.h
new file mode 100644
index 0000000..c4c8e49
--- /dev/null
+++ b/GUI/Qt/Components/HistoryQListModel.h
@@ -0,0 +1,45 @@
+#ifndef HISTORYQLISTMODEL_H
+#define HISTORYQLISTMODEL_H
+
+#include "SNAPCommon.h"
+#include <QAbstractListModel>
+#include <vector>
+
+class EventBucket;
+class GlobalUIModel;
+
+/**
+  QT model used to display an item from the image history as an entry in
+  the table of recently loaded images
+  */
+class HistoryQListModel : public QAbstractListModel
+{
+  Q_OBJECT
+
+public:
+  explicit HistoryQListModel(QObject *parent = 0);
+
+  virtual int rowCount(const QModelIndex &parent) const;
+  virtual QVariant data(const QModelIndex &index, int role) const;
+
+  void Initialize(GlobalUIModel *, const std::string &category);
+
+signals:
+  
+public slots:
+  void onModelUpdate(const EventBucket &bucket);
+
+protected:
+
+  // Need a pointer to the model
+  GlobalUIModel *m_Model;
+
+  // The name of the history
+  std::string m_HistoryName;
+
+  // The cached value of the history - we keep it for speed
+  std::vector<std::string> m_CachedHistory;
+
+};
+
+#endif // HISTORYQLISTMODEL_H
diff --git a/GUI/Qt/Components/ImageInfoInspector.cxx b/GUI/Qt/Components/ImageInfoInspector.cxx
new file mode 100644
index 0000000..c6d17d2
--- /dev/null
+++ b/GUI/Qt/Components/ImageInfoInspector.cxx
@@ -0,0 +1,52 @@
+#include "ImageInfoInspector.h"
+#include "ui_ImageInfoInspector.h"
+
+#include "ImageInfoModel.h"
+#include "QtWidgetArrayCoupling.h"
+#include "QtLineEditCoupling.h"
+#include "QtSpinBoxCoupling.h"
+
+ImageInfoInspector::ImageInfoInspector(QWidget *parent) :
+  SNAPComponent(parent),
+  ui(new Ui::ImageInfoInspector)
+{
+  ui->setupUi(this);
+}
+
+ImageInfoInspector::~ImageInfoInspector()
+{
+  delete ui;
+}
+
+void ImageInfoInspector::SetModel(ImageInfoModel *model)
+{
+  // Store the model
+  m_Model = model;
+
+  // Create the traits objects for the various fields. This allows us to
+  // specify the precision used to display these values
+  FixedPrecisionRealToTextFieldWidgetTraits<double, QLineEdit> tr_real(4);
+
+  makeArrayCoupling(ui->outDimX, ui->outDimY, ui->outDimZ,
+                    m_Model->GetImageDimensionsModel());
+
+  makeArrayCoupling(ui->outSpacingX, ui->outSpacingY, ui->outSpacingZ,
+                    m_Model->GetImageSpacingModel(), tr_real);
+
+  makeArrayCoupling(ui->outOriginX, ui->outOriginY, ui->outOriginZ,
+                    m_Model->GetImageOriginModel(), tr_real);
+
+  makeArrayCoupling(ui->outItkX, ui->outItkY, ui->outItkZ,
+                    m_Model->GetImageItkCoordinatesModel(), tr_real);
+
+  makeArrayCoupling(ui->outNiftiX, ui->outNiftiY, ui->outNiftiZ,
+                    m_Model->GetImageNiftiCoordinatesModel(), tr_real);
+
+  makeArrayCoupling(ui->inVoxX, ui->inVoxY, ui->inVoxZ,
+                    m_Model->GetImageVoxelCoordinatesModel());
+
+  makeArrayCoupling(ui->outMin, ui->outMax,
+                    m_Model->GetImageMinMaxModel(), tr_real);
+
+  makeCoupling(ui->outRAI, m_Model->GetImageOrientationModel());
+}
diff --git a/GUI/Qt/Components/ImageInfoInspector.h b/GUI/Qt/Components/ImageInfoInspector.h
new file mode 100644
index 0000000..7e05dac
--- /dev/null
+++ b/GUI/Qt/Components/ImageInfoInspector.h
@@ -0,0 +1,29 @@
+#ifndef IMAGEINFOINSPECTOR_H
+#define IMAGEINFOINSPECTOR_H
+
+#include <SNAPComponent.h>
+
+class ImageInfoModel;
+
+namespace Ui {
+class ImageInfoInspector;
+}
+
+class ImageInfoInspector : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit ImageInfoInspector(QWidget *parent = 0);
+  ~ImageInfoInspector();
+
+  void SetModel(ImageInfoModel *model);
+
+private:
+
+  ImageInfoModel *m_Model;
+
+  Ui::ImageInfoInspector *ui;
+};
+
+#endif // IMAGEINFOINSPECTOR_H
diff --git a/GUI/Qt/Components/ImageInfoInspector.ui b/GUI/Qt/Components/ImageInfoInspector.ui
new file mode 100644
index 0000000..12dd3c3
--- /dev/null
+++ b/GUI/Qt/Components/ImageInfoInspector.ui
@@ -0,0 +1,964 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ImageInfoInspector</class>
+ <widget class="QWidget" name="ImageInfoInspector">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>450</width>
+    <height>523</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QGroupBox {
+  background-origin: content;
+  margin-top: 15px;
+  font-weight: normal;
+  font-size: 12px;
+  color: black;
+  padding: 5px;
+  border-radius: 0px;
+  border-top: 1px solid rgb(130,130,130);
+  border-left: none;
+  border-right:none;
+  border-bottom:none;
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+}
+QWidget:read-only {
+  background-color:rgb(240,240,240);
+}
+QDoubleSpinBox:read-only {
+  background-color:rgb(240,240,240);
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>6</number>
+   </property>
+   <property name="leftMargin">
+    <number>6</number>
+   </property>
+   <property name="topMargin">
+    <number>18</number>
+   </property>
+   <property name="rightMargin">
+    <number>6</number>
+   </property>
+   <property name="bottomMargin">
+    <number>6</number>
+   </property>
+   <item>
+    <widget class="QGroupBox" name="groupBox">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="title">
+      <string>Dimensions</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QLabel" name="label_3">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>x:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="outDimX">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="label_2">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>y:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="outDimY">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="label">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>z:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="outDimZ">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="title">
+      <string>Voxel Spacing</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item>
+       <spacer name="horizontalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QLabel" name="label_4">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>x:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="outSpacingX">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="label_5">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>y:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="outSpacingY">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="label_6">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>z:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="outSpacingZ">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox_3">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="title">
+      <string>Origin and Orientation</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item row="0" column="0">
+       <spacer name="horizontalSpacer_3">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="1">
+       <widget class="QLabel" name="label_7">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>x:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="3">
+       <widget class="QLabel" name="label_8">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>y:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="5">
+       <widget class="QLabel" name="label_9">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>z:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="4">
+       <widget class="QLineEdit" name="outRAI">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0" colspan="4">
+       <widget class="QLabel" name="label_10">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Orientation (RAI) code:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="2">
+       <widget class="QLineEdit" name="outOriginX">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="4">
+       <widget class="QLineEdit" name="outOriginY">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="6">
+       <widget class="QLineEdit" name="outOriginZ">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="5" colspan="2">
+       <widget class="QToolButton" name="toolButton">
+        <property name="text">
+         <string>Reorient...</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox_4">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="title">
+      <string>3D Cursor Position</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item row="0" column="1">
+       <widget class="QLabel" name="label_11">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>x:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="3">
+       <widget class="QLabel" name="label_12">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>y:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="5">
+       <widget class="QLabel" name="label_13">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>z:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="5">
+       <widget class="QLabel" name="label_15">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>z:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="3">
+       <widget class="QLabel" name="label_16">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>y:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QLabel" name="label_17">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>x:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="5">
+       <widget class="QLabel" name="label_19">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>z:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="3">
+       <widget class="QLabel" name="label_20">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>y:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QLabel" name="label_21">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>x:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="2">
+       <widget class="QSpinBox" name="inVoxX">
+        <property name="minimumSize">
+         <size>
+          <width>64</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>false</bool>
+        </property>
+        <property name="buttonSymbols">
+         <enum>QAbstractSpinBox::UpDownArrows</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="4">
+       <widget class="QSpinBox" name="inVoxY">
+        <property name="minimumSize">
+         <size>
+          <width>64</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>false</bool>
+        </property>
+        <property name="buttonSymbols">
+         <enum>QAbstractSpinBox::UpDownArrows</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="6">
+       <widget class="QSpinBox" name="inVoxZ">
+        <property name="minimumSize">
+         <size>
+          <width>64</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>false</bool>
+        </property>
+        <property name="buttonSymbols">
+         <enum>QAbstractSpinBox::UpDownArrows</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="2">
+       <widget class="QLineEdit" name="outItkX">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>80</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="4">
+       <widget class="QLineEdit" name="outItkY">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>80</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="6">
+       <widget class="QLineEdit" name="outItkZ">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>80</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="2">
+       <widget class="QLineEdit" name="outNiftiX">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="4">
+       <widget class="QLineEdit" name="outNiftiY">
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="6">
+       <widget class="QLineEdit" name="outNiftiZ">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>0</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>80</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QLabel" name="label_18">
+        <property name="font">
+         <font>
+          <pointsize>9</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>Voxel coordinates</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+        <property name="wordWrap">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_14">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+          <horstretch>1</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>9</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>World (ITK) coordinates</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+        <property name="wordWrap">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="label_22">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+          <horstretch>1</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>9</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>World (NIFTI) coordinates</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+        <property name="wordWrap">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox_5">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="title">
+      <string>Intensity Range</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_3">
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item>
+       <spacer name="horizontalSpacer_5">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QLabel" name="label_23">
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>min:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="outMin">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>96</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>64</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="label_25">
+        <property name="minimumSize">
+         <size>
+          <width>48</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>max:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="outMax">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>96</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>64</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/LabelInspector.cxx b/GUI/Qt/Components/LabelInspector.cxx
new file mode 100644
index 0000000..17e6ed2
--- /dev/null
+++ b/GUI/Qt/Components/LabelInspector.cxx
@@ -0,0 +1,54 @@
+#include "LabelInspector.h"
+#include "ui_LabelInspector.h"
+#include <SNAPQtCommon.h>
+#include "GlobalUIModel.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "QtComboBoxCoupling.h"
+#include "QtCheckBoxCoupling.h"
+#include "QtSliderCoupling.h"
+#include "QtSpinBoxCoupling.h"
+
+LabelInspector::LabelInspector(QWidget *parent) :
+  SNAPComponent(parent),
+  ui(new Ui::LabelInspector)
+{
+  ui->setupUi(this);
+  ui->inForeLabel->setIconSize(QSize(16,16));
+  ui->inBackLabel->setIconSize(QSize(16,16));
+
+  // Connect to the action in the menubar
+  ui->btnEdit->setAction("actionLabel_Editor");
+}
+
+LabelInspector::~LabelInspector()
+{
+  delete ui;
+}
+
+void LabelInspector
+::SetModel(GlobalUIModel *model)
+{
+  // Get the model
+  m_Model = model;
+
+  // Use couplings where we can
+  makeCoupling(ui->inOpacity, m_Model->GetSegmentationOpacityModel());
+  makeCoupling(ui->inOpacityValue, m_Model->GetSegmentationOpacityModel());
+  makeCoupling(ui->chkVisible, m_Model->GetSegmentationVisibilityModel());
+
+  // Couple the color label combo box. The actual logic for how the labels are
+  // mapped to color labels is handled in QtComboBoxCoupling.h
+  makeCoupling(ui->inForeLabel,
+               m_Model->GetGlobalState()->GetDrawingColorLabelModel());
+
+  // Couple the draw over label combo box.
+  makeCoupling(ui->inBackLabel,
+               m_Model->GetGlobalState()->GetDrawOverFilterModel());
+
+  // Couple the inversion checkbox
+  makeCoupling(ui->cbInvert,
+               m_Model->GetGlobalState()->GetPolygonInvertModel());
+}
+
+
diff --git a/GUI/Qt/Components/LabelInspector.h b/GUI/Qt/Components/LabelInspector.h
new file mode 100644
index 0000000..103a55b
--- /dev/null
+++ b/GUI/Qt/Components/LabelInspector.h
@@ -0,0 +1,33 @@
+#ifndef LABELINSPECTOR_H
+#define LABELINSPECTOR_H
+
+#include "SNAPComponent.h"
+
+namespace Ui {
+class LabelInspector;
+}
+
+class LabelInspector : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit LabelInspector(QWidget *parent = 0);
+  ~LabelInspector();
+
+  // Set the model
+  void SetModel(GlobalUIModel *model);
+
+public slots:
+
+private slots:
+
+private:
+
+  Ui::LabelInspector *ui;
+
+  GlobalUIModel *m_Model;
+
+};
+
+#endif // LABELINSPECTOR_H
diff --git a/GUI/Qt/Components/LabelInspector.ui b/GUI/Qt/Components/LabelInspector.ui
new file mode 100644
index 0000000..a725d73
--- /dev/null
+++ b/GUI/Qt/Components/LabelInspector.ui
@@ -0,0 +1,431 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LabelInspector</class>
+ <widget class="QWidget" name="LabelInspector">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>169</width>
+    <height>575</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>16777215</width>
+    <height>16777215</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">*  {
+font-size: 12px;
+}
+
+QAbstractItemView::item {
+  padding:4px;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>-1</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout_2">
+     <property name="spacing">
+      <number>4</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="font">
+        <font>
+         <pointsize>-1</pointsize>
+         <weight>75</weight>
+         <bold>true</bold>
+        </font>
+       </property>
+       <property name="styleSheet">
+        <string notr="true">font-weight:bold;</string>
+       </property>
+       <property name="text">
+        <string>Foreground label</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QComboBox" name="inForeLabel">
+       <property name="styleSheet">
+        <string notr="true">QAbstractItemView::item {
+spacing:10;
+}</string>
+       </property>
+       <property name="editable">
+        <bool>false</bool>
+       </property>
+       <property name="insertPolicy">
+        <enum>QComboBox::InsertAtBottom</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="horizontalLayout_3">
+       <property name="spacing">
+        <number>0</number>
+       </property>
+       <item>
+        <spacer name="horizontalSpacer">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Fixed</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>40</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QLabel" name="label_3">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="styleSheet">
+          <string notr="true">font-size:10px;</string>
+         </property>
+         <property name="text">
+          <string><html><head/><body><p>Label used by drawing <br/>and segmentation tools</p></body></html></string>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout_3">
+     <property name="spacing">
+      <number>4</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="label_2">
+       <property name="font">
+        <font>
+         <pointsize>-1</pointsize>
+         <weight>75</weight>
+         <bold>true</bold>
+        </font>
+       </property>
+       <property name="styleSheet">
+        <string notr="true">font-weight:bold;</string>
+       </property>
+       <property name="text">
+        <string>Background label</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QComboBox" name="inBackLabel"/>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="horizontalLayout_4">
+       <property name="spacing">
+        <number>0</number>
+       </property>
+       <item>
+        <spacer name="horizontalSpacer_2">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Fixed</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>40</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QLabel" name="label_4">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="styleSheet">
+          <string notr="true">font-size:10px;</string>
+         </property>
+         <property name="text">
+          <string><html><head/><body><p>Drawing tools only affect <br/>voxels with this label</p></body></html></string>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_4" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_5">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <spacer name="horizontalSpacer_4">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbInvert">
+        <property name="toolTip">
+         <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Helvetica'; font-size:12px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inverts some segmentation operations, such as polygon drawing, by applying the segmentation to the outside of the drawn region, rather than inside.</p></body></html></string>
+        </property>
+        <property name="text">
+         <string>Draw inverted</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line">
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="lineWidth">
+      <number>1</number>
+     </property>
+     <property name="midLineWidth">
+      <number>1</number>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_4">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="label_6">
+        <property name="font">
+         <font>
+          <pointsize>-1</pointsize>
+          <weight>75</weight>
+          <bold>true</bold>
+         </font>
+        </property>
+        <property name="styleSheet">
+         <string notr="true">font-weight:bold;</string>
+        </property>
+        <property name="text">
+         <string>Label opacity</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_2" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <property name="spacing">
+          <number>4</number>
+         </property>
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QSlider" name="inOpacity">
+           <property name="toolTip">
+            <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Helvetica'; font-size:12px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the overall opacity of segmentation labels.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">[A]: Make more transparent</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">[D]: Make more opaque</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">[S]: Toggle on/off</p></body></html></string>
+           </property>
+           <property name="minimum">
+            <number>0</number>
+           </property>
+           <property name="maximum">
+            <number>100</number>
+           </property>
+           <property name="singleStep">
+            <number>1</number>
+           </property>
+           <property name="pageStep">
+            <number>10</number>
+           </property>
+           <property name="value">
+            <number>50</number>
+           </property>
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="tickPosition">
+            <enum>QSlider::TicksBelow</enum>
+           </property>
+           <property name="tickInterval">
+            <number>25</number>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_3" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout_6">
+         <property name="spacing">
+          <number>0</number>
+         </property>
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QSpinBox" name="inOpacityValue">
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="suffix">
+            <string>%</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_6">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeType">
+            <enum>QSizePolicy::Expanding</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>5</width>
+             <height>17</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="chkVisible">
+           <property name="text">
+            <string>Visible</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line_2">
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="lineWidth">
+      <number>1</number>
+     </property>
+     <property name="midLineWidth">
+      <number>1</number>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QActionButton" name="btnEdit">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="text">
+        <string>Label Editor...</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QActionButton</class>
+   <extends>QPushButton</extends>
+   <header location="global">QActionButton.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/LabelMiniInspector.cxx b/GUI/Qt/Components/LabelMiniInspector.cxx
new file mode 100644
index 0000000..fe8c79f
--- /dev/null
+++ b/GUI/Qt/Components/LabelMiniInspector.cxx
@@ -0,0 +1,52 @@
+#include "LabelMiniInspector.h"
+#include "ui_LabelMiniInspector.h"
+#include <SNAPQtCommon.h>
+#include "GlobalUIModel.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "QtComboBoxCoupling.h"
+#include "QtCheckBoxCoupling.h"
+#include "QtSliderCoupling.h"
+#include "QtSpinBoxCoupling.h"
+#include "QtAbstractButtonCoupling.h"
+
+LabelMiniInspector::LabelMiniInspector(QWidget *parent) :
+  SNAPComponent(parent),
+  ui(new Ui::LabelMiniInspector)
+{
+  ui->setupUi(this);
+  ui->inForeLabel->setIconSize(QSize(16,16));
+  ui->inBackLabel->setIconSize(QSize(16,16));
+}
+
+LabelMiniInspector::~LabelMiniInspector()
+{
+  delete ui;
+}
+
+void LabelMiniInspector
+::SetModel(GlobalUIModel *model)
+{
+  // Get the model
+  m_Model = model;
+
+  // Use couplings where we can
+  makeCoupling(ui->inOpacity, m_Model->GetSegmentationOpacityModel());
+  makeCoupling(ui->inOpacityValue, m_Model->GetSegmentationOpacityModel());
+  makeCoupling((QAbstractButton *)ui->toolButton, m_Model->GetSegmentationVisibilityModel());
+
+  // Couple the color label combo box. The actual logic for how the labels are
+  // mapped to color labels is handled in QtComboBoxCoupling.h
+  makeCoupling(ui->inForeLabel,
+               m_Model->GetGlobalState()->GetDrawingColorLabelModel());
+
+  // Couple the draw over label combo box.
+  makeCoupling(ui->inBackLabel,
+               m_Model->GetGlobalState()->GetDrawOverFilterModel());
+
+  // Couple the inversion checkbox
+  makeCoupling(ui->cbInvert,
+               m_Model->GetGlobalState()->GetPolygonInvertModel());
+}
+
+
diff --git a/GUI/Qt/Components/LabelMiniInspector.h b/GUI/Qt/Components/LabelMiniInspector.h
new file mode 100644
index 0000000..ef5d715
--- /dev/null
+++ b/GUI/Qt/Components/LabelMiniInspector.h
@@ -0,0 +1,33 @@
+#ifndef LABELMINIINSPECTOR_H
+#define LABELMINIINSPECTOR_H
+
+#include "SNAPComponent.h"
+
+namespace Ui {
+class LabelMiniInspector;
+}
+
+class LabelMiniInspector : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit LabelMiniInspector(QWidget *parent = 0);
+  ~LabelMiniInspector();
+
+  // Set the model
+  void SetModel(GlobalUIModel *model);
+
+public slots:
+
+private slots:
+
+private:
+
+  Ui::LabelMiniInspector *ui;
+
+  GlobalUIModel *m_Model;
+
+};
+
+#endif // LABELMINIINSPECTOR_H
diff --git a/GUI/Qt/Components/LabelMiniInspector.ui b/GUI/Qt/Components/LabelMiniInspector.ui
new file mode 100644
index 0000000..2f98411
--- /dev/null
+++ b/GUI/Qt/Components/LabelMiniInspector.ui
@@ -0,0 +1,280 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LabelMiniInspector</class>
+ <widget class="QWidget" name="LabelMiniInspector">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>169</width>
+    <height>171</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>16777215</width>
+    <height>16777215</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">*  {
+font-size: 12px;
+}
+
+QAbstractItemView::item {
+  padding:4px;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>2</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+       <weight>50</weight>
+       <bold>false</bold>
+      </font>
+     </property>
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="text">
+      <string>Foreground label:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QComboBox" name="inForeLabel">
+     <property name="styleSheet">
+      <string notr="true">QAbstractItemView::item {
+spacing:10;
+}</string>
+     </property>
+     <property name="editable">
+      <bool>false</bool>
+     </property>
+     <property name="insertPolicy">
+      <enum>QComboBox::InsertAtBottom</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Fixed</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>4</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_3">
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+      </font>
+     </property>
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="text">
+      <string>Background label:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QComboBox" name="inBackLabel"/>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_4" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_5">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <spacer name="horizontalSpacer_4">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbInvert">
+        <property name="toolTip">
+         <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Helvetica'; font-size:12px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inverts some segmentation operations, such as polygon drawing, by applying the segmentation to the outside of the drawn region, rather than inside.</p></body></html></string>
+        </property>
+        <property name="text">
+         <string>Draw inverted</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_3">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Fixed</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>4</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_4">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="label_4">
+        <property name="font">
+         <font>
+          <pointsize>-1</pointsize>
+         </font>
+        </property>
+        <property name="styleSheet">
+         <string notr="true"/>
+        </property>
+        <property name="text">
+         <string>Overall label opacity:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_2" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <property name="spacing">
+          <number>4</number>
+         </property>
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QSpinBox" name="inOpacityValue">
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="suffix">
+            <string>%</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QSlider" name="inOpacity">
+           <property name="toolTip">
+            <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Helvetica'; font-size:12px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the overall opacity of segmentation labels.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">[A]: Make more transparent</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">[D]: Make more opaque</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">[S]: Toggle on/off</p></body></html></string>
+           </property>
+           <property name="minimum">
+            <number>0</number>
+           </property>
+           <property name="maximum">
+            <number>100</number>
+           </property>
+           <property name="singleStep">
+            <number>1</number>
+           </property>
+           <property name="pageStep">
+            <number>10</number>
+           </property>
+           <property name="value">
+            <number>50</number>
+           </property>
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="tickPosition">
+            <enum>QSlider::TicksBelow</enum>
+           </property>
+           <property name="tickInterval">
+            <number>25</number>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QToolButton" name="toolButton">
+           <property name="text">
+            <string>...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../Resources/SNAPResources.qrc">
+             <normaloff>:/root/popup_delete_16.png</normaloff>
+             <normalon>:/root/popup_ok_16.png</normalon>:/root/popup_delete_16.png</iconset>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <property name="autoRaise">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/LabelSelectionButton.cxx b/GUI/Qt/Components/LabelSelectionButton.cxx
new file mode 100644
index 0000000..9eabbb2
--- /dev/null
+++ b/GUI/Qt/Components/LabelSelectionButton.cxx
@@ -0,0 +1,307 @@
+#include "LabelSelectionButton.h"
+#include "GlobalUIModel.h"
+#include "AbstractModel.h"
+#include "LatentITKEventNotifier.h"
+#include "GlobalState.h"
+#include "IRISApplication.h"
+#include "ColorLabelTable.h"
+#include <QtComboBoxCoupling.h>
+
+#include "SNAPQtCommon.h"
+#include <QPainter>
+#include <QIcon>
+#include <QColor>
+#include <QMenu>
+
+LabelSelectionButton::LabelSelectionButton(QWidget *parent) :
+  QToolButton(parent)
+{
+  LabelSelectionButtonPopupMenu *menu = new LabelSelectionButtonPopupMenu(this);
+  this->setMenu(menu);
+  this->setPopupMode(QToolButton::InstantPopup);
+  this->setIconSize(QSize(22,22));
+}
+
+
+void LabelSelectionButton::SetModel(GlobalUIModel *model)
+{
+  m_Model = model;
+
+  LatentITKEventNotifier::connect(
+        m_Model->GetGlobalState()->GetDrawingColorLabelModel(),
+        IRISEvent(), this, SLOT(onModelUpdate(const EventBucket&)));
+
+  LatentITKEventNotifier::connect(
+        m_Model->GetGlobalState()->GetDrawOverFilterModel(),
+        IRISEvent(), this, SLOT(onModelUpdate(const EventBucket&)));
+
+  LabelSelectionButtonPopupMenu *menu
+      = static_cast<LabelSelectionButtonPopupMenu *>(this->menu());
+  menu->SetModel(model);
+
+  this->UpdateAppearance();
+}
+
+void LabelSelectionButton::onModelUpdate(const EventBucket &bucket)
+{
+  this->UpdateAppearance();
+}
+
+
+void LabelSelectionButton::UpdateAppearance()
+{
+  ColorLabelTable *clt = m_Model->GetDriver()->GetColorLabelTable();
+  LabelType fg = m_Model->GetGlobalState()->GetDrawingColorLabel();
+  DrawOverFilter bg = m_Model->GetGlobalState()->GetDrawOverFilter();
+
+  // Draw a split button
+  this->setIcon(CreateLabelComboIcon(22, 22, fg, bg, clt));
+
+  // Update the tooltip
+  this->setToolTip(CreateLabelComboTooltip(fg, bg, clt));
+}
+
+
+/*
+void LabelSelectionButton::UpdateAppearanceOld()
+{
+  int w = 16;
+
+  QPixmap pm(w, w);
+  QPainter qp(&pm);
+
+  QPolygon poly_fg, poly_bg;
+  poly_fg << QPoint(0, 0) << QPoint(w-1,0) << QPoint(0,w-1) << QPoint(0,0);
+  poly_bg << QPoint(0, 0) << QPoint(w-1,0) << QPoint(w-1,w-1) << QPoint(0,w-1) << QPoint(0,0);
+
+  LabelType fg = m_Model->GetGlobalState()->GetDrawingColorLabel();
+  DrawOverFilter bg = m_Model->GetGlobalState()->GetDrawOverFilter();
+  ColorLabel lfg = m_Model->GetDriver()->GetColorLabelTable()->GetColorLabel(fg);
+  ColorLabel lbg = m_Model->GetDriver()->GetColorLabelTable()->GetColorLabel(bg.DrawOverLabel);
+
+  QBrush brush_fg(QColor(lfg.GetRGB(0), lfg.GetRGB(1), lfg.GetRGB(2)));
+  QBrush brush_bg(QColor(lbg.GetRGB(0), lbg.GetRGB(1), lbg.GetRGB(2)));
+
+  qp.setPen(Qt::black);
+  qp.setBrush(brush_bg);
+  qp.drawPolygon(poly_bg);
+
+  qp.setBrush(brush_fg);
+  qp.drawPolygon(poly_fg);
+
+  // Draw a split button
+  this->setIcon(QIcon(pm));
+}
+*/
+
+#include "ColorLabelQuickListWidget.h"
+#include <QWidgetAction>
+#include <QVBoxLayout>
+#include <QLabel>
+
+class ColorLabelQuickListWidgetAction : public QWidgetAction
+{
+public:
+  ColorLabelQuickListWidgetAction(QWidget *parent)
+    : QWidgetAction(parent)
+  {
+    QWidget *topWidget = new QWidget(parent);
+    QVBoxLayout *lo = new QVBoxLayout(topWidget);
+    lo->setContentsMargins(4,4,4,4);
+    lo->setSpacing(2);
+
+    m_Widget = new ColorLabelQuickListWidget(parent);
+
+    lo->addWidget(new QLabel("Quick palette:"),0,Qt::AlignLeft);
+    lo->addWidget(m_Widget, 0, Qt::AlignCenter);
+
+    this->setDefaultWidget(topWidget);
+  }
+
+  irisGetMacro(Widget, ColorLabelQuickListWidget *)
+
+protected:
+  ColorLabelQuickListWidget *m_Widget;
+};
+
+
+LabelSelectionButtonPopupMenu::LabelSelectionButtonPopupMenu(QWidget *parent)
+  : QMenu(parent)
+{
+  // Add the foreground and background label selectors
+  m_SubForeground = this->addMenu("Foreground Label");
+  m_SubBackground = this->addMenu("Background Label");
+  this->addSeparator();
+
+  // Create a QAction wrapped around the recent labels menu
+  ColorLabelQuickListWidgetAction *action = new ColorLabelQuickListWidgetAction(this);
+  this->m_Recent = action->GetWidget();
+  this->addAction(action);
+  this->addSeparator();
+
+  // Label editor window
+  this->addAction(FindUpstreamAction(this, "actionLabel_Editor"));
+
+  this->setStyleSheet("font-size: 12px;");
+
+  connect(m_SubForeground, SIGNAL(triggered(QAction*)), SLOT(onForegroundAction(QAction*)));
+  connect(m_SubBackground, SIGNAL(triggered(QAction*)), SLOT(onBackgroundAction(QAction*)));
+
+  connect(m_Recent, SIGNAL(actionTriggered(QAction*)), this, SLOT(close()));
+
+}
+
+void LabelSelectionButtonPopupMenu::SetModel(GlobalUIModel *model)
+{
+  m_Model = model;
+
+  // Listen to changes in active label, active label set
+  LatentITKEventNotifier::connect(
+        model->GetGlobalState()->GetDrawingColorLabelModel(),
+        IRISEvent(), this, SLOT(onModelUpdate(const EventBucket &)));
+
+  LatentITKEventNotifier::connect(
+        model->GetGlobalState()->GetDrawOverFilterModel(),
+        IRISEvent(), this, SLOT(onModelUpdate(const EventBucket &)));
+
+  // Configure the recents menu
+  m_Recent->SetModel(model);
+
+  this->UpdateMenu();
+
+  // Update the timestamp
+  m_LastUpdateTime.Modified();
+}
+
+
+void LabelSelectionButtonPopupMenu::UpdateMenu()
+{
+  m_SubForeground->clear();
+  m_SubBackground->clear();
+  ColorLabelTable *clt = m_Model->GetDriver()->GetColorLabelTable();
+
+  DrawOverFilter dof[] = {
+    DrawOverFilter(PAINT_OVER_ALL, 0),
+    DrawOverFilter(PAINT_OVER_VISIBLE, 0) };
+
+  for(int i = 0; i < 2; i++)
+    {
+    QIcon icon = CreateColorBoxIcon(16, 16, GetBrushForDrawOverFilter(dof[i], clt));
+    QString name = GetTitleForDrawOverFilter(dof[i], clt);
+    QAction *action = m_SubBackground->addAction(icon, name);
+    action->setData(QVariant::fromValue(dof[i]));
+    action->setCheckable(true);
+    }
+  m_SubBackground->addSeparator();
+
+  typedef ColorLabelTable::ValidLabelMap ValidMap;
+  const ColorLabelTable::ValidLabelMap &vmap = clt->GetValidLabels();
+  for(ValidMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it)
+    {
+    const ColorLabel &cl = it->second;
+    QIcon icon = CreateColorBoxIcon(16, 16, GetBrushForColorLabel(cl));
+    QString name = GetTitleForColorLabel(cl);
+
+    QAction *action_fg = m_SubForeground->addAction(icon, name);
+    action_fg->setData(it->first);
+    action_fg->setCheckable(true);
+
+    QAction *action_bg = m_SubBackground->addAction(icon, name);
+    action_bg->setData(
+          QVariant::fromValue(DrawOverFilter(PAINT_OVER_ONE, it->first)));
+    action_bg->setCheckable(true);
+    }
+}
+
+void LabelSelectionButtonPopupMenu::UpdateCurrents()
+{
+  ColorLabelTable *clt = m_Model->GetDriver()->GetColorLabelTable();
+  LabelType fg = m_Model->GetGlobalState()->GetDrawingColorLabel();
+  DrawOverFilter bg = m_Model->GetGlobalState()->GetDrawOverFilter();
+
+  // Go through and check/uncheck all actions
+  QList<QAction *> afg = m_SubForeground->actions();
+  for(int i = 0; i < afg.size(); i++)
+    {
+    QAction *action = afg.at(i);
+    int label = action->data().toInt();
+    const ColorLabel &cl = clt->GetColorLabel(label);
+
+    // Check if the color label has updated
+    if(cl.GetTimeStamp() > m_LastUpdateTime)
+      {
+      action->setIcon(CreateColorBoxIcon(16, 16, GetBrushForColorLabel(cl)));
+      action->setText(GetTitleForColorLabel(cl));
+      }
+
+    if(label == fg)
+      {
+      action->setChecked(true);
+      m_SubForeground->setIcon(action->icon());
+      }
+    else
+      {
+      action->setChecked(false);
+      }
+    }
+
+  // Go through and check/uncheck all actions
+  QList<QAction *> abg = m_SubBackground->actions();
+  for(int i = 0; i < abg.size(); i++)
+    {
+    QAction *action = abg.at(i);
+    if(action->isSeparator())
+      continue;
+    DrawOverFilter dfi = qvariant_cast<DrawOverFilter>(action->data());
+
+    if(dfi.CoverageMode == PAINT_OVER_ONE)
+      {
+      const ColorLabel &cl = clt->GetColorLabel(dfi.DrawOverLabel);
+
+      // Check if the color label has updated
+      if(cl.GetTimeStamp() > m_LastUpdateTime)
+        {
+        action->setIcon(CreateColorBoxIcon(16, 16, GetBrushForColorLabel(cl)));
+        action->setText(GetTitleForColorLabel(cl));
+        }
+      }
+
+    if(dfi == bg)
+      {
+      action->setChecked(true);
+      m_SubBackground->setIcon(action->icon());
+      }
+    else
+      {
+      action->setChecked(false);
+      }
+    }
+
+  m_LastUpdateTime.Modified();
+}
+
+void LabelSelectionButtonPopupMenu::onModelUpdate(const EventBucket &bucket)
+{
+  if(bucket.HasEvent(DomainChangedEvent()))
+    {
+    this->UpdateMenu();
+    this->UpdateCurrents();
+    }
+  else if(bucket.HasEvent(ValueChangedEvent()) || bucket.HasEvent(DomainDescriptionChangedEvent()))
+    {
+    this->UpdateCurrents();
+    }
+}
+
+void LabelSelectionButtonPopupMenu::onForegroundAction(QAction *action)
+{
+  int label = action->data().toInt();
+  m_Model->GetGlobalState()->SetDrawingColorLabel(label);
+}
+
+void LabelSelectionButtonPopupMenu::onBackgroundAction(QAction *action)
+{
+  DrawOverFilter dof = qvariant_cast<DrawOverFilter>(action->data());
+  m_Model->GetGlobalState()->SetDrawOverFilter(dof);
+}
+
diff --git a/GUI/Qt/Components/LabelSelectionButton.h b/GUI/Qt/Components/LabelSelectionButton.h
new file mode 100644
index 0000000..e1a20c7
--- /dev/null
+++ b/GUI/Qt/Components/LabelSelectionButton.h
@@ -0,0 +1,73 @@
+#ifndef LABELSELECTIONBUTTON_H
+#define LABELSELECTIONBUTTON_H
+
+#include <QToolButton>
+#include <QMenu>
+#include <QWidgetAction>
+#include "itkTimeStamp.h"
+
+class GlobalUIModel;
+class EventBucket;
+class ColorLabelQuickListWidget;
+
+class LabelSelectionButtonRecentPanel : public QWidgetAction
+{
+
+};
+
+class LabelSelectionButtonPopupMenu : public QMenu
+{
+  Q_OBJECT
+
+public:
+  LabelSelectionButtonPopupMenu(QWidget *parent);
+
+  void SetModel(GlobalUIModel *model);
+
+public slots:
+
+  void onModelUpdate(const EventBucket &bucket);
+  void onForegroundAction(QAction *action);
+  void onBackgroundAction(QAction *action);
+
+protected:
+  void UpdateMenu();
+  void UpdateCurrents();
+
+  QMenu *m_SubForeground, *m_SubBackground;
+  ColorLabelQuickListWidget *m_Recent;
+  GlobalUIModel *m_Model;
+  itk::TimeStamp m_LastUpdateTime;
+};
+
+/**
+ * @brief The LabelSelectionButton class
+ * This is an attempt to create a nice looking button with a menu that can
+ * be used to select labels. The button, when pressed, shows a menu where
+ * the user can quickly choose among available labels, including recently
+ * used labels.
+ */
+class LabelSelectionButton : public QToolButton
+{
+  Q_OBJECT
+public:
+  explicit LabelSelectionButton(QWidget *parent = 0);
+
+  void SetModel(GlobalUIModel *model);
+  
+signals:
+  
+public slots:
+
+  void onModelUpdate(const EventBucket &bucket);
+  
+
+protected:
+
+  GlobalUIModel *m_Model;
+
+
+  void UpdateAppearance();
+};
+
+#endif // LABELSELECTIONBUTTON_H
diff --git a/GUI/Qt/Components/LatentITKEventNotifier.cxx b/GUI/Qt/Components/LatentITKEventNotifier.cxx
new file mode 100644
index 0000000..d31a075
--- /dev/null
+++ b/GUI/Qt/Components/LatentITKEventNotifier.cxx
@@ -0,0 +1,186 @@
+#include "LatentITKEventNotifier.h"
+#include <itkObject.h>
+#include <QApplication>
+#include <SNAPEventListenerCallbacks.h>
+
+LatentITKEventNotifierCleanup
+::LatentITKEventNotifierCleanup(QObject *parent)
+  : QObject(parent)
+{
+  m_Source = NULL;
+}
+
+LatentITKEventNotifierCleanup
+::~LatentITKEventNotifierCleanup()
+{
+  if(m_Source)
+    {
+    m_Source->RemoveObserver(m_Tag);
+    m_Source->RemoveObserver(m_DeleteTag);
+    }
+}
+
+void
+LatentITKEventNotifierCleanup
+::SetSource(itk::Object *source, unsigned long tag)
+{
+  // Store the source
+  m_Source = source;
+  m_Tag = tag;
+
+  // Listen for delete events on the source
+  m_DeleteTag = AddListenerConst(
+        source, itk::DeleteEvent(),
+        this, &LatentITKEventNotifierCleanup::DeleteCallback);
+}
+
+void
+LatentITKEventNotifierCleanup
+::DeleteCallback(const itk::Object *object, const itk::EventObject &evt)
+{
+#ifdef SNAP_DEBUG_EVENTS
+  if(flag_snap_debug_events)
+    {
+    std::cout << "DELETE CALLBACK from " << object->GetNameOfClass()
+              << " [" << typeid(*object).name() << "]"
+              << " event " << evt.GetEventName() << std::endl << std::flush;
+    }
+#endif
+  // Forget the source.
+  m_Source = NULL;
+}
+
+
+
+
+LatentITKEventNotifierHelper
+::LatentITKEventNotifierHelper(QObject *parent)
+  : QObject(parent)
+{
+  // Emitting itkEvent will result in onQueuedEvent being called when
+  // control returns to the main Qt loop
+  QObject::connect(this, SIGNAL(itkEvent()),
+                   this, SLOT(onQueuedEvent()),
+                   Qt::QueuedConnection);
+}
+
+void
+LatentITKEventNotifierHelper
+::Callback(itk::Object *object, const itk::EventObject &evt)
+{
+#ifdef SNAP_DEBUG_EVENTS
+  if(flag_snap_debug_events)
+    {
+    std::cout << "QUEUE Event " << evt.GetEventName()
+              << " from " << object->GetNameOfClass()
+              << " [" << object << "] "
+              << " for " << parent()->metaObject()->className()
+              << " named '" << qPrintable(parent()->objectName())
+              << "'" << std::endl << std::flush;
+    }
+#endif
+
+  // Register this event
+  m_Bucket.PutEvent(evt, object);
+
+  // Emit signal
+  emit itkEvent();
+
+  // Call parent's update
+  // QApplication::postEvent(this, new QEvent(QEvent::User), 1000);
+}
+
+void
+LatentITKEventNotifierHelper
+::onQueuedEvent()
+{
+  static int invocation = 0;
+  if(!m_Bucket.IsEmpty())
+    {
+#ifdef SNAP_DEBUG_EVENTS
+    if(flag_snap_debug_events)
+      {
+      std::cout << "SEND " << m_Bucket
+                << " to " << parent()->metaObject()->className()
+                << " named '" << qPrintable(parent()->objectName())
+                << "'" << std::endl << std::flush;
+      }
+#endif
+
+    ++invocation;
+
+    // Send the event to the target object - immediate
+    emit dispatchEvent(m_Bucket);
+
+    // Empty the bucket, so the rest of the events are ignored
+    m_Bucket.Clear();
+    }
+}
+
+/*
+bool
+LatentITKEventNotifierHelper
+::event(QEvent *event)
+{
+  if(event->type() == QEvent::User)
+    {
+    if(!m_Bucket.IsEmpty())
+      {
+      // Send the event to the target object - immediate
+      emit dispatchEvent(m_Bucket);
+
+      // Empty the bucket, so the rest of the events are ignored
+      m_Bucket.Clear();
+      }
+    return true;
+    }
+  else return false;
+}
+*/
+
+void LatentITKEventNotifier
+::connect(itk::Object *source, const itk::EventObject &evt,
+          QObject *target, const char *slot)
+{
+  // Call common implementation
+  LatentITKEventNotifierHelper *c = doConnect(evt, target, slot);
+
+  // Listen to events from the source
+  unsigned long tag = AddListener(source, evt, c,
+                                  &LatentITKEventNotifierHelper::Callback);
+
+  // Create an cleaner as a child of the helper
+  LatentITKEventNotifierCleanup *clean = new LatentITKEventNotifierCleanup(c);
+  clean->SetSource(source, tag);
+}
+
+LatentITKEventNotifierHelper*
+LatentITKEventNotifier
+::doConnect(const itk::EventObject &evt, QObject *target, const char *slot)
+{
+  // It is possible that there is already a helper attached to the target
+  // object. In that case, we can economize by reusing that helper
+  LatentITKEventNotifierHelper *c =
+      target->findChild<LatentITKEventNotifierHelper *>();
+
+  if(!c)
+    {
+    // Here the helper becomes property of QObject target, so that if the
+    // target is deleted, the helper will also go away
+    c = new LatentITKEventNotifierHelper(target);
+    }
+
+  // Connect to the target qobject
+  QObject::connect(c, SIGNAL(dispatchEvent(const EventBucket &)), target, slot);
+
+  return c;
+}
+
+void LatentITKEventNotifier
+::disconnect(itk::Object *source, unsigned long tag)
+{
+  source->RemoveObserver(tag);
+}
+
+
+
diff --git a/GUI/Qt/Components/LatentITKEventNotifier.h b/GUI/Qt/Components/LatentITKEventNotifier.h
new file mode 100644
index 0000000..66822c6
--- /dev/null
+++ b/GUI/Qt/Components/LatentITKEventNotifier.h
@@ -0,0 +1,88 @@
+#ifndef LATENTITKEVENTNOTIFIER_H
+#define LATENTITKEVENTNOTIFIER_H
+
+#include <QObject>
+#include "EventBucket.h"
+#include <map>
+
+class LatentITKEventNotifierHelper : public QObject
+{
+  Q_OBJECT
+
+public:
+  explicit LatentITKEventNotifierHelper(QObject *parent = 0);
+
+  void Callback(itk::Object *object, const itk::EventObject &evt);
+  // bool event(QEvent *event);
+
+public slots:
+  void onQueuedEvent();
+
+signals:
+  void itkEvent();
+  void dispatchEvent(const EventBucket &bucket);
+
+protected:
+  EventBucket m_Bucket;
+};
+
+/**
+  This object is in charge of cleaning up when the parent QObject is deleted.
+  This makes sure that the itk::Object being observed does not try to send
+  commands to a non-existing observer. It also makes sure that if the source
+  itk::Object is deleted, it will not be accessed
+  */
+class LatentITKEventNotifierCleanup : public QObject
+{
+  Q_OBJECT
+
+public:
+  explicit LatentITKEventNotifierCleanup(QObject *parent = 0);
+  ~LatentITKEventNotifierCleanup();
+
+  void SetSource(itk::Object *source, unsigned long tag);
+
+  void DeleteCallback(const itk::Object *object, const itk::EventObject &evt);
+
+protected:
+  itk::Object *m_Source;
+  unsigned long m_Tag, m_DeleteTag;
+};
+
+
+/**
+  This class is used to hook up Qt widgets to the itk event system used
+  by the upstream objects.
+  */
+class LatentITKEventNotifier
+{
+public:
+
+  /**
+    Map itk events originating from object source to a slot in the object
+    target. The signature of slot is void mySlot(const EventBucket &b).
+    The slot will be called after the control has returned to the Qt
+    main loop, and until then, events fired by the source object are
+    pooled into a bucket. This bucket will be passed to the slot.
+
+    Connection is handled by a helper object that becomes the child of the
+    target qWidget. This helper object will automatically disconnect from
+    the target object if the target qWidget is destroyed. The helper object
+    will also automatically disappear if the source itk::Object is deleted.
+    */
+  static void connect(itk::Object *source,
+                      const itk::EventObject &evt,
+                      QObject *target,
+                      const char *slot);
+
+  static void disconnect(itk::Object *source, unsigned long tag);
+
+private:
+
+  static LatentITKEventNotifierHelper *doConnect(
+      const itk::EventObject &evt, QObject *target, const char *slot);
+
+};
+
+
+#endif // LATENTITKEVENTNOTIFIER_H
diff --git a/GUI/Qt/Components/LayerInspectorRowDelegate.cxx b/GUI/Qt/Components/LayerInspectorRowDelegate.cxx
new file mode 100644
index 0000000..e33c50f
--- /dev/null
+++ b/GUI/Qt/Components/LayerInspectorRowDelegate.cxx
@@ -0,0 +1,473 @@
+#include "LayerInspectorRowDelegate.h"
+#include "ui_LayerInspectorRowDelegate.h"
+
+#include "ImageWrapperBase.h"
+#include "LayerTableRowModel.h"
+#include "SNAPQtCommon.h"
+#include "QtAbstractButtonCoupling.h"
+#include "QtLabelCoupling.h"
+#include "QtSliderCoupling.h"
+#include "QtActionGroupCoupling.h"
+#include <QGraphicsOpacityEffect>
+#include <QPropertyAnimation>
+#include <QFile>
+#include <QMenu>
+#include <QContextMenuEvent>
+#include "QtWidgetActivator.h"
+#include "GlobalUIModel.h"
+#include "ImageIODelegates.h"
+#include "ImageIOWizard.h"
+#include "MainImageWindow.h"
+#include "SaveModifiedLayersDialog.h"
+
+#include "DisplayMappingPolicy.h"
+#include "ColorMap.h"
+#include "ColorMapModel.h"
+
+class QAction;
+
+QString LayerInspectorRowDelegate::m_SliderStyleSheetTemplate;
+
+LayerInspectorRowDelegate::LayerInspectorRowDelegate(QWidget *parent) :
+  SNAPComponent(parent),
+  ui(new Ui::LayerInspectorRowDelegate)
+{
+  ui->setupUi(this);
+
+  // Confirugre the popup menu
+  m_PopupMenu = new QMenu(this);
+  m_PopupMenu->setStyleSheet("font-size:11px;");
+
+  // Add the save/close actions
+  m_PopupMenu->addAction(ui->actionSave);
+  m_PopupMenu->addAction(ui->actionClose);
+  m_PopupMenu->addSeparator();
+  m_PopupMenu->addAction(ui->actionAutoContrast);
+
+  // Add the color map menu
+  m_ColorMapMenu = m_PopupMenu->addMenu("Color Map");
+  m_SystemPresetActionGroup = NULL;
+
+  // Add the component selection menu
+  m_DisplayModeMenu = m_PopupMenu->addMenu("Multi-Component Display");
+  m_DisplayModeActionGroup = NULL;
+
+  // set up an event filter
+  ui->inLayerOpacity->installEventFilter(this);
+
+  // Load the style sheet template
+  if(!m_SliderStyleSheetTemplate.length())
+    {
+    QFile qf(":/root/fancyslider.css");
+    if(qf.open(QFile::ReadOnly))
+      {
+      m_SliderStyleSheetTemplate = QString(qf.readAll());
+      }
+    }
+
+  // Initialize the state
+  m_Selected = false;
+  m_Hover = false;
+  ui->stack->setCurrentWidget(ui->pageBlank);
+  UpdateBackgroundPalette();
+}
+
+LayerInspectorRowDelegate::~LayerInspectorRowDelegate()
+{
+  delete ui;
+}
+
+void LayerInspectorRowDelegate::SetModel(LayerTableRowModel *model)
+{
+  m_Model = model;
+
+  makeCoupling(ui->inLayerOpacity, model->GetLayerOpacityModel());
+  makeCoupling(ui->outLayerNickname, model->GetNicknameModel());
+  makeCoupling(ui->outComponent, model->GetComponentNameModel());
+
+  makeCoupling((QAbstractButton *) ui->btnSticky, model->GetStickyModel());
+  makeCoupling((QAbstractButton *) ui->btnVisible, model->GetVisibilityToggleModel());
+
+  // Hook up some activations
+  activateOnFlag(ui->btnVisible, model, LayerTableRowModel::UIF_OPACITY_EDITABLE);
+  activateOnFlag(ui->inLayerOpacity, model, LayerTableRowModel::UIF_OPACITY_EDITABLE);
+  activateOnFlag(ui->btnSticky, model, LayerTableRowModel::UIF_PINNABLE);
+  activateOnFlag(ui->btnMoveUp, model, LayerTableRowModel::UIF_MOVABLE_UP);
+  activateOnFlag(ui->btnMoveDown, model, LayerTableRowModel::UIF_MOVABLE_DOWN);
+  activateOnFlag(ui->actionClose, model, LayerTableRowModel::UIF_CLOSABLE);
+  activateOnFlag(ui->actionAutoContrast, model, LayerTableRowModel::UIF_CONTRAST_ADJUSTABLE);
+  activateOnFlag(m_ColorMapMenu, model, LayerTableRowModel::UIF_COLORMAP_ADJUSTABLE);
+  activateOnFlag(m_DisplayModeMenu, model, LayerTableRowModel::UIF_MULTICOMPONENT);
+
+  // Hook up the colormap and the slider's style sheet
+  connectITK(m_Model->GetLayer(), WrapperChangeEvent());
+  OnNicknameUpdate();
+  ApplyColorMap();
+
+  // Listen to preset changes from the color map model
+  connectITK(m_Model->GetParentModel()->GetColorMapModel(),
+             ColorMapModel::PresetUpdateEvent());
+
+  // Update the color map menu
+  UpdateColorMapMenu();
+
+  // Update the component menu
+  UpdateComponentMenu();
+
+  // The page shown in this widget depends on whether the visibility editing
+  // is on or off
+  connectITK(m_Model->GetParentModel()->GetLayerVisibilityEditableModel(),
+             ValueChangedEvent());
+  UpdateVisibilityControls();
+}
+
+ImageWrapperBase *LayerInspectorRowDelegate::GetLayer() const
+{
+  // No model? No layer.
+  if(!m_Model)
+    return NULL;
+
+  // Must update the model, because the layer might have been deleted
+  // and we must make sure that we return a clean layer
+  m_Model->Update();
+  return m_Model->GetLayer();
+}
+
+void LayerInspectorRowDelegate::UpdateBackgroundPalette()
+{
+  // Set up a pallete for the background
+  QPalette* palette = new QPalette();
+  QLinearGradient linearGradient(QPointF(0, 0), QPointF(0, this->height()));
+
+  if(m_Selected && m_Hover)
+    {
+    linearGradient.setColorAt(0, QColor(180,180,215));
+    linearGradient.setColorAt(1, QColor(200,200,235));
+    }
+  else if(m_Selected)
+    {
+    linearGradient.setColorAt(0, QColor(190,190,225));
+    linearGradient.setColorAt(1, QColor(210,210,245));
+    }
+  else if(m_Hover)
+    {
+    linearGradient.setColorAt(0, QColor(225,225,235));
+    linearGradient.setColorAt(1, QColor(245,245,255));
+    }
+  else
+    {
+    linearGradient.setColorAt(0, QColor(235,235,235));
+    linearGradient.setColorAt(1, QColor(255,255,255));
+    }
+
+  palette->setBrush(QPalette::Window, *(new QBrush(linearGradient)));
+  ui->frame->setPalette(*palette);
+
+  // Also set the font for the label
+  if(ui->outLayerNickname->font().bold() != m_Selected)
+    {
+    QFont font = ui->outLayerNickname->font();
+    font.setBold(m_Selected);
+    ui->outLayerNickname->setFont(font);
+    }
+}
+
+void LayerInspectorRowDelegate::setSelected(bool value)
+{
+  if(m_Selected != value)
+    {
+    m_Selected = value;
+    emit selectionChanged(value);
+
+    // Update the look and feel
+    this->UpdateBackgroundPalette();
+    }
+}
+
+QAction *LayerInspectorRowDelegate::saveAction() const
+{
+  return ui->actionSave;
+}
+
+QAction *LayerInspectorRowDelegate::closeAction() const
+{
+  return ui->actionClose;
+}
+
+QMenu *LayerInspectorRowDelegate::contextMenu() const
+{
+  return this->m_PopupMenu;
+}
+
+void LayerInspectorRowDelegate::enterEvent(QEvent *)
+{
+  m_Hover = true;
+  this->UpdateBackgroundPalette();
+}
+
+void LayerInspectorRowDelegate::leaveEvent(QEvent *)
+{
+  m_Hover = false;
+  this->UpdateBackgroundPalette();
+}
+
+void LayerInspectorRowDelegate::mousePressEvent(QMouseEvent *)
+{
+  this->setSelected(true);
+}
+
+void LayerInspectorRowDelegate::mouseReleaseEvent(QMouseEvent *)
+{
+  this->setSelected(true);
+}
+
+void LayerInspectorRowDelegate::contextMenuEvent(QContextMenuEvent *evt)
+{
+  m_PopupMenu->popup(evt->globalPos());
+}
+
+bool LayerInspectorRowDelegate::eventFilter(QObject *, QEvent *evt)
+{
+  if(evt->type() == QEvent::FocusIn)
+    {
+    if(!this->selected())
+      {
+      this->setSelected(true);
+      return true;
+      }
+    }
+
+  if(evt->type() == QEvent::MouseButtonPress)
+    {
+    if(!this->selected())
+      this->setSelected(true);
+    return false;
+    }
+
+
+  return false;
+}
+
+void LayerInspectorRowDelegate::UpdateVisibilityControls()
+{  
+  if(m_Model->GetParentModel()->GetLayerVisibilityEditable())
+    {
+    ui->stack->setCurrentWidget(ui->pageControls);
+    }
+  else
+    {
+    ui->stack->setCurrentWidget(ui->pageBlank);
+    }
+}
+
+void LayerInspectorRowDelegate::UpdateColorMapMenu()
+{
+  // The presets are available from the color map model. We can use them
+  // regardless of the row that is currently selected
+  ColorMapModel *cmm = m_Model->GetParentModel()->GetColorMapModel();
+  ColorMapPresetManager *pm = cmm->GetPresetManager();
+
+  // Get the system and user presets
+  ColorMapModel::PresetList pSystem, pUser;
+  cmm->GetPresets(pSystem, pUser);
+
+  // Remove all of the existing actions
+  m_ColorMapMenu->clear();
+  if(m_SystemPresetActionGroup)
+    delete m_SystemPresetActionGroup;
+
+  // Create a map from preset names to actions
+  std::map<std::string, QAction *> actionMap;
+
+  // Add all of the system presets
+  m_SystemPresetActionGroup = new QActionGroup(this);
+
+  // Create the actions for the system presets
+  for(unsigned int i = 0; i < pSystem.size(); i++)
+    {
+    QIcon icon = CreateColorMapIcon(16, 16, pm->GetPreset(pSystem[i]));
+    QAction *action = m_SystemPresetActionGroup->addAction(icon, from_utf8(pSystem[i]));
+    action->setCheckable(true);
+    actionMap[pSystem[i]] = action;
+    }
+
+  // Add a separator to the action group
+  m_SystemPresetActionGroup->addAction("")->setSeparator(true);
+
+  // Add the user presets to the action group
+  for(unsigned int i = 0; i < pUser.size(); i++)
+    {
+    QIcon icon = CreateColorMapIcon(16, 16, pm->GetPreset(pUser[i]));
+    QAction *action = m_SystemPresetActionGroup->addAction(icon, from_utf8(pUser[i]));
+    action->setCheckable(true);
+    actionMap[pUser[i]] = action;
+    }
+
+  // Connect the action group to the model
+  makeActionGroupCoupling(m_SystemPresetActionGroup,
+                          actionMap,
+                          m_Model->GetColorMapPresetModel());
+
+  // Add the action group to the menu
+  m_ColorMapMenu->addActions(m_SystemPresetActionGroup->actions());
+}
+
+void LayerInspectorRowDelegate::UpdateComponentMenu()
+{
+  m_DisplayModeMenu->clear();
+
+  if(m_DisplayModeActionGroup)
+    delete m_DisplayModeActionGroup;
+
+  // Create a map from display modes to actions
+  std::map<MultiChannelDisplayMode, QAction *> actionMap;
+
+  // Add all of the system presets
+  m_DisplayModeActionGroup = new QActionGroup(this);
+
+  // Get the list of all available display modes from the model
+  const LayerTableRowModel::DisplayModeList &modes = m_Model->GetAvailableDisplayModes();
+
+  // Create the actions for the display modes
+  LayerTableRowModel::DisplayModeList::const_iterator it;
+  for(it = modes.begin(); it != modes.end(); it++)
+    {
+    MultiChannelDisplayMode mode = *it;
+
+    // Insert some separators into the menu
+    if(mode.SelectedScalarRep == SCALAR_REP_MAGNITUDE || mode.UseRGB)
+      m_DisplayModeMenu->addSeparator();
+
+    // Create an action
+    QAction *action = m_DisplayModeMenu->addAction(
+          from_utf8(m_Model->GetDisplayModeString(mode)));
+
+    action->setCheckable(true);
+
+    m_DisplayModeActionGroup->addAction(action);
+
+    actionMap[mode] = action;
+    }
+
+  // Hook up with the ctions
+  makeActionGroupCoupling(m_DisplayModeActionGroup, actionMap,
+                          m_Model->GetDisplayModeModel());
+}
+
+
+void LayerInspectorRowDelegate::OnNicknameUpdate()
+{
+  // Update things that depend on the nickname
+  QString name = from_utf8(m_Model->GetNickname());
+  ui->actionSave->setText(QString("Save image \"%1\" ...").arg(name));
+  ui->actionSave->setToolTip(ui->actionSave->text());
+  ui->actionClose->setText(QString("Close image \"%1\"").arg(name));
+  ui->actionClose->setToolTip(ui->actionClose->text());
+  ui->outLayerNickname->setToolTip(name);
+
+}
+
+void LayerInspectorRowDelegate::onModelUpdate(const EventBucket &bucket)
+{
+  if(bucket.HasEvent(WrapperDisplayMappingChangeEvent()))
+    {
+    this->ApplyColorMap();
+    }
+  if(bucket.HasEvent(WrapperMetadataChangeEvent()))
+    {
+    this->OnNicknameUpdate();
+    }
+  if(bucket.HasEvent(ValueChangedEvent()))
+    {
+    this->UpdateVisibilityControls();
+    }
+  if(bucket.HasEvent(ColorMapModel::PresetUpdateEvent()))
+    {
+    this->UpdateColorMapMenu();
+    }
+}
+
+void LayerInspectorRowDelegate::mouseMoveEvent(QMouseEvent *)
+{
+  this->setSelected(true);
+}
+
+void LayerInspectorRowDelegate::ApplyColorMap()
+{
+  ColorMap *cm = m_Model->GetLayer()->GetDisplayMapping()->GetColorMap();
+  if(cm)
+    {
+    QStringList stops;
+    for(int i = 0; i < cm->GetNumberOfCMPoints(); i++)
+      {
+      ColorMap::CMPoint cmp = cm->GetCMPoint(i);
+      for(int side = 0; side < 2; side++)
+        {
+        if((i == 0 && side == 0) ||
+           (i == cm->GetNumberOfCMPoints()-1 && side == 1) ||
+           (cmp.m_Type == ColorMap::CONTINUOUS && side == 1))
+          continue;
+
+        QString cmstr = QString("stop: %1 rgba(%2, %3, %4, %5)")
+            .arg(cmp.m_Index)
+            .arg(cmp.m_RGBA[side][0]).arg(cmp.m_RGBA[side][1])
+            .arg(cmp.m_RGBA[side][2]).arg(cmp.m_RGBA[side][3]);
+        stops << cmstr;
+        }
+      }
+    QString gradient = QString("qlineargradient(x1:0, y1:0, x2:1, y2:0, %1);")
+        .arg(stops.join(","));
+
+    QString stylesheet = m_SliderStyleSheetTemplate;
+    stylesheet.replace("#gradient#", gradient);
+    ui->inLayerOpacity->setStyleSheet(stylesheet);
+    }
+}
+
+void LayerInspectorRowDelegate::on_btnMenu_pressed()
+{
+  m_PopupMenu->popup(QCursor::pos());
+  ui->btnMenu->setDown(false);
+}
+
+void LayerInspectorRowDelegate::on_btnMoveUp_clicked()
+{
+  m_Model->MoveLayerUp();
+}
+
+void LayerInspectorRowDelegate::on_btnMoveDown_pressed()
+{
+  m_Model->MoveLayerDown();
+}
+
+void LayerInspectorRowDelegate::on_actionSave_triggered()
+{
+  // Create a model for IO
+  SmartPtr<ImageIOWizardModel> model = m_Model->CreateIOWizardModelForSave();
+
+  // Interactive
+  ImageIOWizard wiz(this);
+  wiz.SetModel(model);
+  wiz.exec();
+}
+
+void LayerInspectorRowDelegate::on_actionClose_triggered()
+{
+  // Should we prompt for a single layer or all layers?
+  ImageWrapperBase *prompted_layer = m_Model->IsMainLayer() ? NULL : m_Model->GetLayer();
+
+  // Prompt for changes
+  if(SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model->GetParentModel(), prompted_layer))
+    {
+    m_Model->CloseLayer();
+    }
+}
+
+void LayerInspectorRowDelegate::onColorMapPresetSelected()
+{
+}
+
+void LayerInspectorRowDelegate::on_actionAutoContrast_triggered()
+{
+  m_Model->AutoAdjustContrast();
+}
diff --git a/GUI/Qt/Components/LayerInspectorRowDelegate.h b/GUI/Qt/Components/LayerInspectorRowDelegate.h
new file mode 100644
index 0000000..13070a8
--- /dev/null
+++ b/GUI/Qt/Components/LayerInspectorRowDelegate.h
@@ -0,0 +1,111 @@
+#ifndef LAYERINSPECTORROWDELEGATE_H
+#define LAYERINSPECTORROWDELEGATE_H
+
+#include <QWidget>
+#include <SNAPComponent.h>
+#include "SNAPCommon.h"
+
+class LayerTableRowModel;
+class ImageWrapperBase;
+class QMenu;
+class QActionGroup;
+class QContextMenuEvent;
+
+namespace Ui {
+class LayerInspectorRowDelegate;
+}
+
+/**
+ * @brief The LayerInspectorRowDelegate class
+ * This compound widget is used to display a row in the table of layers in
+ * the layer inspector. The name LayerInspectorRowDelegate is not quite right
+ * as we are not actually using a Qt list widget to display layers. Instead
+ * these widgets are organized in a QScrollArea.
+ */
+class LayerInspectorRowDelegate : public SNAPComponent
+{
+  Q_OBJECT
+  Q_PROPERTY(bool selected READ selected WRITE setSelected USER true NOTIFY selectionChanged)
+
+public:
+  explicit LayerInspectorRowDelegate(QWidget *parent = 0);
+  ~LayerInspectorRowDelegate();
+
+  void SetModel(LayerTableRowModel *model);
+
+  ImageWrapperBase *GetLayer() const;
+
+  bool selected() const { return m_Selected; }
+
+  // Access the actions for this item
+  QAction * saveAction() const;
+  QAction * closeAction() const;
+
+  // Get the context menu for this item
+  QMenu *contextMenu() const;
+
+  void enterEvent(QEvent *);
+  void leaveEvent(QEvent *);
+
+  void mousePressEvent(QMouseEvent *);
+  void mouseMoveEvent(QMouseEvent *);
+  void mouseReleaseEvent(QMouseEvent *);
+  void contextMenuEvent(QContextMenuEvent *evt);
+
+  bool eventFilter(QObject *, QEvent *);
+
+public slots:
+
+  void setSelected(bool value);
+
+  virtual void onModelUpdate(const EventBucket &bucket);
+
+signals:
+  void selectionChanged(bool);
+  
+private slots:
+  void on_btnMenu_pressed();
+
+  void on_btnMoveUp_clicked();
+
+  void on_btnMoveDown_pressed();
+
+  void on_actionSave_triggered();
+
+  void on_actionClose_triggered();
+
+  void onColorMapPresetSelected();
+
+  void on_actionAutoContrast_triggered();
+
+private:
+  Ui::LayerInspectorRowDelegate *ui;
+
+  // It is very important here that we keep a smart pointer to the model,
+  // rather than a regular pointer. That's because the layer itself may
+  // be deleted, in which case, there will be noone kept holding the model.
+  SmartPtr<LayerTableRowModel> m_Model;
+
+  bool m_Selected;
+  bool m_Hover;
+
+  static QString m_SliderStyleSheetTemplate;
+
+  // A popup menu
+  QMenu *m_PopupMenu;
+
+  // A submenu for the color maps
+  QMenu *m_ColorMapMenu, *m_DisplayModeMenu;
+
+  // An action group for the system presets
+  QActionGroup* m_SystemPresetActionGroup, *m_DisplayModeActionGroup;
+
+  void ApplyColorMap();
+  void UpdateBackgroundPalette();
+  void UpdateVisibilityControls();
+  void UpdateColorMapMenu();
+  void UpdateComponentMenu();
+  void OnNicknameUpdate();
+};
+
+#endif // LAYERINSPECTORROWDELEGATE_H
diff --git a/GUI/Qt/Components/LayerInspectorRowDelegate.ui b/GUI/Qt/Components/LayerInspectorRowDelegate.ui
new file mode 100644
index 0000000..993a6bd
--- /dev/null
+++ b/GUI/Qt/Components/LayerInspectorRowDelegate.ui
@@ -0,0 +1,433 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LayerInspectorRowDelegate</class>
+ <widget class="QWidget" name="LayerInspectorRowDelegate">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>163</width>
+    <height>52</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QToolButton::checked
+{
+	border: none;
+	background-color: rgba(0,0,0,0);
+};
+	
+QToolButton::hovered
+{
+	border: 4px solid gray;
+};
+
+QMenu::item 
+{
+	font-size:9px;
+}
+</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QFrame" name="frame">
+     <property name="autoFillBackground">
+      <bool>true</bool>
+     </property>
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="frameShape">
+      <enum>QFrame::NoFrame</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>1</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="outLayerNickname">
+        <property name="maximumSize">
+         <size>
+          <width>158</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>-1</pointsize>
+         </font>
+        </property>
+        <property name="autoFillBackground">
+         <bool>false</bool>
+        </property>
+        <property name="styleSheet">
+         <string notr="true">font-size:12px;</string>
+        </property>
+        <property name="text">
+         <string>TextLabel</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_4">
+        <property name="spacing">
+         <number>6</number>
+        </property>
+        <property name="rightMargin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QStackedWidget" name="stack">
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="styleSheet">
+           <string notr="true"/>
+          </property>
+          <property name="currentIndex">
+           <number>1</number>
+          </property>
+          <widget class="QWidget" name="pageControls">
+           <property name="autoFillBackground">
+            <bool>false</bool>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <property name="spacing">
+             <number>2</number>
+            </property>
+            <property name="margin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QToolButton" name="btnVisible">
+              <property name="maximumSize">
+               <size>
+                <width>20</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string><html><head/><body><p>Toggle between making the image layer visible or invisible.</p></body></html></string>
+              </property>
+              <property name="autoFillBackground">
+               <bool>false</bool>
+              </property>
+              <property name="styleSheet">
+               <string notr="true"/>
+              </property>
+              <property name="text">
+               <string>...</string>
+              </property>
+              <property name="icon">
+               <iconset resource="../Resources/SNAPResources.qrc">
+                <normaloff>:/root/icons8_invisible_16.png</normaloff>
+                <normalon>:/root/icons8_visible_16.png</normalon>:/root/icons8_invisible_16.png</iconset>
+              </property>
+              <property name="checkable">
+               <bool>true</bool>
+              </property>
+              <property name="checked">
+               <bool>true</bool>
+              </property>
+              <property name="autoRaise">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QSlider" name="inLayerOpacity">
+              <property name="maximumSize">
+               <size>
+                <width>64</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string><html><head/><body><p>Change the opacity of the image layer.</p></body></html></string>
+              </property>
+              <property name="autoFillBackground">
+               <bool>false</bool>
+              </property>
+              <property name="styleSheet">
+               <string notr="true">QSlider::groove:horizontal {
+border: 1px solid #bbb;
+background: white;
+height: 6px;
+border-radius: 3px;
+}
+
+QSlider::sub-page:horizontal {
+background: qlineargradient(x1: 0, y1: 0,    x2: 0, y2: 1,
+    stop: 0 #66e, stop: 1 #bbf);
+background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
+    stop: 0 #bbf, stop: 1 #55f);
+border: 1px solid #777;
+height: 6px;
+border-radius: 3px;
+}
+
+QSlider::add-page:horizontal {
+background: #fff;
+border: 1px solid #777;
+height: 6px;
+border-radius: 3px;
+}
+
+QSlider::handle:horizontal {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+    stop:0 #eee, stop:1 #ccc);
+border: 1px solid #777;
+width: 13px;
+margin-top: -2px;
+margin-bottom: -2px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal:hover {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+    stop:0 #fff, stop:1 #ddd);
+border: 1px solid #444;
+border-radius: 3px;
+}
+
+QSlider::sub-page:horizontal:disabled {
+background: #bbb;
+border-color: #999;
+}
+
+QSlider::add-page:horizontal:disabled {
+background: #eee;
+border-color: #999;
+}
+
+QSlider::handle:horizontal:disabled {
+background: #eee;
+border: 1px solid #aaa;
+border-radius: 4px;
+}</string>
+              </property>
+              <property name="sliderPosition">
+               <number>55</number>
+              </property>
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="tickPosition">
+               <enum>QSlider::NoTicks</enum>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnSticky">
+              <property name="maximumSize">
+               <size>
+                <width>20</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string><html><head/><body><p>&quot;Pin&quot; or &quot;unpin&quot; the image layer. When an image layer is pinned, it is shown as an overlay when image layers are tiled (<img src=":/root/layout_tile_16.png"/>).</p></body></html></string>
+              </property>
+              <property name="autoFillBackground">
+               <bool>false</bool>
+              </property>
+              <property name="text">
+               <string>...</string>
+              </property>
+              <property name="icon">
+               <iconset resource="../Resources/SNAPResources.qrc">
+                <normaloff>:/root/icons8_unpin_16.png</normaloff>
+                <normalon>:/root/icons8_pin_16.png</normalon>:/root/icons8_unpin_16.png</iconset>
+              </property>
+              <property name="checkable">
+               <bool>true</bool>
+              </property>
+              <property name="checked">
+               <bool>false</bool>
+              </property>
+              <property name="autoRaise">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnMoveUp">
+              <property name="maximumSize">
+               <size>
+                <width>20</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string><html><head/><body><p>Move an image layer up in the list of image layers. This changes its position when layers are tiled (<img src=":/root/layout_tile_16.png"/>) and makes it be rendered earlier when layers are stacked (<img src=":/root/layout_overlay_16.png"/>).</p></body></html></string>
+              </property>
+              <property name="autoFillBackground">
+               <bool>false</bool>
+              </property>
+              <property name="text">
+               <string>...</string>
+              </property>
+              <property name="icon">
+               <iconset resource="../Resources/SNAPResources.qrc">
+                <normaloff>:/root/icons8_up_18.png</normaloff>:/root/icons8_up_18.png</iconset>
+              </property>
+              <property name="checked">
+               <bool>false</bool>
+              </property>
+              <property name="autoRaise">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnMoveDown">
+              <property name="maximumSize">
+               <size>
+                <width>20</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string><html><head/><body><p>Move an image layer down in the list of image layers. This changes its position when layers are tiled (<img src=":/root/layout_tile_16.png"/>) and makes it be rendered later when layers are stacked (<img src=":/root/layout_overlay_16.png"/>).</p></body></html></string>
+              </property>
+              <property name="autoFillBackground">
+               <bool>false</bool>
+              </property>
+              <property name="text">
+               <string>...</string>
+              </property>
+              <property name="icon">
+               <iconset resource="../Resources/SNAPResources.qrc">
+                <normaloff>:/root/icons8_down_18.png</normaloff>:/root/icons8_down_18.png</iconset>
+              </property>
+              <property name="checkable">
+               <bool>false</bool>
+              </property>
+              <property name="checked">
+               <bool>false</bool>
+              </property>
+              <property name="autoRaise">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+          <widget class="QWidget" name="pageBlank">
+           <property name="autoFillBackground">
+            <bool>false</bool>
+           </property>
+           <property name="styleSheet">
+            <string notr="true"/>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_3">
+            <property name="margin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QLabel" name="outComponent">
+              <property name="toolTip">
+               <string><html><head/><body><p>Indicates what aspect of a multi-component image layer is displayed (e.g., a particular component, magnitude of components, etc.).</p></body></html></string>
+              </property>
+              <property name="styleSheet">
+               <string notr="true">font-size:11px;
+color: rgb(120, 120, 120)</string>
+              </property>
+              <property name="text">
+               <string>TextLabel</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnMenu">
+              <property name="toolTip">
+               <string><html><head/><body><p>Show a context menu of commands for this image layer.</p></body></html></string>
+              </property>
+              <property name="autoFillBackground">
+               <bool>false</bool>
+              </property>
+              <property name="text">
+               <string>...</string>
+              </property>
+              <property name="icon">
+               <iconset resource="../Resources/SNAPResources.qrc">
+                <normaloff>:/root/open_popup_16.png</normaloff>:/root/open_popup_16.png</iconset>
+              </property>
+              <property name="checkable">
+               <bool>false</bool>
+              </property>
+              <property name="checked">
+               <bool>false</bool>
+              </property>
+              <property name="autoRaise">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+  <action name="actionSave">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/save_22.png</normaloff>:/root/save_22.png</iconset>
+   </property>
+   <property name="text">
+    <string>Save...</string>
+   </property>
+   <property name="toolTip">
+    <string>Save Image to File</string>
+   </property>
+  </action>
+  <action name="actionClose">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/icons8_close_16.png</normaloff>:/root/icons8_close_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Close</string>
+   </property>
+   <property name="toolTip">
+    <string>Close (unload) the selected image layer</string>
+   </property>
+  </action>
+  <action name="actionAutoContrast">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/icons8_fantasy_16.png</normaloff>:/root/icons8_fantasy_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Auto Adjust Contrast</string>
+   </property>
+   <property name="toolTip">
+    <string>Adjust contrast of the image layer automatically for optimal visualization</string>
+   </property>
+  </action>
+ </widget>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/MetadataInspector.cxx b/GUI/Qt/Components/MetadataInspector.cxx
new file mode 100644
index 0000000..e8d1c33
--- /dev/null
+++ b/GUI/Qt/Components/MetadataInspector.cxx
@@ -0,0 +1,82 @@
+#include "MetadataInspector.h"
+#include "ui_MetadataInspector.h"
+#include <QAbstractTableModel>
+#include <QtLineEditCoupling.h>
+#include "ImageInfoModel.h"
+
+void MetadataTableQtModel::SetParentModel(ImageInfoModel *model)
+{
+  m_ParentModel = model;
+  LatentITKEventNotifier::connect(
+        m_ParentModel,ImageInfoModel::MetadataChangeEvent(),
+        this, SLOT(onModelUpdate()));
+}
+
+int MetadataTableQtModel::rowCount(const QModelIndex &parent) const
+{
+  return m_ParentModel->GetMetadataRows();
+}
+
+int MetadataTableQtModel::columnCount(const QModelIndex &parent) const
+{
+  return 2;
+}
+
+QVariant MetadataTableQtModel::headerData(
+    int section, Qt::Orientation orientation, int role) const
+{
+  const char *header[] = {"Key", "Value"};
+  if(role == Qt::DisplayRole)
+    {
+    return header[section];
+    }
+  else return QVariant();
+}
+
+QVariant MetadataTableQtModel::data(
+    const QModelIndex &index, int role) const
+{
+  // Ignore bad requests
+  if(index.isValid() && (role == Qt::DisplayRole || role == Qt::ToolTipRole))
+    return m_ParentModel->GetMetadataCell(index.row(), index.column()).c_str();
+  else return QVariant();
+}
+
+void MetadataTableQtModel::onModelUpdate()
+{
+  m_ParentModel->Update();
+  emit layoutChanged();
+}
+
+
+
+
+
+MetadataInspector::MetadataInspector(QWidget *parent) :
+  SNAPComponent(parent),
+  ui(new Ui::MetadataInspector)
+{
+  ui->setupUi(this);
+  m_TableModel = new MetadataTableQtModel(this);
+}
+
+MetadataInspector::~MetadataInspector()
+{
+  delete ui;
+}
+
+void MetadataInspector::SetModel(ImageInfoModel *model)
+{
+  m_Model = model;
+  m_TableModel->SetParentModel(model);
+
+  // Hook the table model to the table widget
+  ui->tblMetaData->setModel(m_TableModel);
+
+  // Connect the filter input to the model
+  makeCoupling(ui->inFilter, m_Model->GetMetadataFilterModel());
+}
+
+void MetadataInspector::onModelUpdate(const EventBucket &bucket)
+{
+}
diff --git a/GUI/Qt/Components/MetadataInspector.h b/GUI/Qt/Components/MetadataInspector.h
new file mode 100644
index 0000000..d38d5a6
--- /dev/null
+++ b/GUI/Qt/Components/MetadataInspector.h
@@ -0,0 +1,63 @@
+#ifndef METADATAINSPECTOR_H
+#define METADATAINSPECTOR_H
+
+#include <SNAPComponent.h>
+#include <SNAPCommon.h>
+#include <QAbstractTableModel>
+
+class ImageInfoModel;
+class MetadataTableQtModel;
+
+namespace Ui {
+class MetadataInspector;
+}
+
+
+class MetadataTableQtModel : public QAbstractTableModel
+{
+  Q_OBJECT
+
+public:
+  MetadataTableQtModel(QWidget *parent) : QAbstractTableModel(parent) {}
+  virtual ~MetadataTableQtModel() {}
+
+  void SetParentModel(ImageInfoModel *model);
+  int rowCount(const QModelIndex &parent) const;
+  int columnCount(const QModelIndex &parent) const;
+
+  QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+  QVariant data(const QModelIndex &index, int role) const;
+
+public slots:
+
+  void onModelUpdate();
+
+
+protected:
+
+  ImageInfoModel *m_ParentModel;
+};
+
+
+class MetadataInspector : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit MetadataInspector(QWidget *parent = 0);
+  ~MetadataInspector();
+
+  // Set the model
+  void SetModel(ImageInfoModel *model);
+
+  // Respond to model updates
+  virtual void onModelUpdate(const EventBucket &bucket);
+
+private:
+  Ui::MetadataInspector *ui;
+  MetadataTableQtModel *m_TableModel;
+  ImageInfoModel *m_Model;
+};
+
+#endif // METADATAINSPECTOR_H
diff --git a/GUI/Qt/Components/MetadataInspector.ui b/GUI/Qt/Components/MetadataInspector.ui
new file mode 100644
index 0000000..2e2778d
--- /dev/null
+++ b/GUI/Qt/Components/MetadataInspector.ui
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MetadataInspector</class>
+ <widget class="QWidget" name="MetadataInspector">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>410</width>
+    <height>444</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>12</number>
+   </property>
+   <property name="leftMargin">
+    <number>6</number>
+   </property>
+   <property name="topMargin">
+    <number>18</number>
+   </property>
+   <property name="rightMargin">
+    <number>6</number>
+   </property>
+   <property name="bottomMargin">
+    <number>6</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="font">
+      <font>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="text">
+      <string>Image Metadata:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTableView" name="tblMetaData">
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="sortingEnabled">
+      <bool>false</bool>
+     </property>
+     <attribute name="horizontalHeaderDefaultSectionSize">
+      <number>180</number>
+     </attribute>
+     <attribute name="horizontalHeaderStretchLastSection">
+      <bool>true</bool>
+     </attribute>
+     <attribute name="verticalHeaderVisible">
+      <bool>false</bool>
+     </attribute>
+     <attribute name="verticalHeaderDefaultSectionSize">
+      <number>24</number>
+     </attribute>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Filter:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="inFilter"/>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/PaintbrushToolPanel.cxx b/GUI/Qt/Components/PaintbrushToolPanel.cxx
new file mode 100644
index 0000000..5a3f67c
--- /dev/null
+++ b/GUI/Qt/Components/PaintbrushToolPanel.cxx
@@ -0,0 +1,58 @@
+#include "PaintbrushToolPanel.h"
+#include "ui_PaintbrushToolPanel.h"
+
+#include "PaintbrushSettingsModel.h"
+#include "QtRadioButtonCoupling.h"
+#include "QtCheckBoxCoupling.h"
+#include "QtDoubleSpinBoxCoupling.h"
+#include "QtSpinBoxCoupling.h"
+#include "QtSliderCoupling.h"
+
+PaintbrushToolPanel::PaintbrushToolPanel(QWidget *parent) :
+  QWidget(parent),
+  ui(new Ui::PaintbrushToolPanel)
+{
+  ui->setupUi(this);
+
+  // Adjust the shortcuts for increase/decrease behavior
+  ui->actionBrushIncrease->setShortcuts(
+        ui->actionBrushIncrease->shortcuts() << QKeySequence('='));
+
+  ui->actionBrushDecrease->setShortcuts(
+        ui->actionBrushDecrease->shortcuts() << QKeySequence('_'));
+
+  addAction(ui->actionBrushIncrease);
+  addAction(ui->actionBrushDecrease);
+}
+
+PaintbrushToolPanel::~PaintbrushToolPanel()
+{
+  delete ui;
+}
+
+void PaintbrushToolPanel::SetModel(PaintbrushSettingsModel *model)
+{
+  m_Model = model;
+
+  // Couple the radio buttons
+  std::map<PaintbrushMode, QAbstractButton *> rmap;
+  rmap[PAINTBRUSH_RECTANGULAR] = ui->btnSquare;
+  rmap[PAINTBRUSH_ROUND] = ui->btnRound;
+  rmap[PAINTBRUSH_WATERSHED] = ui->btnWatershed;
+  makeRadioGroupCoupling(ui->grpBrushStyle, rmap,
+                         m_Model->GetPaintbrushModeModel());
+
+  // Couple the other controls
+  makeCoupling(ui->chkVolumetric, model->GetVolumetricBrushModel());
+  makeCoupling(ui->chkIsotropic, model->GetIsotropicBrushModel());
+  makeCoupling(ui->chkChase, model->GetChaseCursorModel());
+
+  makeCoupling(ui->inBrushSizeSlider, model->GetBrushSizeModel());
+  makeCoupling(ui->inBrushSizeSpinbox, model->GetBrushSizeModel());
+
+  // Couple the visibility of the adaptive widget
+  makeWidgetVisibilityCoupling(ui->grpAdaptive, model->GetAdaptiveModeModel());
+
+  makeCoupling(ui->inGranularity, model->GetThresholdLevelModel());
+  makeCoupling(ui->inSmoothness, model->GetSmoothingIterationsModel());
+}
diff --git a/GUI/Qt/Components/PaintbrushToolPanel.h b/GUI/Qt/Components/PaintbrushToolPanel.h
new file mode 100644
index 0000000..9002ee0
--- /dev/null
+++ b/GUI/Qt/Components/PaintbrushToolPanel.h
@@ -0,0 +1,27 @@
+#ifndef PAINTBRUSHTOOLPANEL_H
+#define PAINTBRUSHTOOLPANEL_H
+
+#include <QWidget>
+
+class PaintbrushSettingsModel;
+
+namespace Ui {
+class PaintbrushToolPanel;
+}
+
+class PaintbrushToolPanel : public QWidget
+{
+  Q_OBJECT
+  
+public:
+  explicit PaintbrushToolPanel(QWidget *parent = 0);
+  ~PaintbrushToolPanel();
+
+  void SetModel(PaintbrushSettingsModel *model);
+  
+private:
+  Ui::PaintbrushToolPanel *ui;
+  PaintbrushSettingsModel *m_Model;
+};
+
+#endif // PAINTBRUSHTOOLPANEL_H
diff --git a/GUI/Qt/Components/PaintbrushToolPanel.ui b/GUI/Qt/Components/PaintbrushToolPanel.ui
new file mode 100644
index 0000000..54e0fc6
--- /dev/null
+++ b/GUI/Qt/Components/PaintbrushToolPanel.ui
@@ -0,0 +1,421 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PaintbrushToolPanel</class>
+ <widget class="QWidget" name="PaintbrushToolPanel">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>179</width>
+    <height>442</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>160</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+      </font>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">* {
+font-size: 11px;
+}
+</string>
+     </property>
+     <property name="text">
+      <string>Paint with the selected label by clicking and dragging the left mouse button</string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line_2">
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_2">
+     <property name="text">
+      <string>Brush Style:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="grpBrushStyle" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="spacing">
+       <number>6</number>
+      </property>
+      <property name="leftMargin">
+       <number>12</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QToolButton" name="btnSquare">
+        <property name="maximumSize">
+         <size>
+          <width>26</width>
+          <height>26</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string><html><head/><body><p>Rectangular brush shape</p></body></html></string>
+        </property>
+        <property name="text">
+         <string>square</string>
+        </property>
+        <property name="icon">
+         <iconset resource="../Resources/SNAPResources.qrc">
+          <normaloff>:/root/brush_shape_square.png</normaloff>:/root/brush_shape_square.png</iconset>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="autoExclusive">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnRound">
+        <property name="maximumSize">
+         <size>
+          <width>26</width>
+          <height>26</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string><html><head/><body><p>Round brush shape</p></body></html></string>
+        </property>
+        <property name="text">
+         <string>round</string>
+        </property>
+        <property name="icon">
+         <iconset resource="../Resources/SNAPResources.qrc">
+          <normaloff>:/root/brush_shape_round.png</normaloff>:/root/brush_shape_round.png</iconset>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="autoExclusive">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnWatershed">
+        <property name="maximumSize">
+         <size>
+          <width>26</width>
+          <height>26</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string><html><head/><body><p>Adaptive brush (adjusts shape to follow image boundaries)</p></body></html></string>
+        </property>
+        <property name="text">
+         <string>adaptive</string>
+        </property>
+        <property name="icon">
+         <iconset resource="../Resources/SNAPResources.qrc">
+          <normaloff>:/root/brush_shape_adaptive.png</normaloff>:/root/brush_shape_adaptive.png</iconset>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="autoExclusive">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_3">
+     <property name="text">
+      <string>Brush Size:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_2" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="spacing">
+       <number>12</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>12</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QSpinBox" name="inBrushSizeSpinbox"/>
+      </item>
+      <item>
+       <widget class="QSlider" name="inBrushSizeSlider">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_4">
+     <property name="text">
+      <string>Brush Options:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QCheckBox" name="chkVolumetric">
+        <property name="toolTip">
+         <string><html><head/><body><p>When checked, the brush is applied in all three dimensions: a rectangular brush creates a cube in the segmentation, and a round brush creates a sphere.</p></body></html></string>
+        </property>
+        <property name="text">
+         <string>Volumetric</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="chkIsotropic">
+        <property name="toolTip">
+         <string><html><head/><body><p>This option is relevant for images with anisotropic voxels (voxels with different x,y and z dimensions). When checked, the physical dimensions of the brush are kept as close to equal as possible. When not checked, the brush size is K x K voxels, regardless of the dimensions of the voxel.</p></body></html></string>
+        </property>
+        <property name="text">
+         <string>Isotropic</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="chkChase">
+        <property name="toolTip">
+         <string><html><head/><body><p>When checked, at the end of each paintbrush stroke, the position of the 3D image cursor is reset to the endpoint of the stroke.</p></body></html></string>
+        </property>
+        <property name="text">
+         <string>Cursor chases brush</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="grpAdaptive" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_3">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="Line" name="line_3">
+        <property name="frameShadow">
+         <enum>QFrame::Plain</enum>
+        </property>
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="label_5">
+        <property name="text">
+         <string>Adaptive Algorithm:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_5" native="true">
+        <layout class="QFormLayout" name="formLayout">
+         <property name="fieldGrowthPolicy">
+          <enum>QFormLayout::FieldsStayAtSizeHint</enum>
+         </property>
+         <property name="horizontalSpacing">
+          <number>6</number>
+         </property>
+         <property name="verticalSpacing">
+          <number>4</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item row="0" column="0">
+          <widget class="QLabel" name="label_6">
+           <property name="text">
+            <string>Granularity:</string>
+           </property>
+           <property name="buddy">
+            <cstring>inGranularity</cstring>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QDoubleSpinBox" name="inGranularity">
+           <property name="toolTip">
+            <string><html><head/><body><p>Lower values of this parameter lead to oversegmentation, while higher values lead to undersegmentation. </p></body></html></string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QLabel" name="label_7">
+           <property name="text">
+            <string>Smoothness:</string>
+           </property>
+           <property name="buddy">
+            <cstring>inSmoothness</cstring>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QDoubleSpinBox" name="inSmoothness">
+           <property name="toolTip">
+            <string><html><head/><body><p>Larger values of this parameter produce smoother segments.</p></body></html></string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+  <action name="actionBrushIncrease">
+   <property name="text">
+    <string>Increase Brush Size</string>
+   </property>
+   <property name="shortcut">
+    <string>+</string>
+   </property>
+  </action>
+  <action name="actionBrushDecrease">
+   <property name="text">
+    <string>Increase Brush Size</string>
+   </property>
+   <property name="shortcut">
+    <string>-</string>
+   </property>
+  </action>
+ </widget>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>actionBrushIncrease</sender>
+   <signal>triggered()</signal>
+   <receiver>inBrushSizeSpinbox</receiver>
+   <slot>stepUp()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>40</x>
+     <y>160</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionBrushDecrease</sender>
+   <signal>triggered()</signal>
+   <receiver>inBrushSizeSpinbox</receiver>
+   <slot>stepDown()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>40</x>
+     <y>160</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/GUI/Qt/Components/QActionButton.cxx b/GUI/Qt/Components/QActionButton.cxx
new file mode 100644
index 0000000..5dd2cf5
--- /dev/null
+++ b/GUI/Qt/Components/QActionButton.cxx
@@ -0,0 +1,46 @@
+#include "QActionButton.h"
+#include "SNAPQtCommon.h"
+#include <QAction>
+#include "QToolButton"
+
+QActionButton::QActionButton(QWidget *parent) :
+  QPushButton(parent)
+{
+  m_action = NULL;
+}
+
+void QActionButton::setAction(QString actionName)
+{
+  // Remove old connections
+  if(m_action && m_action->objectName() != actionName)
+    {
+    disconnect(m_action, SIGNAL(changed()), this, SLOT(updateFromAction()));
+    disconnect(this, SIGNAL(clicked()), m_action, SLOT(trigger()));
+    }
+
+  // Assign the action
+  m_action = FindUpstreamAction(this, actionName);
+  if(m_action)
+    {
+    // Update ourselves
+    updateFromAction();
+
+    // Create connections
+    connect(m_action, SIGNAL(changed()), this, SLOT(updateFromAction()));
+    connect(this, SIGNAL(clicked()), m_action, SLOT(trigger()));
+    }
+}
+
+QString QActionButton::action() const
+{
+  return m_action->objectName();
+}
+
+void QActionButton::updateFromAction()
+{
+  setToolTip(m_action->toolTip());
+  setEnabled(m_action->isEnabled());
+  setStatusTip(m_action->statusTip());
+}
+
+
diff --git a/GUI/Qt/Components/QActionButton.h b/GUI/Qt/Components/QActionButton.h
new file mode 100644
index 0000000..6bd2a43
--- /dev/null
+++ b/GUI/Qt/Components/QActionButton.h
@@ -0,0 +1,31 @@
+#ifndef QACTIONBUTTON_H
+#define QACTIONBUTTON_H
+
+#include <QPushButton>
+
+class QAction;
+
+class QActionButton : public QPushButton
+{
+  Q_OBJECT
+  Q_PROPERTY(QString action READ action WRITE setAction NOTIFY actionChanged)
+
+public:
+  explicit QActionButton(QWidget *parent = 0);
+  void setAction(QString action);
+  QString action() const;
+  
+signals:
+  void actionChanged(QString);
+  
+public slots:
+
+  void updateFromAction();
+
+private:
+
+  QAction *m_action;
+  
+};
+
+#endif // QACTIONBUTTON_H
diff --git a/GUI/Qt/Components/QColorButtonWidget.cxx b/GUI/Qt/Components/QColorButtonWidget.cxx
new file mode 100644
index 0000000..33df18c
--- /dev/null
+++ b/GUI/Qt/Components/QColorButtonWidget.cxx
@@ -0,0 +1,35 @@
+#include "QColorButtonWidget.h"
+#include <QToolButton>
+#include <QColorDialog>
+#include <QHBoxLayout>
+#include <SNAPQtCommon.h>
+
+QColorButtonWidget::QColorButtonWidget(QWidget *parent) : QWidget(parent)
+{
+  m_Button = new QToolButton(this);
+  m_Button->setText("Choose ...");
+  m_Button->setIcon(CreateColorBoxIcon(16,16,m_value));
+  m_Button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+  m_Button->setIconSize(QSize(16,16));
+
+  QHBoxLayout *lo = new QHBoxLayout();
+  lo->setContentsMargins(0,0,0,0);
+  lo->addWidget(m_Button);
+  this->setLayout(lo);
+
+  connect(m_Button, SIGNAL(clicked()), SLOT(onButtonPress()));
+}
+
+void QColorButtonWidget::setValue(QColor value)
+{
+  m_value = value;
+  m_Button->setIcon(CreateColorBoxIcon(16,16,value));
+  emit valueChanged();
+}
+
+void QColorButtonWidget::onButtonPress()
+{
+  QColor color = QColorDialog::getColor(m_value, this);
+  if(color.isValid())
+    setValue(color);
+}
diff --git a/GUI/Qt/Components/QColorButtonWidget.h b/GUI/Qt/Components/QColorButtonWidget.h
new file mode 100644
index 0000000..3ffa733
--- /dev/null
+++ b/GUI/Qt/Components/QColorButtonWidget.h
@@ -0,0 +1,33 @@
+#ifndef QCOLORBUTTONWIDGET_H
+#define QCOLORBUTTONWIDGET_H
+
+#include <QWidget>
+
+class QToolButton;
+
+class QColorButtonWidget : public QWidget
+{
+  Q_OBJECT
+public:
+  explicit QColorButtonWidget(QWidget *parent = 0);
+
+  Q_PROPERTY(QColor value READ value WRITE setValue NOTIFY valueChanged)
+
+  void setValue(QColor value);
+
+  QColor value() { return m_value; }
+
+signals:
+  void valueChanged();
+
+public slots:
+
+  void onButtonPress();
+
+private:
+  QToolButton *m_Button;
+
+  QColor m_value;
+};
+
+#endif // QCOLORBUTTONWIDGET_H
diff --git a/GUI/Qt/Components/QDoubleSlider.cxx b/GUI/Qt/Components/QDoubleSlider.cxx
new file mode 100644
index 0000000..82e09ed
--- /dev/null
+++ b/GUI/Qt/Components/QDoubleSlider.cxx
@@ -0,0 +1,46 @@
+#include "QDoubleSlider.h"
+#include <cmath>
+
+QDoubleSlider::QDoubleSlider(QWidget *parent) :
+  QSlider(parent)
+{
+  m_DoubleMin = 0.0;
+  m_DoubleMax = 1.0;
+  m_DoubleStep = 0.01;
+  updateRange();
+}
+
+void QDoubleSlider::updateRange()
+{
+  int mymax = ceil((m_DoubleMax - m_DoubleMin) / m_DoubleStep);
+  this->setMinimum(0);
+  this->setMaximum(mymax);
+  this->setSingleStep(1);
+
+  this->setDoubleValue(m_DoubleValue);
+}
+
+void QDoubleSlider::setDoubleValue(double x)
+{
+  m_DoubleValue = x;
+  double t = (m_DoubleValue - m_DoubleMin) / (m_DoubleMax - m_DoubleMin);
+  t = std::max(0.0, std::min(1.0, t));
+  int p = (int)(0.5 + this->maximum() * t);
+  if(this->value() != p)
+    this->setValue(p);
+  m_CorrespondingIntValue = p;
+}
+
+double QDoubleSlider::doubleValue()
+{
+  if(this->value() != m_CorrespondingIntValue)
+    {
+    double t = this->value() * 1.0 / this->maximum();
+    m_DoubleValue = m_DoubleMin + t * (m_DoubleMax - m_DoubleMin);
+    m_CorrespondingIntValue = this->value();
+    }
+
+  return m_DoubleValue;
+}
+
+
diff --git a/GUI/Qt/Components/QDoubleSlider.h b/GUI/Qt/Components/QDoubleSlider.h
new file mode 100644
index 0000000..0716e4a
--- /dev/null
+++ b/GUI/Qt/Components/QDoubleSlider.h
@@ -0,0 +1,69 @@
+#ifndef QDOUBLESLIDER_H
+#define QDOUBLESLIDER_H
+
+#include <QSlider>
+
+class QDoubleSlider : public QSlider
+{
+  Q_OBJECT
+public:
+  explicit QDoubleSlider(QWidget *parent = 0);
+
+  double doubleMinimum()
+  {
+    return m_DoubleMin;
+  }
+
+  double doubleMaximum()
+  {
+    return m_DoubleMax;
+  }
+
+  double doubleSingleStep()
+  {
+    return m_DoubleStep;
+  }
+
+  void setDoubleMinimum(double value)
+  {
+    m_DoubleMin = value;
+    updateRange();
+  }
+
+  void setDoubleMaximum(double value)
+  {
+    m_DoubleMax = value;
+    updateRange();
+  }
+
+  void setDoubleSingleStep(double value)
+  {
+    m_DoubleStep = value;
+    updateRange();
+  }
+
+  double doubleValue();
+
+  void setDoubleValue(double x);
+
+signals:
+
+public slots:
+
+private:
+  double m_DoubleMin;
+  double m_DoubleMax;
+  double m_DoubleStep;
+  double m_DoubleValue;
+
+  int m_CorrespondingIntValue;
+
+  void updateRange();
+
+  void updateStep()
+  {
+    QSlider::setSingleStep((int)(1000 * m_DoubleStep / (m_DoubleMax - m_DoubleMin)));
+  }
+};
+
+#endif // QDOUBLESLIDER_H
diff --git a/GUI/Qt/Components/QDoubleSliderWithEditor.cxx b/GUI/Qt/Components/QDoubleSliderWithEditor.cxx
new file mode 100644
index 0000000..67dfb15
--- /dev/null
+++ b/GUI/Qt/Components/QDoubleSliderWithEditor.cxx
@@ -0,0 +1,162 @@
+#include "QDoubleSliderWithEditor.h"
+#include "ui_QDoubleSliderWithEditor.h"
+#include <cmath>
+
+QDoubleSliderWithEditor::QDoubleSliderWithEditor(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::QDoubleSliderWithEditor)
+{
+  ui->setupUi(this);
+
+  ui->slider->setMinimum(0);
+  ui->slider->setMaximum(1000000);
+  ui->slider->setSingleStep(0);
+
+  // When the value in the slider changes, we want to update the spinbox
+  connect(ui->slider, SIGNAL(valueChanged(int)),
+          this, SLOT(sliderValueChanged(int)));
+  connect(ui->spinbox, SIGNAL(valueChanged(double)),
+          this, SLOT(spinnerValueChanged(double)));
+
+  m_IgnoreSliderEvent = false;
+  m_IgnoreSpinnerEvent = false;
+  m_ForceDiscreteSteps = true;
+}
+
+QDoubleSliderWithEditor::~QDoubleSliderWithEditor()
+{
+  delete ui;
+}
+
+void QDoubleSliderWithEditor::setValue(double newval)
+{
+  // Set the value in the spinbox
+  if(newval != ui->spinbox->value())
+    {
+    m_IgnoreSpinnerEvent = true;
+    ui->spinbox->setValue(newval);
+    ui->spinbox->setSpecialValueText("");
+    m_IgnoreSpinnerEvent = false;
+    this->updateSliderFromSpinner();
+    }
+}
+
+double QDoubleSliderWithEditor::value()
+{
+  return ui->spinbox->value();
+}
+
+void QDoubleSliderWithEditor::updateSliderFromSpinner()
+{
+  // Set the value of the slider proportionally to the range of the spinner
+  double a = ui->spinbox->minimum();
+  double b = ui->spinbox->maximum();
+  double v = ui->spinbox->value();
+
+  double r = (v - a) / (b - a);
+  int vs = (int) (ui->slider->maximum() * r);
+
+  m_IgnoreSliderEvent = true;
+  if(vs != ui->slider->value())
+    ui->slider->setValue(vs);
+  m_IgnoreSliderEvent = false;
+}
+
+double QDoubleSliderWithEditor::minimum()
+{
+  return ui->spinbox->minimum();
+}
+
+double QDoubleSliderWithEditor::maximum()
+{
+  return ui->spinbox->maximum();
+}
+
+double QDoubleSliderWithEditor::singleStep()
+{
+  return ui->spinbox->singleStep();
+}
+
+void QDoubleSliderWithEditor::setMinimum(double x)
+{
+  ui->spinbox->setMinimum(x);
+  this->updateSliderFromSpinner();
+}
+
+void QDoubleSliderWithEditor::setMaximum(double x)
+{
+  ui->spinbox->setMaximum(x);
+  this->updateSliderFromSpinner();
+}
+
+void QDoubleSliderWithEditor::setSingleStep(double x)
+{
+  ui->spinbox->setSingleStep(x);
+}
+
+void QDoubleSliderWithEditor::setForceDiscreteSteps(bool useDiscreteSteps)
+{
+  m_ForceDiscreteSteps = useDiscreteSteps;
+}
+
+void QDoubleSliderWithEditor::sliderValueChanged(int valslider)
+{
+  if(!m_IgnoreSliderEvent)
+    {
+    // We need to map the integer value into the closest acceptable by the spinbox
+    double r = valslider * 1.0 / ui->slider->maximum();
+    double a = ui->spinbox->minimum();
+    double b = ui->spinbox->maximum();
+    double v;
+
+    // If necessary, round the value using singleStep
+    if(m_ForceDiscreteSteps)
+      {
+      double step = ui->spinbox->singleStep();
+      double t = 0.5 * step + (b - a) * r;
+      v = a + (t - std::fmod(t, step));
+      }
+    else
+      {
+      v = a + (b - a) * r;
+      }
+
+    // Set the value in the spinner and slider
+    this->setValue(v);
+
+    // Invoke the event
+    emit valueChanged(ui->spinbox->value());
+    }
+}
+
+void QDoubleSliderWithEditor::spinnerValueChanged(double value)
+{
+  // This is very simple, we just stick the value into the slider
+  if(!m_IgnoreSpinnerEvent)
+    {
+    this->updateSliderFromSpinner();
+    emit valueChanged(value);
+    }
+}
+
+void QDoubleSliderWithEditor::stepUp()
+{
+  ui->spinbox->stepUp();
+}
+
+void QDoubleSliderWithEditor::stepDown()
+{
+  ui->spinbox->stepDown();
+}
+
+void QDoubleSliderWithEditor::setValueToNull()
+{
+  // First, set the value to minimum
+  m_IgnoreSliderEvent = true;
+  m_IgnoreSpinnerEvent = true;
+  ui->slider->setValue(ui->slider->minimum());
+  ui->spinbox->setValue(ui->spinbox->minimum());
+  ui->spinbox->setSpecialValueText(" ");
+  m_IgnoreSliderEvent = false;
+  m_IgnoreSpinnerEvent = false;
+}
diff --git a/GUI/Qt/Components/QDoubleSliderWithEditor.h b/GUI/Qt/Components/QDoubleSliderWithEditor.h
new file mode 100644
index 0000000..8177746
--- /dev/null
+++ b/GUI/Qt/Components/QDoubleSliderWithEditor.h
@@ -0,0 +1,65 @@
+#ifndef QDOUBLESLIDERWITHEDITOR_H
+#define QDOUBLESLIDERWITHEDITOR_H
+
+#include <QWidget>
+
+namespace Ui {
+  class QDoubleSliderWithEditor;
+}
+
+class QDoubleSliderWithEditor : public QWidget
+{
+  Q_OBJECT
+
+public:
+
+  Q_PROPERTY(double value
+             READ value
+             WRITE setValue
+             NOTIFY valueChanged)
+
+  Q_PROPERTY(double minimum READ minimum WRITE setMinimum)
+  Q_PROPERTY(double maximum READ maximum WRITE setMaximum)
+  Q_PROPERTY(double singleStep READ singleStep WRITE setSingleStep)
+
+  explicit QDoubleSliderWithEditor(QWidget *parent = 0);
+  ~QDoubleSliderWithEditor();
+
+  double value();
+  void setValue(double newval);
+
+  void setValueToNull();
+
+  double minimum();
+  double maximum();
+  double singleStep();
+  void setMinimum(double);
+  void setMaximum(double);
+  void setSingleStep(double);
+  void setOrientation(Qt::Orientation) {}
+
+  /** Whether the slider uses discrete steps (in units of SingleStep) or
+   * a continuous range of values */
+  void setForceDiscreteSteps(bool useDiscreteSteps);
+
+public slots:
+
+  void sliderValueChanged(int);
+  void spinnerValueChanged(double);
+  void stepUp();
+  void stepDown();
+
+signals:
+  void valueChanged(double);
+
+private:
+
+  void updateSliderFromSpinner();
+
+  Ui::QDoubleSliderWithEditor *ui;
+
+  bool m_IgnoreSliderEvent, m_IgnoreSpinnerEvent;
+  bool m_ForceDiscreteSteps;
+};
+
+#endif // QDOUBLESLIDERWITHEDITOR_H
diff --git a/GUI/Qt/Components/QDoubleSliderWithEditor.ui b/GUI/Qt/Components/QDoubleSliderWithEditor.ui
new file mode 100644
index 0000000..0318a4e
--- /dev/null
+++ b/GUI/Qt/Components/QDoubleSliderWithEditor.ui
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QDoubleSliderWithEditor</class>
+ <widget class="QWidget" name="QDoubleSliderWithEditor">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>210</width>
+    <height>32</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QDoubleSpinBox" name="spinbox">
+     <property name="buttonSymbols">
+      <enum>QAbstractSpinBox::NoButtons</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QSlider" name="slider">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="invertedControls">
+      <bool>false</bool>
+     </property>
+     <property name="tickPosition">
+      <enum>QSlider::NoTicks</enum>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/QtCursorOverride.h b/GUI/Qt/Components/QtCursorOverride.h
new file mode 100644
index 0000000..b8115c9
--- /dev/null
+++ b/GUI/Qt/Components/QtCursorOverride.h
@@ -0,0 +1,42 @@
+#ifndef QCURSOROVERRIDE_H
+#define QCURSOROVERRIDE_H
+
+#include <QCursor>
+#include <QApplication>
+
+/**
+  A small object that can be allocated on the stack to change the appearance
+  of the Qt cursor. It is conventient to use inside of try/catch blocks
+
+  try
+    {
+    CusrorOverride co;
+    // do stuff
+    }
+  catch(...)
+    {
+    // cursor restored at this point
+    }
+
+*/
+
+class QtCursorOverride
+{
+public:
+  QtCursorOverride(const QCursor &cursor)
+  {
+    QApplication::setOverrideCursor(cursor);
+  }
+
+  QtCursorOverride(Qt::CursorShape shape = Qt::WaitCursor)
+  {
+    QApplication::setOverrideCursor(QCursor(shape));
+  }
+
+  ~QtCursorOverride()
+  {
+    QApplication::restoreOverrideCursor();
+  }
+};
+
+#endif // QCURSOROVERRIDE_H
diff --git a/GUI/Qt/Components/QtIPCManager.cxx b/GUI/Qt/Components/QtIPCManager.cxx
new file mode 100644
index 0000000..66ab8b1
--- /dev/null
+++ b/GUI/Qt/Components/QtIPCManager.cxx
@@ -0,0 +1,33 @@
+#include "QtIPCManager.h"
+#include "SNAPEvents.h"
+#include "SynchronizationModel.h"
+
+
+QtIPCManager::QtIPCManager(QWidget *parent) :
+  SNAPComponent(parent)
+{
+  // Start the IPC timer at 30ms intervals
+  startTimer(30);
+}
+
+void QtIPCManager::SetModel(SynchronizationModel *model)
+{
+  m_Model = model;
+
+  // Listen to update events from the model
+  connectITK(m_Model, ModelUpdateEvent());
+}
+
+void QtIPCManager::onModelUpdate(const EventBucket &bucket)
+{
+  // Update the model - this is where all the broadcasting takes place
+  m_Model->Update();
+}
+
+void QtIPCManager::timerEvent(QTimerEvent *)
+{
+  if(!m_Model) return;
+  m_Model->ReadIPCState();
+}
+
+
diff --git a/GUI/Qt/Components/QtIPCManager.h b/GUI/Qt/Components/QtIPCManager.h
new file mode 100644
index 0000000..8522a77
--- /dev/null
+++ b/GUI/Qt/Components/QtIPCManager.h
@@ -0,0 +1,38 @@
+#ifndef QTIPCMANAGER_H
+#define QTIPCMANAGER_H
+
+#include <QObject>
+#include <SNAPComponent.h>
+
+class SynchronizationModel;
+
+/**
+ * @brief This class manages IPC communications between SNAP sessions on the
+ * GUI level. It uses Qt's timers to schedule checks for IPC updates, and it
+ * listens to the events from the model layer in order to send IPC messages
+ * out.
+ */
+class QtIPCManager : public SNAPComponent
+{
+  Q_OBJECT
+public:
+  explicit QtIPCManager(QWidget *parent = 0);
+
+  void SetModel(SynchronizationModel *model);
+  
+signals:
+  
+public slots:
+
+  virtual void onModelUpdate(const EventBucket &bucket);
+
+protected:
+
+  virtual void timerEvent(QTimerEvent *);
+
+private:
+
+  SynchronizationModel *m_Model;
+};
+
+#endif // QTIPCMANAGER_H
diff --git a/GUI/Qt/Components/QtRendererPlatformSupport.cxx b/GUI/Qt/Components/QtRendererPlatformSupport.cxx
new file mode 100644
index 0000000..87c82e3
--- /dev/null
+++ b/GUI/Qt/Components/QtRendererPlatformSupport.cxx
@@ -0,0 +1,128 @@
+#include "QtRendererPlatformSupport.h"
+#include <QGLWidget>
+#include <QPainter>
+#include <QPixmap>
+#include <QFontMetrics>
+#include "SNAPQtCommon.h"
+#include <QDebug>
+#include <iostream>
+
+QRect
+QtRendererPlatformSupport::WorldRectangleToPixelRectangle(const QRect &world)
+{
+  // Viewport and such
+  vnl_vector<int> viewport(4);
+  vnl_matrix<double> model_view(4,4), projection(4,4);
+
+  // Map the rectangle to viewport coordinates
+  glGetIntegerv(GL_VIEWPORT, viewport.data_block());
+  glGetDoublev(GL_PROJECTION_MATRIX, projection.data_block());
+  glGetDoublev(GL_MODELVIEW_MATRIX, model_view.data_block());
+
+  vnl_vector<double> xw1(4), xs1, xw2(4), xs2;
+  xw1[0] = world.x(); xw1[1] = world.y();
+  xw1[2] = 0.0; xw1[3] = 1.0;
+  xs1 = projection.transpose() * (model_view.transpose() * xw1);
+
+  xw2[0] = world.x() + world.width(); xw2[1] = world.y() + world.height();
+  xw2[2] = 0.0; xw2[3] = 1.0;
+  xs2 = projection.transpose() * (model_view.transpose() * xw2);
+
+  double x = std::min(xs1[0] / xs1[3], xs2[0] / xs2[3]);
+  double y = std::min(xs1[1] / xs1[3], xs2[1] / xs2[3]);
+  double w = fabs(xs1[0] / xs1[3] - xs2[0] / xs2[3]);
+  double h = fabs(xs1[1] / xs1[3] - xs2[1] / xs2[3]);
+
+  x = (x + 1) / 2;  y = (y + 1) / 2;
+  w = w / 2;  h = h / 2;
+
+
+  return QRect(
+      QPoint((int)(x * viewport[2] + viewport[0]), (int)(y * viewport[3] + viewport[1])),
+      QSize((int)(w * viewport[2]),(int)(h * viewport[3])));
+}
+
+
+void QtRendererPlatformSupport
+::RenderTextInOpenGL(const char *text,
+                     int x, int y, int w, int h,
+                     FontInfo font,
+                     int align_horiz, int align_vert,
+                     const Vector3d &rgbf)
+{
+  // Map the coordinates to screen coordinates
+  QRect rWorld(QPoint(x, y), QSize(w, h));
+  QRect rScreen = this->WorldRectangleToPixelRectangle(rWorld);
+
+  // Create a pixmap to render the text
+  QImage canvas(rScreen.width(), rScreen.height(), QImage::Format_ARGB32);
+  canvas.fill(QColor(0,0,0,0));
+
+  // Paint the text onto the canvas
+  QPainter painter(&canvas);
+
+  QColor pen_color;
+  pen_color.setRgbF(rgbf[0], rgbf[1], rgbf[2], 1.0);
+  painter.setPen(pen_color);
+
+  int ah = Qt::AlignHCenter, av = Qt::AlignVCenter;
+  switch(align_horiz)
+    {
+    case AbstractRendererPlatformSupport::LEFT    : ah = Qt::AlignLeft;    break;
+    case AbstractRendererPlatformSupport::HCENTER : ah = Qt::AlignHCenter; break;
+    case AbstractRendererPlatformSupport::RIGHT   : ah = Qt::AlignRight;   break;
+    }
+  switch(align_vert)
+    {
+    case AbstractRendererPlatformSupport::BOTTOM  : av = Qt::AlignBottom;  break;
+    case AbstractRendererPlatformSupport::VCENTER : av = Qt::AlignVCenter; break;
+    case AbstractRendererPlatformSupport::TOP     : av = Qt::AlignTop;     break;
+    }
+
+  QFont qfont;
+  switch(font.type)
+    {
+    case AbstractRendererPlatformSupport::SERIF:
+      qfont.setFamily("Times");     break;
+    case AbstractRendererPlatformSupport::SANS:
+      qfont.setFamily("Helvetica"); break;
+    case AbstractRendererPlatformSupport::TYPEWRITER:
+      qfont.setFamily("Courier"); break;
+    }
+
+  qfont.setPixelSize(font.pixel_size);
+  qfont.setBold(font.bold);
+  painter.setFont(qfont);
+
+  painter.drawText(QRectF(0,0,rScreen.width(),rScreen.height()), ah | av, QString::fromUtf8(text));
+
+  QImage gl = QGLWidget::convertToGLFormat(canvas);
+
+  glPushAttrib(GL_COLOR_BUFFER_BIT);
+  glEnable(GL_BLEND);
+  glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+  glRasterPos2i(x,y);
+  glDrawPixels(rScreen.width(),rScreen.height(), GL_RGBA, GL_UNSIGNED_BYTE, gl.bits());
+  glPopAttrib();
+}
+
+int
+QtRendererPlatformSupport
+::MeasureTextWidth(const char *text, AbstractRendererPlatformSupport::FontInfo font)
+{
+  QFont qfont;
+  switch(font.type)
+    {
+    case AbstractRendererPlatformSupport::SERIF:
+      qfont.setFamily("Times");     break;
+    case AbstractRendererPlatformSupport::SANS:
+      qfont.setFamily("Helvetica"); break;
+    case AbstractRendererPlatformSupport::TYPEWRITER:
+      qfont.setFamily("Courier"); break;
+    }
+  qfont.setPixelSize(font.pixel_size);
+  qfont.setBold(font.bold);
+
+  QFontMetrics fm(qfont);
+  return fm.width(QString::fromUtf8(text));
+}
diff --git a/GUI/Qt/Components/QtRendererPlatformSupport.h b/GUI/Qt/Components/QtRendererPlatformSupport.h
new file mode 100644
index 0000000..a4c23f1
--- /dev/null
+++ b/GUI/Qt/Components/QtRendererPlatformSupport.h
@@ -0,0 +1,23 @@
+#ifndef QTRENDERERPLATFORMSUPPORT_H
+#define QTRENDERERPLATFORMSUPPORT_H
+
+#include "AbstractRenderer.h"
+#include <QRect>
+
+class QtRendererPlatformSupport : public AbstractRendererPlatformSupport
+{
+public:
+  virtual void RenderTextInOpenGL(
+      const char *text,
+      int x, int y, int w, int h,
+      FontInfo font,
+      int align_horiz, int align_vert,
+      const Vector3d &rgbf);
+
+  virtual int MeasureTextWidth(const char *text, FontInfo font);
+
+protected:
+  QRect WorldRectangleToPixelRectangle(const QRect &world);
+};
+
+#endif // QTRENDERERPLATFORMSUPPORT_H
diff --git a/GUI/Qt/Components/QtReporterDelegates.cxx b/GUI/Qt/Components/QtReporterDelegates.cxx
new file mode 100644
index 0000000..53869c4
--- /dev/null
+++ b/GUI/Qt/Components/QtReporterDelegates.cxx
@@ -0,0 +1,154 @@
+#include "QtReporterDelegates.h"
+#include "UIReporterDelegates.h"
+#include <QResizeEvent>
+#include <QProgressDialog>
+#include <QCoreApplication>
+
+#include <QPainter>
+#include <QPixmap>
+#include <QWindow>
+
+#include <QImage>
+#include "itkImage.h"
+#include "itkImageRegionIteratorWithIndex.h"
+#include "Registry.h"
+#include <sstream>
+
+#include "SNAPQtCommon.h"
+
+
+QtViewportReporter::QtViewportReporter()
+{
+  m_ClientWidget = NULL;
+  m_Filter = new EventFilter();
+  m_Filter->m_Owner = this;
+}
+
+QtViewportReporter::~QtViewportReporter()
+{
+  if(m_ClientWidget)
+    m_ClientWidget->removeEventFilter(m_Filter);
+
+  delete m_Filter;
+}
+
+void QtViewportReporter::SetClientWidget(QWidget *widget)
+{
+  // In case we are changing widgets, make sure the filter is cleared
+  if(m_ClientWidget)
+    m_ClientWidget->removeEventFilter(m_Filter);
+
+  // Store the widget
+  m_ClientWidget = widget;
+
+  // Capture events from the widget
+  m_ClientWidget->installEventFilter(m_Filter);
+}
+
+bool QtViewportReporter::CanReportSize()
+{
+  return m_ClientWidget != NULL;
+}
+
+Vector2ui QtViewportReporter::GetViewportSize()
+{
+  // For retina displays, this method reports size in actual pixels, not abstract pixels
+  return Vector2ui(m_ClientWidget->width() * m_ClientWidget->windowHandle()->devicePixelRatio(),
+                   m_ClientWidget->height() * m_ClientWidget->windowHandle()->devicePixelRatio());
+}
+
+float QtViewportReporter::GetViewportPixelRatio()
+{
+  return m_ClientWidget->windowHandle()->devicePixelRatio();
+}
+
+Vector2ui QtViewportReporter::GetLogicalViewportSize()
+{
+  return Vector2ui(m_ClientWidget->width(), m_ClientWidget->height());
+}
+
+bool
+QtViewportReporter::EventFilter
+::eventFilter(QObject *object, QEvent *event)
+{
+  if(object == m_Owner->m_ClientWidget && event->type() == QEvent::Resize)
+    {
+    m_Owner->InvokeEvent(ViewportResizeEvent());
+    }
+  return QObject::eventFilter(object, event);
+}
+
+QtProgressReporterDelegate::QtProgressReporterDelegate()
+{
+  m_Dialog = NULL;
+}
+
+void QtProgressReporterDelegate::SetProgressDialog(QProgressDialog *dialog)
+{
+  m_Dialog = dialog;
+  m_Dialog->setMinimum(0);
+  m_Dialog->setMaximum(1000);
+  m_Dialog->setWindowModality(Qt::WindowModal);
+  m_Dialog->setLabelText("ITK-SNAP progress");
+}
+
+#include <QDebug>
+#include <QAction>
+void QtProgressReporterDelegate::SetProgressValue(double value)
+{
+  m_Dialog->setValue((int) (1000 * value));
+  // qDebug() << "Progress: " << value;
+  // QCoreApplication::processEvents();
+}
+
+
+std::string QtSystemInfoDelegate::GetApplicationDirectory()
+{
+  return to_utf8(QCoreApplication::applicationDirPath());
+}
+
+std::string QtSystemInfoDelegate::GetApplicationFile()
+{
+  return to_utf8(QCoreApplication::applicationFilePath());
+}
+
+#include <QStandardPaths>
+std::string QtSystemInfoDelegate::GetApplicationPermanentDataLocation()
+{
+  return to_utf8(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
+}
+
+void QtSystemInfoDelegate
+::LoadResourceAsImage2D(std::string tag, GrayscaleImage *image)
+{
+  // Load the image using Qt
+  QImage iq(QString(":/snapres/snapres/%1").arg(from_utf8(tag)));
+
+  // Initialize the itk image
+  itk::ImageRegion<2> region;
+  region.SetSize(0, iq.width());
+  region.SetSize(1, iq.height());
+  image->SetRegions(region);
+  image->Allocate();
+
+  // Fill the image buffer
+  for(itk::ImageRegionIteratorWithIndex<GrayscaleImage> it(image, region);
+      !it.IsAtEnd(); ++it)
+    {
+    it.Set(qGray(iq.pixel(it.GetIndex()[0],it.GetIndex()[1])));
+    }
+}
+
+void QtSystemInfoDelegate::LoadResourceAsRegistry(std::string tag, Registry &reg)
+{
+  // Read the file into a byte array
+  QFile file(QString(":/snapres/snapres/%1").arg(from_utf8(tag)));
+  if(file.open(QIODevice::ReadOnly | QIODevice::Text))
+    {
+    QByteArray ba = file.readAll();
+
+    // Read the registry contents
+    std::stringstream ss(ba.data());
+    reg.ReadFromStream(ss);
+    }
+}
diff --git a/GUI/Qt/Components/QtReporterDelegates.h b/GUI/Qt/Components/QtReporterDelegates.h
new file mode 100644
index 0000000..8564c68
--- /dev/null
+++ b/GUI/Qt/Components/QtReporterDelegates.h
@@ -0,0 +1,92 @@
+#ifndef QTREQUESTDELEGATES_H
+#define QTREQUESTDELEGATES_H
+
+#include <QWidget>
+#include "UIReporterDelegates.h"
+
+class QProgressDialog;
+class QGLWidget;
+
+/**
+  An implementation of a viewport reporter for Qt.
+
+  CAVEAT: the reported must be destroyed before the client widget
+  */
+class QtViewportReporter : public ViewportSizeReporter
+{
+public:
+
+  irisITKObjectMacro(QtViewportReporter, ViewportSizeReporter)
+
+  /** Set the widget that we report on */
+  void SetClientWidget(QWidget *widget);
+
+  bool CanReportSize();
+
+  Vector2ui GetViewportSize();
+
+  float GetViewportPixelRatio();
+
+  Vector2ui GetLogicalViewportSize();
+
+protected:
+
+  QtViewportReporter();
+  virtual ~QtViewportReporter();
+
+  QWidget *m_ClientWidget;
+
+
+  /** This helper class intercepts resize events from the widget */
+  class EventFilter : public QObject
+  {
+  public:
+    bool eventFilter(QObject *object, QEvent *event);
+    QtViewportReporter *m_Owner;
+  };
+
+  EventFilter *m_Filter;
+
+};
+
+class QtProgressReporterDelegate : public ProgressReporterDelegate
+{
+public:
+  QtProgressReporterDelegate();
+
+  void SetProgressDialog(QProgressDialog *dialog);
+  void SetProgressValue(double);
+
+private:
+  QProgressDialog *m_Dialog;
+};
+
+class QtTextRenderingDelegate : public TextRenderingDelegate
+{
+public:
+
+  virtual void RenderTextInOpenGL(
+      const char *text,
+      int x, int y, int w, int h,
+      int font_size,
+      int align_horiz, int align_vert,
+      unsigned char rgba[]);
+
+protected:
+
+};
+
+class QtSystemInfoDelegate : public SystemInfoDelegate
+{
+public:
+  virtual std::string GetApplicationDirectory();
+  virtual std::string GetApplicationFile();
+  virtual std::string GetApplicationPermanentDataLocation();
+
+  typedef itk::Image<unsigned char, 2> GrayscaleImage;
+
+  virtual void LoadResourceAsImage2D(std::string tag, GrayscaleImage *image);
+  virtual void LoadResourceAsRegistry(std::string tag, Registry &reg);
+};
+
+#endif // QTREQUESTDELEGATES_H
diff --git a/GUI/Qt/Components/QtWarningDialog.cxx b/GUI/Qt/Components/QtWarningDialog.cxx
new file mode 100644
index 0000000..15bb2e2
--- /dev/null
+++ b/GUI/Qt/Components/QtWarningDialog.cxx
@@ -0,0 +1,56 @@
+#include "QtWarningDialog.h"
+
+#include "ui_QtWarningDialog.h"
+
+#include <QString>
+#include <QLabel>
+#include <QPushButton>
+#include <QCheckBox>
+#include <QVBoxLayout>
+#include <iostream>
+
+void QtWarningDialog
+::show(const std::vector<IRISWarning> &wl)
+{
+  const QString htmlTemplate =
+      "<tr><td width=40><img src=\":/root/%1.png\" /></td>"
+      "<td>%2</td></tr>";
+
+  if(wl.size())
+    {
+    QString html;
+    for(std::vector<IRISWarning>::const_iterator it = wl.begin();
+        it != wl.end(); it++)
+      {
+      QString text = it->what();
+      QString head = text.section(".",0,0);
+      QString tail = text.section(".", 1);
+      html += QString(htmlTemplate).arg(
+            "dlg_warning_32", QString("<b>%1.</b> \n%2").arg(head, tail));
+      }
+    html = QString("<table>%1</table>").arg(html);
+
+    QtWarningDialog msg;
+    msg.ui->label->setText(html);
+    msg.exec();
+    }
+}
+
+QtWarningDialog::QtWarningDialog(QWidget *parent)
+  : QDialog(parent),
+    ui(new Ui::QtWarningDialog)
+{
+  ui->setupUi(this);
+}
+
+QtWarningDialog::~QtWarningDialog()
+{
+  delete ui;
+}
+
+
+
+void QtWarningDialog::on_pushButton_clicked()
+{
+  this->close();
+}
diff --git a/GUI/Qt/Components/QtWarningDialog.h b/GUI/Qt/Components/QtWarningDialog.h
new file mode 100644
index 0000000..497bf46
--- /dev/null
+++ b/GUI/Qt/Components/QtWarningDialog.h
@@ -0,0 +1,40 @@
+#ifndef QTWARNINGDIALOG_H
+#define QTWARNINGDIALOG_H
+
+namespace Ui {
+class QtWarningDialog;
+}
+
+#include "IRISException.h"
+#include <list>
+#include <QDialog>
+
+class QLabel;
+class QCheckBox;
+class QPushButton;
+
+class QtWarningDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+
+  explicit QtWarningDialog(QWidget *parent = 0);
+  ~ QtWarningDialog();
+
+  static void show(const std::vector<IRISWarning> &warnings);
+
+public slots:
+
+private slots:
+  void on_pushButton_clicked();
+
+private:
+  QLabel *m_Label;
+  QPushButton *m_Button;
+  QCheckBox *m_Checkbox;
+
+  Ui::QtWarningDialog *ui;
+};
+
+#endif // QTWARNINGDIALOG_H
diff --git a/GUI/Qt/Components/QtWarningDialog.ui b/GUI/Qt/Components/QtWarningDialog.ui
new file mode 100644
index 0000000..1befbc4
--- /dev/null
+++ b/GUI/Qt/Components/QtWarningDialog.ui
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtWarningDialog</class>
+ <widget class="QDialog" name="QtWarningDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>384</width>
+    <height>179</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>ITK-SNAP - Warnings Generated</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>15</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>1</horstretch>
+       <verstretch>1</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>360</width>
+       <height>80</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>400</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="text">
+      <string>Warning: blah blah blah blah!</string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QCheckBox" name="checkBox">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="text">
+      <string>Do not show this warning again</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton">
+       <property name="text">
+        <string>Close</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/QtWidgetActivator.cxx b/GUI/Qt/Components/QtWidgetActivator.cxx
new file mode 100644
index 0000000..db6cabe
--- /dev/null
+++ b/GUI/Qt/Components/QtWidgetActivator.cxx
@@ -0,0 +1,75 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "QtWidgetActivator.h"
+#include "LatentITKEventNotifier.h"
+#include <QWidget>
+#include <QAction>
+#include <StateManagement.h>
+#include "GlobalUIModel.h"
+#include "SNAPUIFlag.h"
+
+QtWidgetActivator
+::QtWidgetActivator(QObject *parent, BooleanCondition *cond)
+  : QObject(parent)
+{
+  // Register to listen to the state change events
+  m_TargetWidget = dynamic_cast<QWidget *>(parent);
+  m_TargetAction = dynamic_cast<QAction *>(parent);
+  m_Condition = cond;
+
+  // Give it a name
+  setObjectName(QString("Activator:%1").arg(parent->objectName()));
+
+  // React to events after control returns to the main UI loop
+  LatentITKEventNotifier::connect(
+        cond, StateMachineChangeEvent(), this, SLOT(OnStateChange()));
+
+  // Update the state of the widget
+  this->OnStateChange();
+}
+
+QtWidgetActivator::~QtWidgetActivator()
+{
+}
+
+void QtWidgetActivator::OnStateChange()
+{
+  // Update the state of the widget based on the condition
+  bool active = (*m_Condition)();
+  if(m_TargetWidget)
+    {
+    bool status = m_TargetWidget->isEnabledTo(m_TargetWidget->parentWidget());
+    if(status != active)
+      m_TargetWidget->setEnabled(active);
+    }
+  else if(m_TargetAction)
+    {
+    bool status = m_TargetAction->isEnabled();
+    if(status != active)
+      m_TargetAction->setEnabled(active);
+    }
+}
diff --git a/GUI/Qt/Components/QtWidgetActivator.h b/GUI/Qt/Components/QtWidgetActivator.h
new file mode 100644
index 0000000..88ce457
--- /dev/null
+++ b/GUI/Qt/Components/QtWidgetActivator.h
@@ -0,0 +1,102 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTWIDGETACTIVATOR_H
+#define QTWIDGETACTIVATOR_H
+
+#include <QObject>
+#include <SNAPCommon.h>
+#include <SNAPUIFlag.h>
+
+class BooleanCondition;
+class QAction;
+
+class QtWidgetActivator : public QObject
+{
+  Q_OBJECT
+public:
+  /**
+    Creates an activator with widget parent and boolean condition. The
+    condition will be deleted when this object is destroyed. The parent
+    widget enabled property will mirror the BoolenaCondition
+
+    The widget can be a QWidget or a QAction. Otherwise, this will do nothing
+   */
+  explicit QtWidgetActivator(QObject *parent, BooleanCondition *cond);
+  ~QtWidgetActivator();
+
+public slots:
+
+  void OnStateChange();
+
+private:
+  QWidget *m_TargetWidget;
+  QAction *m_TargetAction;
+  SmartPtr<BooleanCondition> m_Condition;
+};
+
+template<class TModel, class TStateEnum>
+void activateOnFlag(QObject *w, TModel *m, TStateEnum flag)
+{
+  typedef SNAPUIFlag<TModel, TStateEnum> FlagType;
+  SmartPtr<FlagType> f = FlagType::New(m, flag);
+  new QtWidgetActivator(w, f);
+}
+
+template<class TModel, class TStateEnum>
+void activateOnNotFlag(QObject *w, TModel *m, TStateEnum flag)
+{
+  typedef SNAPUIFlag<TModel, TStateEnum> FlagType;
+  SmartPtr<FlagType> f = FlagType::New(m, flag);
+  SmartPtr<NotCondition> nf = NotCondition::New(f);
+  new QtWidgetActivator(w, nf);
+}
+
+
+template<class TModel, class TStateEnum>
+void activateOnAllFlags(QObject *w, TModel *m,
+                        TStateEnum flag1, TStateEnum flag2)
+{
+  typedef SNAPUIFlag<TModel, TStateEnum> FlagType;
+  SmartPtr<FlagType> f1 = FlagType::New(m, flag1);
+  SmartPtr<FlagType> f2 = FlagType::New(m, flag2);
+  SmartPtr<AndCondition> f = AndCondition::New(f1, f2);
+  new QtWidgetActivator(w, f);
+}
+
+template<class TModel, class TStateEnum>
+void activateOnAnyFlags(QObject *w, TModel *m,
+                        TStateEnum flag1, TStateEnum flag2)
+{
+  typedef SNAPUIFlag<TModel, TStateEnum> FlagType;
+  SmartPtr<FlagType> f1 = FlagType::New(m, flag1);
+  SmartPtr<FlagType> f2 = FlagType::New(m, flag2);
+  SmartPtr<OrCondition> f = OrCondition::New(f1, f2);
+  new QtWidgetActivator(w, f);
+}
+
+
+#endif // QTWIDGETACTIVATOR_H
diff --git a/GUI/Qt/Components/RecentHistoryItemsView.cxx b/GUI/Qt/Components/RecentHistoryItemsView.cxx
new file mode 100644
index 0000000..c282d68
--- /dev/null
+++ b/GUI/Qt/Components/RecentHistoryItemsView.cxx
@@ -0,0 +1,98 @@
+#include "RecentHistoryItemsView.h"
+#include "ui_RecentHistoryItemsView.h"
+#include "HistoryManager.h"
+#include <QListView>
+#include <QItemDelegate>
+#include <QPainter>
+#include <QMenu>
+#include <QAction>
+#include <HistoryQListModel.h>
+#include <SNAPQtCommon.h>
+#include <IRISApplication.h>
+#include <SystemInterface.h>
+#include <GlobalUIModel.h>
+
+class HistoryListItemDelegate : public QItemDelegate
+{
+public:
+  HistoryListItemDelegate(QWidget *parent) : QItemDelegate(parent) {}
+
+  void paint(QPainter *painter,
+             const QStyleOptionViewItem &option,
+             const QModelIndex &index) const
+  {
+    if(!(option.state & QStyle::State_MouseOver))
+      {
+      painter->setOpacity(0.8);
+      }
+    QItemDelegate::paint(painter, option, index);
+  }
+};
+
+RecentHistoryItemsView::RecentHistoryItemsView(QWidget *parent) :
+  QWidget(parent),
+  ui(new Ui::RecentHistoryItemsView)
+{
+  ui->setupUi(this);
+
+  // Delegate for history
+  HistoryListItemDelegate *del = new HistoryListItemDelegate(ui->listRecent);
+  ui->listRecent->setItemDelegate(del);
+
+  // Set up the popup for the recent list
+  m_RecentListPopup = new QMenu(this);
+  m_RecentListPopupAction = m_RecentListPopup->addAction(
+        "Remove from recent image list", this,
+        SLOT(OnRemoveRecentImageListItem()));
+}
+
+RecentHistoryItemsView::~RecentHistoryItemsView()
+{
+  delete ui;
+}
+
+void RecentHistoryItemsView::Initialize(GlobalUIModel *model, std::string history)
+{
+  m_Model = model;
+  m_History = history;
+
+  // Create a model for the table of recent images and connect to the widget
+  m_HistoryModel = new HistoryQListModel(ui->listRecent);
+  m_HistoryModel->Initialize(model, history);
+  ui->listRecent->setModel(m_HistoryModel);
+}
+
+void RecentHistoryItemsView::on_listRecent_clicked(const QModelIndex &index)
+{
+  // Load the appropriate image
+  if(index.isValid())
+    {
+    QString filename = ui->listRecent->model()->data(index, Qt::UserRole).toString();
+    emit RecentItemSelected(filename);
+    }
+}
+
+void RecentHistoryItemsView::on_listRecent_customContextMenuRequested(const QPoint &pos)
+{
+  QModelIndex idx = ui->listRecent->indexAt(pos);
+  if(idx.isValid())
+    {
+    QVariant data = ui->listRecent->model()->data(idx, Qt::UserRole);
+    if(!data.isNull())
+      {
+      m_RecentListPopupAction->setData(data);
+      m_RecentListPopup->popup(QCursor::pos());
+      }
+    }
+}
+
+void RecentHistoryItemsView::OnRemoveRecentImageListItem()
+{
+  QAction *action = qobject_cast<QAction *>(this->sender());
+  QString filename = action->data().toString();
+  HistoryManager *hm =
+      m_Model->GetDriver()->GetSystemInterface()->GetHistoryManager();
+  hm->DeleteHistoryItem(m_History, to_utf8(filename));
+}
+
+
diff --git a/GUI/Qt/Components/RecentHistoryItemsView.h b/GUI/Qt/Components/RecentHistoryItemsView.h
new file mode 100644
index 0000000..bd6ff56
--- /dev/null
+++ b/GUI/Qt/Components/RecentHistoryItemsView.h
@@ -0,0 +1,51 @@
+#ifndef RECENTHISTORYITEMSVIEW_H
+#define RECENTHISTORYITEMSVIEW_H
+
+#include <QWidget>
+
+class GlobalUIModel;
+class QMenu;
+class QAction;
+class HistoryQListModel;
+class QModelIndex;
+
+namespace Ui {
+class RecentHistoryItemsView;
+}
+
+class RecentHistoryItemsView : public QWidget
+{
+  Q_OBJECT
+  
+public:
+
+  /** Set the model and the history name managed by this widget */
+  void Initialize(GlobalUIModel *model, std::string history);
+
+  explicit RecentHistoryItemsView(QWidget *parent = 0);
+  ~RecentHistoryItemsView();
+
+signals:
+
+  void RecentItemSelected(QString filename);
+
+private slots:
+
+  void OnRemoveRecentImageListItem();
+
+  void on_listRecent_clicked(const QModelIndex &index);
+
+  void on_listRecent_customContextMenuRequested(const QPoint &pos);
+  
+private:
+  Ui::RecentHistoryItemsView *ui;
+
+  GlobalUIModel *m_Model;
+  QMenu *m_RecentListPopup;
+  QAction *m_RecentListPopupAction;
+  HistoryQListModel *m_HistoryModel;
+  std::string m_History;
+
+};
+
+#endif // RECENTHISTORYITEMSVIEW_H
diff --git a/GUI/Qt/Components/RecentHistoryItemsView.ui b/GUI/Qt/Components/RecentHistoryItemsView.ui
new file mode 100644
index 0000000..df6d53e
--- /dev/null
+++ b/GUI/Qt/Components/RecentHistoryItemsView.ui
@@ -0,0 +1,505 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RecentHistoryItemsView</class>
+ <widget class="QWidget" name="RecentHistoryItemsView">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>662</width>
+    <height>544</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QListView" name="listRecent">
+     <property name="palette">
+      <palette>
+       <active>
+        <colorrole role="WindowText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Button">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>35</red>
+           <green>35</green>
+           <blue>35</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Light">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>53</red>
+           <green>53</green>
+           <blue>53</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Midlight">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>44</red>
+           <green>44</green>
+           <blue>44</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Dark">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>17</red>
+           <green>17</green>
+           <blue>17</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Mid">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>23</red>
+           <green>23</green>
+           <blue>23</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Text">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="BrightText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="ButtonText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Base">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>0</red>
+           <green>0</green>
+           <blue>0</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Window">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>35</red>
+           <green>35</green>
+           <blue>35</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Shadow">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>0</red>
+           <green>0</green>
+           <blue>0</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="AlternateBase">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>17</red>
+           <green>17</green>
+           <blue>17</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="ToolTipBase">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>220</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="ToolTipText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>0</red>
+           <green>0</green>
+           <blue>0</blue>
+          </color>
+         </brush>
+        </colorrole>
+       </active>
+       <inactive>
+        <colorrole role="WindowText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Button">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>35</red>
+           <green>35</green>
+           <blue>35</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Light">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>53</red>
+           <green>53</green>
+           <blue>53</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Midlight">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>44</red>
+           <green>44</green>
+           <blue>44</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Dark">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>17</red>
+           <green>17</green>
+           <blue>17</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Mid">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>23</red>
+           <green>23</green>
+           <blue>23</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Text">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="BrightText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="ButtonText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Base">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>0</red>
+           <green>0</green>
+           <blue>0</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Window">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>35</red>
+           <green>35</green>
+           <blue>35</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Shadow">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>0</red>
+           <green>0</green>
+           <blue>0</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="AlternateBase">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>17</red>
+           <green>17</green>
+           <blue>17</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="ToolTipBase">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>220</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="ToolTipText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>0</red>
+           <green>0</green>
+           <blue>0</blue>
+          </color>
+         </brush>
+        </colorrole>
+       </inactive>
+       <disabled>
+        <colorrole role="WindowText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>17</red>
+           <green>17</green>
+           <blue>17</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Button">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>35</red>
+           <green>35</green>
+           <blue>35</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Light">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>53</red>
+           <green>53</green>
+           <blue>53</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Midlight">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>44</red>
+           <green>44</green>
+           <blue>44</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Dark">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>17</red>
+           <green>17</green>
+           <blue>17</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Mid">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>23</red>
+           <green>23</green>
+           <blue>23</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Text">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>17</red>
+           <green>17</green>
+           <blue>17</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="BrightText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="ButtonText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>17</red>
+           <green>17</green>
+           <blue>17</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Base">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>35</red>
+           <green>35</green>
+           <blue>35</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Window">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>35</red>
+           <green>35</green>
+           <blue>35</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="Shadow">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>0</red>
+           <green>0</green>
+           <blue>0</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="AlternateBase">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>35</red>
+           <green>35</green>
+           <blue>35</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="ToolTipBase">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>220</blue>
+          </color>
+         </brush>
+        </colorrole>
+        <colorrole role="ToolTipText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>0</red>
+           <green>0</green>
+           <blue>0</blue>
+          </color>
+         </brush>
+        </colorrole>
+       </disabled>
+      </palette>
+     </property>
+     <property name="font">
+      <font>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="mouseTracking">
+      <bool>true</bool>
+     </property>
+     <property name="contextMenuPolicy">
+      <enum>Qt::CustomContextMenu</enum>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">QListView::item:hover {
+background-color:rgb(88, 88, 88);
+}</string>
+     </property>
+     <property name="editTriggers">
+      <set>QAbstractItemView::NoEditTriggers</set>
+     </property>
+     <property name="alternatingRowColors">
+      <bool>false</bool>
+     </property>
+     <property name="selectionMode">
+      <enum>QAbstractItemView::NoSelection</enum>
+     </property>
+     <property name="iconSize">
+      <size>
+       <width>128</width>
+       <height>128</height>
+      </size>
+     </property>
+     <property name="movement">
+      <enum>QListView::Static</enum>
+     </property>
+     <property name="resizeMode">
+      <enum>QListView::Adjust</enum>
+     </property>
+     <property name="layoutMode">
+      <enum>QListView::SinglePass</enum>
+     </property>
+     <property name="spacing">
+      <number>24</number>
+     </property>
+     <property name="gridSize">
+      <size>
+       <width>200</width>
+       <height>160</height>
+      </size>
+     </property>
+     <property name="viewMode">
+      <enum>QListView::IconMode</enum>
+     </property>
+     <property name="uniformItemSizes">
+      <bool>false</bool>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+     <property name="selectionRectVisible">
+      <bool>false</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/SNAPComponent.cxx b/GUI/Qt/Components/SNAPComponent.cxx
new file mode 100644
index 0000000..b111c6d
--- /dev/null
+++ b/GUI/Qt/Components/SNAPComponent.cxx
@@ -0,0 +1,46 @@
+#include "SNAPComponent.h"
+#include "LatentITKEventNotifier.h"
+#include "QtWidgetActivator.h"
+#include "GlobalUIModel.h"
+#include "SNAPUIFlag.h"
+
+SNAPComponent::SNAPComponent(QWidget *parent) :
+    QWidget(parent)
+{
+}
+
+void
+SNAPComponent
+::connectITK(itk::Object *src, const itk::EventObject &ev, const char *slot)
+{
+  LatentITKEventNotifier::connect(src, ev, this, slot);
+}
+
+void
+SNAPComponent
+::disconnectITK(itk::Object *src, unsigned long tag)
+{
+  LatentITKEventNotifier::disconnect(src, tag);
+}
+
+/**
+  A QObject used as a convenience to detach observers from ITK objects.
+  When destroyed, this object will disconnect itself from the ITK object
+  */
+/*
+class QtObserverTagHolder : public QObject
+{
+public:
+  QtObserverTagHolder(itk::Object *source, unsigned long tag)
+    : m_Source(source), m_Tag(tag) {}
+
+  ~QtObserverTagHolder()
+  {
+    m_Source->RemoveObserver(m_Tag);
+  }
+
+private:
+  itk::Object *m_Source;
+  unsigned long m_Tag;
+};
+*/
diff --git a/GUI/Qt/Components/SNAPComponent.h b/GUI/Qt/Components/SNAPComponent.h
new file mode 100644
index 0000000..a905caf
--- /dev/null
+++ b/GUI/Qt/Components/SNAPComponent.h
@@ -0,0 +1,46 @@
+#ifndef SNAPCOMPONENT_H
+#define SNAPCOMPONENT_H
+
+#include <QWidget>
+#include "UIState.h"
+
+class EventBucket;
+class GlobalUIModel;
+
+namespace itk {
+class EventObject;
+class Object;
+}
+
+/**
+  \class SNAPComponent
+  \brief A base class for all SNAP components that consist of a set of widgets
+  layed out in a parent widget. This class has mostly helper functionality to
+  reduce the number of includes and shorten the common calls made from SNAP
+  widgets
+  */
+class SNAPComponent : public QWidget
+{
+  Q_OBJECT
+public:
+  explicit SNAPComponent(QWidget *parent = 0);
+
+
+
+public slots:
+
+  // Default slot for model updates
+  virtual void onModelUpdate(const EventBucket &bucket) {}
+
+protected:
+
+  /** Register to receive ITK events from object src. Events will be cached in
+    an event bucket and delivered once execution returns to the UI loop */
+  void connectITK(itk::Object *src, const itk::EventObject &ev,
+                  const char *slot = SLOT(onModelUpdate(const EventBucket &)));
+
+  void disconnectITK(itk::Object *src, unsigned long tag);
+
+};
+
+#endif // SNAPCOMPONENT_H
diff --git a/GUI/Qt/Components/SNAPQtCommon.cxx b/GUI/Qt/Components/SNAPQtCommon.cxx
new file mode 100644
index 0000000..6c403fc
--- /dev/null
+++ b/GUI/Qt/Components/SNAPQtCommon.cxx
@@ -0,0 +1,533 @@
+#include "SNAPQtCommon.h"
+#include <QPainter>
+#include <QPixmap>
+#include <QWidget>
+#include <QAction>
+#include <QObject>
+#include <QPushButton>
+#include <QMainWindow>
+#include <QMessageBox>
+#include <QApplication>
+#include <QMenu>
+#include <QComboBox>
+#include <QStandardItemModel>
+#include <QFileInfo>
+#include <QGraphicsItem>
+#include <QGraphicsScene>
+#include <QGraphicsDropShadowEffect>
+
+
+#include "QtCursorOverride.h"
+#include "GlobalUIModel.h"
+#include "SystemInterface.h"
+#include "IRISApplication.h"
+#include "HistoryManager.h"
+#include "SimpleFileDialogWithHistory.h"
+#include "ColorLabelTable.h"
+#include "ColorMap.h"
+#include "ColorMapModel.h"
+#include "ImageIOWizard.h"
+
+
+QIcon CreateColorBoxIcon(int w, int h, const QBrush &brush)
+{
+  QRect r(2,2,w-5,w-5);
+  QPixmap pix(w, h);
+  pix.fill(QColor(0,0,0,0));
+  QPainter paint(&pix);
+  paint.setPen(Qt::black);
+  paint.setBrush(brush);
+  paint.drawRect(r);
+  return QIcon(pix);
+}
+
+QIcon CreateColorBoxIcon(int w, int h, const QColor &rgb)
+{
+  return CreateColorBoxIcon(w, h, QBrush(rgb));
+}
+
+QIcon CreateColorBoxIcon(int w, int h, const Vector3ui &rgb)
+{
+ return CreateColorBoxIcon(w, h, QColor(rgb(0), rgb(1), rgb(2)));
+}
+
+QIcon CreateInvisibleIcon(int w, int h)
+{
+  // Add initial entries to background
+  QPixmap pix(w, h);
+  pix.fill(QColor(0,0,0,0));
+  return QIcon(pix);
+}
+
+
+#include <map>
+#include <itkObject.h>
+
+QIcon CreateColorMapIcon(int w, int h, ColorMap *cmap)
+{
+  // Maintain a static map of icons for each existing color map
+  typedef std::pair<itk::TimeStamp, QIcon> StampedIcon;
+  typedef std::map<ColorMap *, StampedIcon> IconMap;
+  static IconMap icon_map;
+
+  // Get the color map's timestamp
+  itk::TimeStamp ts_cmap = cmap->GetTimeStamp();
+
+  // Try to find the icon in the icon map
+  IconMap::iterator it = icon_map.find(cmap);
+  if(it != icon_map.end())
+    {
+    // We have created an icon for this before. Check that it's current and
+    // that it matches the requested size (only one size is cached!)
+    itk::TimeStamp ts_icon = it->second.first;
+    if(ts_cmap == ts_icon)
+      return it->second.second;
+    }
+
+  // Create the actual icon
+  QPixmap pix(w, h);
+  pix.fill(QColor(0,0,0,0));
+
+  QPainter paint(&pix);
+  for(int x = 3; x <= w-4; x++)
+    {
+    double t = (x - 3.0) / (w - 7.0);
+    ColorMap::RGBAType rgba = cmap->MapIndexToRGBA(t);
+    paint.setPen(QColor(rgba[0], rgba[1], rgba[2]));
+    paint.drawLine(x, 3, x, w-4);
+    }
+
+  paint.setPen(Qt::black);
+  QRect r(2,2,w-5,w-5);
+  paint.drawRect(r);
+
+  QIcon icon(pix);
+
+  // Save the icon
+  icon_map[cmap] = std::make_pair(ts_cmap, icon);
+  return icon;
+}
+
+QStandardItem *CreateColorMapPresetItem(
+    ColorMapModel *cmm, const std::string &preset)
+{
+  ColorMap *cm = cmm->GetPresetManager()->GetPreset(preset);
+  QIcon icon = CreateColorMapIcon(16, 16, cm);
+
+  QStandardItem *item = new QStandardItem(icon, from_utf8(preset));
+  item->setData(QVariant::fromValue(preset), Qt::UserRole);
+
+  return item;
+}
+
+void
+PopulateColorMapPresetCombo(QComboBox *combo, ColorMapModel *model)
+{
+  // Get the list of system presets and custom presets from the model
+  ColorMapModel::PresetList pSystem, pUser;
+  model->GetPresets(pSystem, pUser);
+
+  // What is the current item
+  QVariant currentItemData = combo->itemData(combo->currentIndex(), Qt::UserRole);
+  std::string currentPreset = currentItemData.value<std::string>();
+  int newIndex = -1;
+
+  // The system presets don't change, so we only need to set them the
+  // first time around
+  QStandardItemModel *sim = new QStandardItemModel();
+
+  for(unsigned int i = 0; i < pSystem.size(); i++)
+    {
+    sim->appendRow(CreateColorMapPresetItem(model, pSystem[i]));
+    if(currentPreset == pSystem[i])
+      newIndex = i;
+    }
+
+  for(unsigned int i = 0; i < pUser.size(); i++)
+    {
+    sim->appendRow(CreateColorMapPresetItem(model, pUser[i]));
+    if(currentPreset == pUser[i])
+      newIndex = pSystem.size() + i;
+    }
+
+  // Update the model
+  combo->setModel(sim);
+
+  // Set the current item if possible
+  combo->setCurrentIndex(newIndex);
+
+  // Insert separator
+  combo->insertSeparator(pSystem.size());
+}
+
+
+
+QBrush GetBrushForColorLabel(const ColorLabel &cl)
+{
+  return QBrush(QColor(cl.GetRGB(0), cl.GetRGB(1), cl.GetRGB(2)));
+}
+
+QBrush GetBrushForDrawOverFilter(DrawOverFilter flt, const ColorLabel &cl)
+{
+  switch(flt.CoverageMode)
+    {
+    case PAINT_OVER_VISIBLE:
+      return QBrush(Qt::black, Qt::Dense6Pattern);
+    case PAINT_OVER_ONE:
+      return QBrush(QColor(cl.GetRGB(0), cl.GetRGB(1), cl.GetRGB(2)));
+    case PAINT_OVER_ALL:
+      return QBrush(Qt::black, Qt::BDiagPattern);
+    }
+  return QBrush();
+}
+
+QString GetTitleForColorLabel(const ColorLabel &cl)
+{
+  return QString::fromUtf8(cl.GetLabel());
+}
+
+QString GetTitleForDrawOverFilter(DrawOverFilter flt, const ColorLabel &cl)
+{
+  switch(flt.CoverageMode)
+    {
+    case PAINT_OVER_VISIBLE:
+      return QString("All visible labels");
+    case PAINT_OVER_ONE:
+      return QString::fromUtf8(cl.GetLabel());
+    case PAINT_OVER_ALL:
+      return QString("All labels");
+    }
+  return QString();
+}
+
+QBrush GetBrushForColorLabel(int label, ColorLabelTable *clt)
+{
+  return GetBrushForColorLabel(clt->GetColorLabel(label));
+}
+
+QBrush GetBrushForDrawOverFilter(DrawOverFilter flt, ColorLabelTable *clt)
+{
+  return GetBrushForDrawOverFilter(flt, clt->GetColorLabel(flt.DrawOverLabel));
+}
+
+QString GetTitleForColorLabel(int label, ColorLabelTable *clt)
+{
+  return GetTitleForColorLabel(clt->GetColorLabel(label));
+}
+
+QString GetTitleForDrawOverFilter(DrawOverFilter flt, ColorLabelTable *clt)
+{
+  return GetTitleForDrawOverFilter(flt, clt->GetColorLabel(flt.DrawOverLabel));
+}
+
+
+QIcon CreateLabelComboIcon(int w, int h, LabelType fg, DrawOverFilter bg, ColorLabelTable *clt)
+{
+  // TODO: this could be made a little prettier
+  QGraphicsScene scene(0,0,w,h);
+
+  QPixmap pm(w, h);
+  pm.fill(QColor(0,0,0,0));
+
+  QPainter qp(&pm);
+
+  QBrush brush_fg = GetBrushForColorLabel(fg, clt);
+  QBrush brush_bg = GetBrushForDrawOverFilter(bg, clt);
+
+  QGraphicsItem *item_bg = scene.addRect(w/3,h/3,w/2+1,h/2+1,QPen(Qt::black), brush_bg);
+  scene.addRect(2,2,w/2+1,h/2+1,QPen(Qt::black), brush_fg);
+
+  QGraphicsDropShadowEffect *eff_bg = new QGraphicsDropShadowEffect(&scene);
+  eff_bg->setBlurRadius(1.0);
+  eff_bg->setOffset(1.0);
+  eff_bg->setColor(QColor(63,63,63,100));
+  item_bg->setGraphicsEffect(eff_bg);
+
+  scene.render(&qp);
+
+  return QIcon(pm);
+}
+
+QString CreateLabelComboTooltip(LabelType fg, DrawOverFilter bg, ColorLabelTable *clt)
+{
+  return QString(
+        "<html><head/><body>"
+        "<p>Foreground label:<br><span style=\" font-weight:600;\">%1</span></p>"
+        "<p>Background label:<br><span style=\" font-weight:600;\">%2</span></p>"
+        "</body></html>").
+      arg(GetTitleForColorLabel(fg, clt)).arg(GetTitleForDrawOverFilter(bg, clt));
+}
+
+
+
+
+
+
+QAction *FindUpstreamAction(QWidget *widget, const QString &targetActionName)
+{
+  // Look for a parent of QMainWindow type
+  QMainWindow *topwin = NULL;
+  for(QObject *p = widget; p != NULL; p = p->parent())
+    {
+    if((topwin = dynamic_cast<QMainWindow *>(p)) != NULL)
+      break;
+    }
+
+  // If nothing found, try a global search
+  if(!topwin)
+    {
+    QWidgetList lst = QApplication::topLevelWidgets();
+    for(QWidgetList::Iterator it = lst.begin();
+        it != lst.end(); ++it)
+      {
+      QWidget *w = *it;
+      if((topwin = dynamic_cast<QMainWindow *>(w)) != NULL)
+        break;
+      }
+    }
+
+  // Look for the action
+  QAction *result = NULL;
+  if(topwin)
+    {
+    result = topwin->findChild<QAction *>(targetActionName);
+    }
+
+  if(!result)
+      std::cerr << "Failed find upstream action " << targetActionName.toStdString() << std::endl;
+
+  return result;
+}
+
+void ConnectWidgetToTopLevelAction(
+    QWidget *w, const char *signal, QString actionName)
+{
+  QAction *action = FindUpstreamAction(w, actionName);
+  QObject::connect(w, signal, action, SLOT(trigger()));
+}
+
+bool TriggerUpstreamAction(QWidget *widget, const QString &targetActionName)
+{
+  // Find and execute the relevant action
+  QAction *action = FindUpstreamAction(widget, targetActionName);
+  if(action)
+    {
+    action->trigger();
+    return true;
+    }
+  else
+    return false;
+}
+
+QStringList toQStringList(const std::vector<std::string> inlist)
+{
+  QStringList qsl;
+  qsl.reserve(inlist.size());
+  for(std::vector<std::string>::const_iterator it = inlist.begin();
+      it != inlist.end(); ++it)
+    {
+    qsl.push_back(from_utf8(*it));
+    }
+  return qsl;
+}
+
+void ReportNonLethalException(QWidget *parent,
+                              std::exception &exc,
+                              QString windowTitleText,
+                              QString mainErrorText)
+{
+  QMessageBox b(parent);
+
+  b.setWindowTitle(QString("%1 - ITK-SNAP").arg(windowTitleText));
+  if(mainErrorText.isNull())
+    {
+    b.setText(exc.what());
+    }
+  else
+    {
+    b.setText(mainErrorText);
+    b.setDetailedText(exc.what());
+    }
+
+  b.setIcon(QMessageBox::Critical);
+  b.exec();
+}
+
+void PopulateHistoryMenu(
+    QMenu *menu, QObject *receiver, const char *slot,
+    const QStringList &local_history,
+    const QStringList &global_history)
+{
+  menu->clear();
+
+  QStringListIterator itLocal(local_history);
+  itLocal.toBack();
+  while(itLocal.hasPrevious())
+    {
+    QString entry = itLocal.previous();
+    QAction *action = menu->addAction(entry);
+    QObject::connect(action, SIGNAL(triggered()), receiver, slot);
+    }
+
+  int nLocal = menu->actions().size();
+
+  QStringListIterator itGlobal(global_history);
+  itGlobal.toBack();
+  while(itGlobal.hasPrevious())
+    {
+    QString entry = itGlobal.previous();
+    if(local_history.indexOf(entry) == -1)
+      {
+      QAction *action = menu->addAction(entry);
+      QObject::connect(action, SIGNAL(triggered()), receiver, slot);
+      }
+    }
+
+  if(nLocal > 0 && menu->actions().size() > nLocal)
+    menu->insertSeparator(menu->actions()[nLocal]);
+
+
+}
+
+
+void PopulateHistoryMenu(
+    QMenu *menu, QObject *receiver, const char *slot,
+    GlobalUIModel *model, QString hist_category)
+{
+  HistoryManager *hm =
+      model->GetDriver()->GetSystemInterface()->GetHistoryManager();
+
+  QStringList hl = toQStringList(hm->GetLocalHistory(hist_category.toStdString()));
+  QStringList hg = toQStringList(hm->GetGlobalHistory(hist_category.toStdString()));
+  PopulateHistoryMenu(menu, receiver, slot, hl, hg);
+}
+
+
+
+
+/** Show a generic file save dialog with a history dropdown */
+QString ShowSimpleSaveDialogWithHistory(
+    QWidget *parent,
+    GlobalUIModel *model, QString hist_category,
+    QString window_title, QString file_title,
+    QString file_pattern, bool force_extension,
+    QString init_file)
+{
+  return SimpleFileDialogWithHistory::showSaveDialog(
+        parent, model, window_title, file_title, hist_category, file_pattern, force_extension,init_file);
+}
+
+/** Show a generic file open dialog with a history dropdown */
+QString ShowSimpleOpenDialogWithHistory(
+    QWidget *parent, GlobalUIModel *model, QString hist_category,
+    QString window_title, QString file_title, QString file_pattern,
+    QString init_file)
+{
+  return SimpleFileDialogWithHistory::showOpenDialog(
+        parent, model, window_title, file_title, hist_category, file_pattern, init_file);
+}
+
+bool SaveImageLayer(GlobalUIModel *model, ImageWrapperBase *wrapper,
+                    LayerRole role, bool force_interactive,
+                    QWidget *parent)
+{
+  // Create a model for saving the segmentation image via a wizard
+  SmartPtr<ImageIOWizardModel> wiz_model =
+      model->CreateIOWizardModelForSave(wrapper, role);
+
+  // Interactive or not?
+  if(force_interactive || wiz_model->GetSuggestedFilename().size() == 0)
+    {
+    // Execute the IO wizard
+    ImageIOWizard wiz(parent);
+    wiz.SetModel(wiz_model);
+    wiz.exec();
+    }
+  else
+    {
+    try
+      {
+      QtCursorOverride curse(Qt::WaitCursor);
+      wiz_model->SaveImage(wiz_model->GetSuggestedFilename());
+      }
+    catch(std::exception &exc)
+      {
+      ReportNonLethalException(
+            parent, exc, "Image IO Error",
+            QString("Failed to save image %1").arg(
+              from_utf8(wiz_model->GetSuggestedFilename())));
+      }
+    }
+
+  return wiz_model->GetSaveDelegate()->IsSaveSuccessful();
+}
+
+bool SaveWorkspace(QWidget *parent, GlobalUIModel *model, bool interactive, QWidget *widget)
+{
+  // Get the currently stored project name
+  QString file_abs = from_utf8(model->GetGlobalState()->GetProjectFilename());
+
+  // Prompt for a project filename if one was not provided
+  if(interactive || file_abs.length() == 0)
+    {
+    // Use the dialog with history - to be consistent with other parts of SNAP
+    QString file = ShowSimpleSaveDialogWithHistory(
+          parent, model, "Project", "Save Workspace",
+          "Workspace File", "ITK-SNAP Workspace Files (*.itksnap)",
+          "itksnap");
+
+    // If user hits cancel, move on
+    if(file.isNull())
+      return false;
+
+    // Make sure to get an absolute path, because the project needs that info
+    file_abs = QFileInfo(file).absoluteFilePath();
+    }
+
+  // If file was provided, set it as the current project file
+  try
+    {
+    model->GetDriver()->SaveProject(to_utf8(file_abs));
+    return true;
+    }
+  catch(exception &exc)
+    {
+    ReportNonLethalException(widget, exc, "Error Saving Project",
+                             QString("Failed to save project %1").arg(file_abs));
+    return false;
+    }
+}
+
+#include <QFileDialog>
+#include <QFileInfo>
+
+// TODO: this is so f***ng lame! Global variable!!! Put this inside of
+// a class!!!!
+#include <QMap>
+#include <QDir>
+#include <GenericImageData.h>
+#include <QStandardPaths>
+
+QMap<QString, QDir> g_CategoryToLastPathMap;
+
+QString GetFileDialogPath(GlobalUIModel *model, const char *HistoryName)
+{
+  // Already have something for this category? Then use it
+  if(g_CategoryToLastPathMap.find(HistoryName) != g_CategoryToLastPathMap.end())
+    return g_CategoryToLastPathMap[HistoryName].absolutePath();
+
+  // Is there a main image loaded
+  if(model->GetDriver()->IsMainImageLoaded())
+    {
+    QString fn = from_utf8(model->GetDriver()->GetCurrentImageData()->GetMain()->GetFileName());
+    return QFileInfo(fn).absolutePath();
+    }
+
+  // Use home directory
+  return QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first();
+}
+
+void UpdateFileDialogPathForCategory(const char *HistoryName, QString dir)
+{
+  g_CategoryToLastPathMap[HistoryName] = QDir(dir);
+}
diff --git a/GUI/Qt/Components/SNAPQtCommon.h b/GUI/Qt/Components/SNAPQtCommon.h
new file mode 100644
index 0000000..314e9b1
--- /dev/null
+++ b/GUI/Qt/Components/SNAPQtCommon.h
@@ -0,0 +1,155 @@
+#ifndef SNAPQTCOMMON_H
+#define SNAPQTCOMMON_H
+
+#include <QBrush>
+#include <QIcon>
+#include <QObject>
+#include <SNAPCommon.h>
+#include <string>
+#include <QMetaType>
+
+Q_DECLARE_METATYPE(std::string)
+
+class QWidget;
+class QAction;
+class GlobalUIModel;
+class QMenu;
+class QSlider;
+class QSpinBox;
+class ColorLabelTable;
+class ColorLabel;
+class ColorMap;
+class QComboBox;
+class ColorMapModel;
+class ImageWrapperBase;
+
+// Generate an icon with a black border and a given fill color
+QIcon CreateColorBoxIcon(int w, int h, const QBrush &brush);
+QIcon CreateColorBoxIcon(int w, int h, const QColor &rgb);
+QIcon CreateColorBoxIcon(int w, int h, const Vector3ui &rgb);
+QIcon CreateInvisibleIcon(int w, int h);
+
+// This creates an icon for a given color map. This function uses internal
+// caching so that the icon is only regenerated if the color map has been
+// modified since the last time the icon was generated.
+QIcon CreateColorMapIcon(int w, int h, ColorMap *cmap);
+
+/**
+ * Generate a combo box with color map presets. Ideally, this would be handled
+ * through the coupling mechanism, but the mechanism does not currently support
+ * separators. Such a combo box is required in a few places, so it made sense to
+ * put the code here
+ */
+void PopulateColorMapPresetCombo(QComboBox *combo, ColorMapModel *model);
+
+// Generate a brush corresponding to a color label
+QBrush GetBrushForColorLabel(const ColorLabel &cl);
+QBrush GetBrushForDrawOverFilter(DrawOverFilter flt, const ColorLabel &cl);
+QString GetTitleForColorLabel(const ColorLabel &cl);
+QString GetTitleForDrawOverFilter(DrawOverFilter flt, const ColorLabel &cl);
+
+QBrush GetBrushForColorLabel(int label, ColorLabelTable *clt);
+QBrush GetBrushForDrawOverFilter(DrawOverFilter flt, ColorLabelTable *clt);
+QString GetTitleForColorLabel(int label, ColorLabelTable *clt);
+QString GetTitleForDrawOverFilter(DrawOverFilter flt, ColorLabelTable *clt);
+
+// Create an icon and tooltip corresponding to a combination of a drawing label
+// and a draw-over label
+QIcon CreateLabelComboIcon(int w, int h, LabelType fg, DrawOverFilter bg, ColorLabelTable *clt);
+QString CreateLabelComboTooltip(LabelType fg, DrawOverFilter bg, ColorLabelTable *clt);
+
+
+// Find an upstream action for a widget
+QAction* FindUpstreamAction(QWidget *w, const QString &targetActionName);
+
+// Connect a widget to the trigger slot in an upstream action
+void ConnectWidgetToTopLevelAction(QWidget *w, const char *signal, QString actionName);
+
+// Trigger an upstream action in a Qt widget. Return code is true
+// if the upstream action was found, false otherwise
+bool TriggerUpstreamAction(QWidget *w, const QString &targetActionName);
+
+// Convert a container of std::strings into a QStringList
+QStringList toQStringList(const std::vector<std::string> inlist);
+
+// Find a parent window of appropriate class
+template <class TWidget>
+TWidget *findParentWidget(QObject *w)
+{
+  do
+    {
+    w = w->parent();
+    if(w)
+      {
+      TWidget *tw = dynamic_cast<TWidget *>(w);
+      if(tw)
+        return tw;
+      }
+    }
+  while(w);
+  return NULL;
+}
+
+// Couple a slider and a
+
+// Standard way for handling non-lethal exceptions
+void ReportNonLethalException(QWidget *parent,
+                              std::exception &exc,
+                              QString windowTitleText,
+                              QString mainErrorText = QString());
+
+/** Populate a menu with history items */
+void PopulateHistoryMenu(
+    QMenu *menu, QObject *receiver, const char *slot,
+    GlobalUIModel *model, QString hist_category);
+
+void PopulateHistoryMenu(
+    QMenu *menu, QObject *receiver, const char *slot,
+    const QStringList &local_history, const QStringList &global_history);
+
+/** Get the path in which to open a file dialog */
+QString GetFileDialogPath(GlobalUIModel *model, const char *HistoryName);
+
+/** Save the path where something was saved */
+void UpdateFileDialogPathForCategory(const char *HistoryName, QString dir);
+
+/** Show a generic file save dialog with a history dropdown */
+QString ShowSimpleSaveDialogWithHistory(QWidget *parent, GlobalUIModel *model, QString hist_category,
+    QString window_title, QString file_title, QString file_pattern,
+    bool force_extension, QString init_file = QString());
+
+/** Show a generic file open dialog with a history dropdown */
+QString ShowSimpleOpenDialogWithHistory(QWidget *parent, GlobalUIModel *model, QString hist_category,
+    QString window_title, QString file_title, QString file_pattern, QString init_file = QString());
+
+/**
+ * This static save method provides a simple interface for saving an
+ * image layer either interactively or non-interactively depending on
+ * whether the image layer has a filename set. Exceptions are handled
+ * within the method. The method returns true if the image was actually
+ * saved, and false if there was a problem, or user cancelled.
+ */
+bool SaveImageLayer(GlobalUIModel *model, ImageWrapperBase *wrapper,
+                    LayerRole role, bool force_interactive = false,
+                    QWidget *parent = NULL);
+
+
+/**
+ * A static method to save the project/workspace to file
+ */
+bool SaveWorkspace(QWidget *parent, GlobalUIModel *model, bool interactive, QWidget *widget);
+
+/** Convert a QString to a std::string using UTF8 encoding */
+inline std::string to_utf8(const QString &qstring)
+{
+  return std::string(qstring.toUtf8().constData());
+}
+
+/** Convert an std::string with UTF8 encoding to a Qt string */
+inline QString from_utf8(const std::string &input)
+{
+  return QString::fromUtf8(input.c_str());
+}
+
+
+#endif // SNAPQTCOMMON_H
diff --git a/GUI/Qt/Components/SliceViewPanel.cxx b/GUI/Qt/Components/SliceViewPanel.cxx
new file mode 100644
index 0000000..6170d2e
--- /dev/null
+++ b/GUI/Qt/Components/SliceViewPanel.cxx
@@ -0,0 +1,503 @@
+#include "SliceViewPanel.h"
+#include "ui_SliceViewPanel.h"
+
+#include "GlobalUIModel.h"
+#include "SNAPEvents.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "itkCommand.h"
+#include "CrosshairsRenderer.h"
+#include "PolygonDrawingRenderer.h"
+#include "PaintbrushRenderer.h"
+#include "SnakeROIRenderer.h"
+#include "SnakeROIModel.h"
+#include "SliceWindowCoordinator.h"
+#include "PolygonDrawingModel.h"
+#include "QtWidgetActivator.h"
+#include "SnakeModeRenderer.h"
+#include "SnakeWizardModel.h"
+#include "DisplayLayoutModel.h"
+#include "PaintbrushModel.h"
+#include "SliceWindowDecorationRenderer.h"
+#include "MainImageWindow.h"
+#include "SNAPQtCommon.h"
+#include "QtScrollbarCoupling.h"
+#include <QCursor>
+#include <QBitmap>
+
+#include <QStackedLayout>
+#include <QMenu>
+
+SliceViewPanel::SliceViewPanel(QWidget *parent) :
+    SNAPComponent(parent),
+    ui(new Ui::SliceViewPanel)
+{
+  ui->setupUi(this);
+
+  // Initialize
+  m_GlobalUI = NULL;
+  m_SliceModel = NULL;
+
+  // Create my own renderers
+  m_SnakeModeRenderer = SnakeModeRenderer::New();
+  m_DecorationRenderer = SliceWindowDecorationRenderer::New();
+
+  QString menuStyle = "font-size: 12px;";
+
+  // Create the popup menus for the polygon mode
+  m_MenuPolyInactive = new QMenu(ui->imPolygon);
+  m_MenuPolyInactive->setStyleSheet(menuStyle);
+  m_MenuPolyInactive->addAction(ui->actionPaste);
+
+  m_MenuPolyDrawing = new QMenu(ui->imPolygon);
+  m_MenuPolyDrawing->setStyleSheet(menuStyle);
+  m_MenuPolyDrawing->addAction(ui->actionComplete);
+  m_MenuPolyDrawing->addAction(ui->actionCompleteAndAccept);
+  m_MenuPolyDrawing->addAction(ui->actionUndo);
+  m_MenuPolyDrawing->addAction(ui->actionClearDrawing);
+
+  m_MenuPolyEditing = new QMenu(ui->imPolygon);
+  m_MenuPolyEditing->setStyleSheet(menuStyle);
+  m_MenuPolyEditing->addAction(ui->actionAccept);
+  m_MenuPolyEditing->addAction(ui->actionDeleteSelected);
+  m_MenuPolyEditing->addAction(ui->actionSplitSelected);
+  m_MenuPolyEditing->addAction(ui->actionClearPolygon);
+
+  // Connect the actions to the toolbar buttons (sucks to do this by hand)
+  ui->btnAcceptPolygon->setDefaultAction(ui->actionAccept);
+  ui->btnPastePolygon->setDefaultAction(ui->actionPaste);
+  ui->btnClearDrawing->setDefaultAction(ui->actionClearDrawing);
+  ui->btnCloseLoop->setDefaultAction(ui->actionComplete);
+  ui->btnDeleteNodes->setDefaultAction(ui->actionDeleteSelected);
+  ui->btnDeletePolygon->setDefaultAction(ui->actionClearPolygon);
+  ui->btnSplitNodes->setDefaultAction(ui->actionSplitSelected);
+  ui->btnUndoLast->setDefaultAction(ui->actionUndo);
+
+  this->addAction(ui->actionZoom_In);
+  this->addAction(ui->actionZoom_Out);
+
+  // Connect the context menu signal from polygon mode to this widget
+  connect(ui->imPolygon, SIGNAL(contextMenuRequested()), SLOT(onContextMenu()));
+
+  // Arrange the interaction modes into a tree structure. The first child of
+  // every interaction mode is an empty QWidget. The tree is used to allow
+  // events to fall through from one interaction mode to another
+
+  // TODO: can we think of a more dynamic system for doing this? Essentially,
+  // there is a pipeline through which events pass through, which is
+  // reconfigured when the mode changes.
+
+
+  // Add all the individual interactors to the main panel using a stacked
+  // layout. This assures that all of the interactors have the same size as
+  // the sliceView. The actual propagation of events is handled by the
+  // event filter logic.
+  /*
+  QStackedLayout *loMain = new QStackedLayout();
+  loMain->setContentsMargins(0,0,0,0);
+  loMain->addWidget(ui->imCrosshairs);
+  loMain->addWidget(ui->imZoomPan);
+  loMain->addWidget(ui->imThumbnail);
+  loMain->addWidget(ui->imPolygon);
+  loMain->addWidget(ui->imSnakeROI);
+  loMain->addWidget(ui->imPaintbrush);
+  delete ui->sliceView->layout();
+  ui->sliceView->setLayout(loMain);
+  */
+
+  // Configure the initial event chain
+  m_CurrentEventFilter = NULL;
+  ConfigureEventChain(ui->imCrosshairs);
+
+  // Also lay out the pages
+  QStackedLayout *loPages = new QStackedLayout();
+  loPages->addWidget(ui->pageDefault);
+  loPages->addWidget(ui->pagePolygonDraw);
+  loPages->addWidget(ui->pagePolygonEdit);
+  loPages->addWidget(ui->pagePolygonInactive);
+  delete ui->toolbar->layout();
+  ui->toolbar->setLayout(loPages);
+
+  // Send wheel events from Crosshairs mode to the slider
+  ui->imCrosshairs->SetWheelEventTargetWidget(ui->inSlicePosition);
+
+  // Set page size on the slice position widget
+  ui->inSlicePosition->setPageStep(5);
+
+  // Set up the drawing cursor
+  QBitmap bmBitmap(":/root/crosshair_cursor_bitmap.png");
+  QBitmap bmMask(":/root/crosshair_cursor_mask.png");
+  m_DrawingCrosshairCursor = new QCursor(bmBitmap, bmMask, 7, 7);
+}
+
+SliceViewPanel::~SliceViewPanel()
+{
+  delete ui;
+  delete m_DrawingCrosshairCursor;
+}
+
+GenericSliceView * SliceViewPanel::GetSliceView()
+{
+  return ui->sliceView;
+}
+
+void SliceViewPanel::Initialize(GlobalUIModel *model, unsigned int index)
+{
+  // Store the model
+  this->m_GlobalUI = model;
+  this->m_Index = index;
+
+  // Get the slice model
+  m_SliceModel = m_GlobalUI->GetSliceModel(index);
+
+  // Initialize the slice view
+  ui->sliceView->SetModel(m_SliceModel);
+
+  // Initialize the interaction modes
+  ui->imCrosshairs->SetModel(m_GlobalUI->GetCursorNavigationModel(index));
+  ui->imZoomPan->SetModel(m_GlobalUI->GetCursorNavigationModel(index));
+  ui->imZoomPan->SetMouseButtonBehaviorToZoomPanMode();
+  ui->imThumbnail->SetModel(m_GlobalUI->GetCursorNavigationModel(index));
+  ui->imPolygon->SetModel(m_GlobalUI->GetPolygonDrawingModel(index));
+  ui->imSnakeROI->SetModel(m_GlobalUI->GetSnakeROIModel(index));
+  ui->imPaintbrush->SetModel(m_GlobalUI->GetPaintbrushModel(index));
+
+  // Initialize the 'orphan' renderers (without a custom widget)
+  GenericSliceRenderer *parentRenderer =
+      static_cast<GenericSliceRenderer *>(ui->sliceView->GetRenderer());
+
+  m_DecorationRenderer->SetParentRenderer(parentRenderer);
+  m_SnakeModeRenderer->SetParentRenderer(parentRenderer);
+  m_SnakeModeRenderer->SetModel(m_GlobalUI->GetSnakeWizardModel());
+
+  // Listen to cursor change events, which require a repaint of the slice view
+  connectITK(m_GlobalUI->GetDriver(), CursorUpdateEvent());
+  connectITK(m_GlobalUI->GetDriver(), MainImageDimensionsChangeEvent());
+
+  // Add listener for changes to the model
+  connectITK(m_SliceModel, ModelUpdateEvent());
+
+  // Listen to toolbar change events
+  connectITK(m_GlobalUI, ToolbarModeChangeEvent());
+
+  // Listen to polygon state change events
+  connectITK(m_GlobalUI->GetPolygonDrawingModel(index),
+             StateMachineChangeEvent());
+
+  // Listen to the Snake ROI model too
+  connectITK(m_GlobalUI->GetSnakeROIModel(index),
+             ModelUpdateEvent());
+
+  // Listen to paintbrush motion
+  connectITK(m_GlobalUI->GetPaintbrushModel(index),
+             PaintbrushModel::PaintbrushMovedEvent());
+
+  // Listen to all (?) events from the snake wizard as well
+  connectITK(m_GlobalUI->GetSnakeWizardModel(), IRISEvent());
+
+  // Widget coupling
+  makeCoupling(ui->inSlicePosition, m_SliceModel->GetSliceIndexModel());
+
+  // Activation
+  activateOnFlag(this, m_GlobalUI, UIF_BASEIMG_LOADED);
+
+  // Set up activation for polygon buttons
+  PolygonDrawingModel *pm = m_GlobalUI->GetPolygonDrawingModel(index);
+
+  activateOnAllFlags(ui->actionAccept, pm, UIF_EDITING, UIF_HAVEPOLYGON);
+  activateOnAllFlags(ui->actionPaste, pm, UIF_INACTIVE, UIF_HAVECACHED);
+  activateOnAllFlags(ui->actionClearDrawing, pm, UIF_DRAWING, UIF_HAVEPOLYGON);
+  activateOnAllFlags(ui->actionComplete, pm, UIF_DRAWING, UIF_HAVEPOLYGON);
+  activateOnAllFlags(ui->actionCompleteAndAccept, pm, UIF_DRAWING, UIF_HAVEPOLYGON);
+  activateOnAllFlags(ui->actionDeleteSelected, pm, UIF_EDITING, UIF_HAVE_VERTEX_SELECTION);
+  activateOnAllFlags(ui->actionSplitSelected, pm, UIF_EDITING, UIF_HAVE_EDGE_SELECTION);
+  activateOnAllFlags(ui->actionUndo, pm, UIF_DRAWING, UIF_HAVEPOLYGON);
+  activateOnAllFlags(ui->actionClearPolygon, pm, UIF_EDITING, UIF_HAVEPOLYGON);
+
+  // Update the expand view button
+  this->UpdateExpandViewButton();
+
+  // Listen to the events affecting the expand view button
+  DisplayLayoutModel *dlm = m_GlobalUI->GetDisplayLayoutModel();
+  connectITK(dlm, DisplayLayoutModel::ViewPanelLayoutChangeEvent());
+  connectITK(dlm, DisplayLayoutModel::LayerLayoutChangeEvent());
+
+  // Arrange the rendering overlays and widgets based on current mode
+  this->OnToolbarModeChange();
+}
+
+void SliceViewPanel::onModelUpdate(const EventBucket &eb)
+{
+  if(eb.HasEvent(ToolbarModeChangeEvent()) ||
+     eb.HasEvent(StateMachineChangeEvent()))
+    {
+    OnToolbarModeChange();
+    }
+  if(eb.HasEvent(DisplayLayoutModel::ViewPanelLayoutChangeEvent()) ||
+     eb.HasEvent(DisplayLayoutModel::LayerLayoutChangeEvent()))
+    {
+    UpdateExpandViewButton();
+    }
+  ui->sliceView->update();
+}
+
+void SliceViewPanel::on_inSlicePosition_valueChanged(int value)
+{
+  // Update the text output
+  int pos = ui->inSlicePosition->value();
+  int lim = ui->inSlicePosition->maximum();
+  ui->lblSliceInfo->setText(QString("%1 of %2").arg(pos+1).arg(lim+1));
+}
+
+void SliceViewPanel::ConfigureEventChain(QWidget *w)
+{
+  // Remove all event filters from the slice view
+  QObjectList kids = ui->sliceView->children();
+  for(QObjectList::Iterator it = kids.begin(); it!=kids.end(); ++it)
+    ui->sliceView->removeEventFilter(*it);
+
+  // Now add the event filters in the order in which we want them to react
+  // to events. The last event filter is first to receive events, and should
+  // thus be the thumbnail interaction mode. The first event filter is always
+  // the crosshairs interaction mode, which is the fallback for all others.
+  ui->sliceView->installEventFilter(ui->imCrosshairs);
+
+  // If the current mode is not crosshairs mode, add it as the filter
+  if(w != ui->imCrosshairs)
+    {
+    ui->sliceView->installEventFilter(w);
+    }
+
+  // The last guy in the chain is the thumbnail interactor
+  ui->sliceView->installEventFilter(ui->imThumbnail);
+}
+
+// TODO: implement semi-transparent rendering on widgets on top of the
+// OpenGL scene using code from
+// http://www.qtcentre.org/wiki/index.php?title=Accelerate_your_Widgets_with_OpenGL
+void SliceViewPanel::enterEvent(QEvent *)
+{
+  /*
+  ui->mainToolbar->show();
+  ui->sidebar->show();
+  */
+}
+
+void SliceViewPanel::leaveEvent(QEvent *)
+{
+  /*
+  ui->mainToolbar->hide();
+  ui->sidebar->hide();
+  */
+
+
+}
+
+void SliceViewPanel::SetActiveMode(QWidget *mode, bool clearChildren)
+{
+  // If the widget does not have a stacked layout, do nothing, we've reached
+  // the end of the recursion
+  QStackedLayout *loParent =
+      dynamic_cast<QStackedLayout *>(mode->parentWidget()->layout());
+
+  if(loParent)
+    {
+    // Set the mode as the current widget in the parent
+    loParent->setCurrentWidget(mode);
+
+    // Make sure the parent widget is also the current widget
+    SetActiveMode(mode->parentWidget(), false);
+
+    // Make sure no children are selected
+    if(clearChildren)
+      {
+      // If the selected mode has child modes, make sure none is selected
+      QStackedLayout *lo = dynamic_cast<QStackedLayout *>(mode->layout());
+      if(lo)
+        lo->setCurrentIndex(0);
+      }
+    }
+}
+
+void SliceViewPanel::OnToolbarModeChange()
+{
+  // Get the renderer and configure its overlays
+  GenericSliceRenderer *ren = (GenericSliceRenderer *) ui->sliceView->GetRenderer();
+
+  // Configure the renderers
+  GenericSliceRenderer::RendererDelegateList &ovTiled = ren->GetTiledOverlays();
+  GenericSliceRenderer::RendererDelegateList &ovGlobal = ren->GetGlobalOverlays();
+
+  // Append the overlays in the right order
+  ovTiled.clear();
+  ovTiled.push_back(m_SnakeModeRenderer);
+  ovTiled.push_back(ui->imCrosshairs->GetRenderer());
+  ovTiled.push_back(ui->imPolygon->GetRenderer());
+
+  ovGlobal.clear();
+  ovGlobal.push_back(m_DecorationRenderer);
+
+  switch(m_GlobalUI->GetGlobalState()->GetToolbarMode())
+    {
+    case POLYGON_DRAWING_MODE:
+      ConfigureEventChain(ui->imPolygon);
+      break;
+    case PAINTBRUSH_MODE:
+      ConfigureEventChain(ui->imPaintbrush);
+      ovTiled.push_back(ui->imPaintbrush->GetRenderer());
+      break;
+    case ANNOTATION_MODE:
+      break;
+    case ROI_MODE:
+      ConfigureEventChain(ui->imSnakeROI);
+      ovTiled.push_back(ui->imSnakeROI->GetRenderer());
+      break;
+    case CROSSHAIRS_MODE:
+      ConfigureEventChain(ui->imCrosshairs);
+      break;
+    case NAVIGATION_MODE:
+      ConfigureEventChain(ui->imZoomPan);
+      break;
+    }
+
+  // Need to change to the appropriate page
+  QStackedLayout *loPages =
+      static_cast<QStackedLayout *>(ui->toolbar->layout());
+  if(m_GlobalUI->GetGlobalState()->GetToolbarMode() == POLYGON_DRAWING_MODE)
+    {
+    switch(m_GlobalUI->GetPolygonDrawingModel(m_Index)->GetState())
+      {
+      case PolygonDrawingModel::DRAWING_STATE:
+        loPages->setCurrentWidget(ui->pagePolygonDraw); break;
+      case PolygonDrawingModel::EDITING_STATE:
+        loPages->setCurrentWidget(ui->pagePolygonEdit); break;
+      case PolygonDrawingModel::INACTIVE_STATE:
+        loPages->setCurrentWidget(ui->pagePolygonInactive); break;
+      }
+    }
+  else
+    loPages->setCurrentWidget(ui->pageDefault);
+}
+
+void SliceViewPanel::on_btnZoomToFit_clicked()
+{
+  m_GlobalUI->GetSliceCoordinator()->ResetViewToFitInOneWindow(m_Index);
+
+}
+
+void SliceViewPanel::onContextMenu()
+{
+  if(m_GlobalUI->GetGlobalState()->GetToolbarMode() == POLYGON_DRAWING_MODE)
+    {
+    QMenu *menu = NULL;
+    switch(m_GlobalUI->GetPolygonDrawingModel(m_Index)->GetState())
+      {
+      case PolygonDrawingModel::DRAWING_STATE:
+        menu = m_MenuPolyDrawing; break;
+      case PolygonDrawingModel::EDITING_STATE:
+        menu = m_MenuPolyEditing; break;
+      case PolygonDrawingModel::INACTIVE_STATE:
+        menu = m_MenuPolyInactive; break;
+      }
+
+    if(menu)
+      {
+      menu->popup(QCursor::pos());
+      }
+    }
+}
+
+void SliceViewPanel::SetMouseMotionTracking(bool enable)
+{
+  ui->sliceView->setMouseTracking(enable);
+  // TODO: in the future, consider using a better cursor for polygon drawing operations
+  /*
+  if(enable)
+    this->setCursor(*m_DrawingCrosshairCursor);
+  else
+    this->setCursor(QCursor(Qt::ArrowCursor));
+    */
+}
+
+void SliceViewPanel::on_btnExpand_clicked()
+{
+  // Get the layout applied when the button is pressed
+  DisplayLayoutModel *dlm = m_GlobalUI->GetDisplayLayoutModel();
+  DisplayLayoutModel::ViewPanelLayout layout =
+      dlm->GetViewPanelExpandButtonActionModel(m_Index)->GetValue();
+
+  // Apply this layout
+  dlm->GetViewPanelLayoutModel()->SetValue(layout);
+}
+
+void SliceViewPanel::UpdateExpandViewButton()
+{
+  // Get the layout applied when the button is pressed
+  DisplayLayoutModel *dlm = m_GlobalUI->GetDisplayLayoutModel();
+  DisplayLayoutModel::ViewPanelLayout layout =
+      dlm->GetViewPanelExpandButtonActionModel(m_Index)->GetValue();
+
+  // Set the appropriate icon
+  static const char* iconNames[] =
+    { "fourviews", "axial", "coronal", "sagittal", "3d" };
+
+  QString iconFile = QString(":/root/dl_%1.png").arg(iconNames[layout]);
+  ui->btnExpand->setIcon(QIcon(iconFile));
+
+  // Set the tooltip
+  if(layout == DisplayLayoutModel::VIEW_ALL)
+    {
+    ui->btnExpand->setToolTip("Restore the four-panel display configuration");
+    }
+  else
+    {
+    ui->btnExpand->setToolTip("Expand this view to occupy the entire window");
+    }
+
+  // Also expand the tile/cascade button
+  LayerLayout ll = dlm->GetSliceViewLayerLayoutModel()->GetValue();
+  if(ll == LAYOUT_TILED)
+    {
+    ui->btnToggleLayout->setIcon(QIcon(":/root/layout_overlay_16.png"));
+    ui->btnToggleLayout->setToolTip("Render image overlays on top of each other");
+    }
+  else if(ll == LAYOUT_STACKED)
+    {
+    ui->btnToggleLayout->setIcon(QIcon(":/root/layout_tile_16.png"));
+    ui->btnToggleLayout->setToolTip("Tile image overlays side by side");
+    }
+}
+
+
+void SliceViewPanel::on_btnScreenshot_clicked()
+{
+  MainImageWindow *parent = findParentWidget<MainImageWindow>(this);
+  parent->ExportScreenshot(m_Index);
+}
+
+void SliceViewPanel::on_btnToggleLayout_clicked()
+{
+  DisplayLayoutModel *dlm = m_GlobalUI->GetDisplayLayoutModel();
+  LayerLayout ll = dlm->GetSliceViewLayerLayoutModel()->GetValue();
+  if(ll == LAYOUT_TILED)
+    {
+    dlm->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_STACKED);
+    }
+  else
+    {
+    dlm->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED);
+    }
+}
+
+void SliceViewPanel::on_actionZoom_In_triggered()
+{
+  // Zoom in
+  m_GlobalUI->GetSliceCoordinator()->ZoomInOrOutInOneWindow(m_Index, 1.1);
+}
+
+void SliceViewPanel::on_actionZoom_Out_triggered()
+{
+  // Zoom out
+  m_GlobalUI->GetSliceCoordinator()->ZoomInOrOutInOneWindow(m_Index, 1.0 / 1.1);
+}
diff --git a/GUI/Qt/Components/SliceViewPanel.h b/GUI/Qt/Components/SliceViewPanel.h
new file mode 100644
index 0000000..6034d45
--- /dev/null
+++ b/GUI/Qt/Components/SliceViewPanel.h
@@ -0,0 +1,108 @@
+#ifndef SLICEVIEWPANEL_H
+#define SLICEVIEWPANEL_H
+
+#include <SNAPComponent.h>
+#include <GlobalState.h>
+
+class GenericSliceView;
+class QMenu;
+class QtInteractionDelegateWidget;
+class SnakeModeRenderer;
+class SliceWindowDecorationRenderer;
+class GenericSliceModel;
+class QCursor;
+
+namespace Ui {
+    class SliceViewPanel;
+}
+
+class SliceViewPanel : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit SliceViewPanel(QWidget *parent = 0);
+  ~SliceViewPanel();
+
+  // Register the data model with this widget
+  void Initialize(GlobalUIModel *model, unsigned int index);
+
+  // Get the index of this panel
+  irisGetMacro(Index, unsigned int)
+
+  GenericSliceView *GetSliceView();
+
+  // Callback for when the toolbar changes
+  void SetMouseMotionTracking(bool enable);
+
+
+private slots:
+  void on_inSlicePosition_valueChanged(int value);
+
+  void on_btnZoomToFit_clicked();
+
+  void onModelUpdate(const EventBucket &eb);
+
+  void OnToolbarModeChange();
+
+  void onContextMenu();
+
+  void on_btnExpand_clicked();
+
+  void on_btnScreenshot_clicked();
+
+  void on_btnToggleLayout_clicked();
+
+  void on_actionZoom_In_triggered();
+
+  void on_actionZoom_Out_triggered();
+
+private:
+  Ui::SliceViewPanel *ui;
+
+  // Popup menus used for polygon operations
+  QMenu *m_MenuPolyInactive, *m_MenuPolyEditing, *m_MenuPolyDrawing;
+
+  // Current event filter on the crosshair widget
+  QWidget *m_CurrentEventFilter;
+
+  // Global UI pointer
+  GlobalUIModel *m_GlobalUI;
+
+  // Slice model
+  GenericSliceModel *m_SliceModel;
+
+  // Custom cursor for drawing operations
+  QCursor *m_DrawingCrosshairCursor;
+
+  // Some renderers don't require a separate widget (no user interaction)
+  // and so they are owned by this panel.
+  SmartPtr<SnakeModeRenderer> m_SnakeModeRenderer;
+  SmartPtr<SliceWindowDecorationRenderer> m_DecorationRenderer;
+
+
+  // Index of the panel
+  unsigned int m_Index;
+
+  void SetActiveMode(QWidget *mode, bool clearChildren = true);
+
+  /**
+  The common setup is to have an event filter chain
+    widget -- crosshair -- active_mode -- thumbnail
+  In other words, all events first go to the thumbnail,
+  then to the active mode, then to the crosshair mode
+  */
+  void ConfigureEventChain(QWidget *w);
+
+  /**
+   * Listen to mouse enter/exit events in order to show and hide toolbars
+   */
+  void enterEvent(QEvent *);
+  void leaveEvent(QEvent *);
+
+  /** Update the expand view / contract view button based on the state */
+  void UpdateExpandViewButton();
+
+};
+
+#endif // SLICEVIEWPANEL_H
diff --git a/GUI/Qt/Components/SliceViewPanel.ui b/GUI/Qt/Components/SliceViewPanel.ui
new file mode 100644
index 0000000..c9bcc4d
--- /dev/null
+++ b/GUI/Qt/Components/SliceViewPanel.ui
@@ -0,0 +1,983 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SliceViewPanel</class>
+ <widget class="QWidget" name="SliceViewPanel">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>542</width>
+    <height>382</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">* {
+font-size:11px;
+}</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <property name="spacing">
+    <number>2</number>
+   </property>
+   <item row="1" column="1" alignment="Qt::AlignHCenter">
+    <widget class="QWidget" name="sidebar" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>2</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QToolButton" name="btnExpand">
+        <property name="maximumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="icon">
+         <iconset>
+          <normalon>:/root/dl_axial.png</normalon>
+         </iconset>
+        </property>
+        <property name="autoRaise">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnToggleLayout">
+        <property name="maximumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="icon">
+         <iconset resource="../Resources/SNAPResources.qrc">
+          <normaloff>:/root/layout_overlay_16.png</normaloff>
+          <normalon>:/root/layout_tile_16.png</normalon>:/root/layout_overlay_16.png</iconset>
+        </property>
+        <property name="checkable">
+         <bool>false</bool>
+        </property>
+        <property name="checked">
+         <bool>false</bool>
+        </property>
+        <property name="autoRaise">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnScreenshot">
+        <property name="maximumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Save a screenshot</string>
+        </property>
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="icon">
+         <iconset>
+          <normalon>:/root/screencapture2.gif</normalon>
+         </iconset>
+        </property>
+        <property name="autoRaise">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item alignment="Qt::AlignHCenter">
+       <widget class="QScrollBar" name="inSlicePosition">
+        <property name="enabled">
+         <bool>true</bool>
+        </property>
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="2">
+    <widget class="QWidget" name="mainToolbar" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_6">
+      <property name="spacing">
+       <number>4</number>
+      </property>
+      <property name="leftMargin">
+       <number>10</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>10</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QWidget" name="toolbar" native="true">
+        <layout class="QVBoxLayout" name="verticalLayout">
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QWidget" name="pageDefault" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <property name="spacing">
+             <number>4</number>
+            </property>
+            <property name="topMargin">
+             <number>0</number>
+            </property>
+            <property name="bottomMargin">
+             <number>0</number>
+            </property>
+            <item>
+             <spacer name="horizontalSpacer">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnZoomToFit">
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="font">
+               <font>
+                <pointsize>-1</pointsize>
+               </font>
+              </property>
+              <property name="toolTip">
+               <string/>
+              </property>
+              <property name="text">
+               <string>zoom to fit</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QWidget" name="pagePolygonDraw" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout">
+            <property name="spacing">
+             <number>4</number>
+            </property>
+            <property name="topMargin">
+             <number>0</number>
+            </property>
+            <property name="bottomMargin">
+             <number>0</number>
+            </property>
+            <item>
+             <spacer name="horizontalSpacer_2">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnCloseLoop">
+              <property name="minimumSize">
+               <size>
+                <width>64</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="font">
+               <font>
+                <pointsize>-1</pointsize>
+               </font>
+              </property>
+              <property name="toolTip">
+               <string/>
+              </property>
+              <property name="text">
+               <string>complete</string>
+              </property>
+              <property name="toolButtonStyle">
+               <enum>Qt::ToolButtonTextOnly</enum>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnUndoLast">
+              <property name="minimumSize">
+               <size>
+                <width>96</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="font">
+               <font>
+                <pointsize>-1</pointsize>
+               </font>
+              </property>
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Helvetica'; font-size:11px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Deletes the last point added to the polygon</p></body></html></string>
+              </property>
+              <property name="text">
+               <string>undo last point</string>
+              </property>
+              <property name="toolButtonStyle">
+               <enum>Qt::ToolButtonTextOnly</enum>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnClearDrawing">
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="font">
+               <font>
+                <pointsize>-1</pointsize>
+               </font>
+              </property>
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Helvetica'; font-size:11px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Clears the current polygon so you can start drawing from scratch</p></body></html></string>
+              </property>
+              <property name="text">
+               <string>clear</string>
+              </property>
+              <property name="toolButtonStyle">
+               <enum>Qt::ToolButtonTextOnly</enum>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QWidget" name="pagePolygonEdit" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout_3">
+            <property name="spacing">
+             <number>4</number>
+            </property>
+            <property name="topMargin">
+             <number>0</number>
+            </property>
+            <property name="bottomMargin">
+             <number>0</number>
+            </property>
+            <item>
+             <spacer name="horizontalSpacer_3">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnAcceptPolygon">
+              <property name="minimumSize">
+               <size>
+                <width>64</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="font">
+               <font>
+                <pointsize>-1</pointsize>
+               </font>
+              </property>
+              <property name="toolTip">
+               <string/>
+              </property>
+              <property name="text">
+               <string>accept</string>
+              </property>
+              <property name="toolButtonStyle">
+               <enum>Qt::ToolButtonTextOnly</enum>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnDeleteNodes">
+              <property name="minimumSize">
+               <size>
+                <width>46</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="font">
+               <font>
+                <pointsize>-1</pointsize>
+               </font>
+              </property>
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Helvetica'; font-size:11px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Deletes the selected vertices in the polygon</p></body></html></string>
+              </property>
+              <property name="text">
+               <string>delete</string>
+              </property>
+              <property name="toolButtonStyle">
+               <enum>Qt::ToolButtonTextOnly</enum>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnSplitNodes">
+              <property name="minimumSize">
+               <size>
+                <width>46</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="font">
+               <font>
+                <pointsize>-1</pointsize>
+               </font>
+              </property>
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Helvetica'; font-size:11px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Splits each selected edge in the polygon by inserting a new vertex in the middle</p></body></html></string>
+              </property>
+              <property name="text">
+               <string>split</string>
+              </property>
+              <property name="toolButtonStyle">
+               <enum>Qt::ToolButtonTextOnly</enum>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnDeletePolygon">
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="font">
+               <font>
+                <pointsize>-1</pointsize>
+               </font>
+              </property>
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Helvetica'; font-size:11px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Deletes the entire polygon, so you can draw a new one from scratch</p></body></html></string>
+              </property>
+              <property name="text">
+               <string>clear</string>
+              </property>
+              <property name="toolButtonStyle">
+               <enum>Qt::ToolButtonTextOnly</enum>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QWidget" name="pagePolygonInactive" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout_5">
+            <property name="spacing">
+             <number>4</number>
+            </property>
+            <property name="topMargin">
+             <number>0</number>
+            </property>
+            <property name="bottomMargin">
+             <number>0</number>
+            </property>
+            <item>
+             <spacer name="horizontalSpacer_4">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QToolButton" name="btnPastePolygon">
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>20</height>
+               </size>
+              </property>
+              <property name="font">
+               <font>
+                <pointsize>-1</pointsize>
+               </font>
+              </property>
+              <property name="toolTip">
+               <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Helvetica'; font-size:11px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pastes the last polygon that you have accepted in this slice view. You can then move the vertices in the pasted polygon to fit image data. This can be more efficient than drawing a new polygon when performing segmentation across multiple slices.</p></body></html></string>
+              </property>
+              <property name="text">
+               <string>paste last polygon</string>
+              </property>
+              <property name="toolButtonStyle">
+               <enum>Qt::ToolButtonTextOnly</enum>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="lblSliceInfo">
+        <property name="minimumSize">
+         <size>
+          <width>64</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>-1</pointsize>
+         </font>
+        </property>
+        <property name="styleSheet">
+         <string notr="true">font-size:11px;</string>
+        </property>
+        <property name="text">
+         <string>TextLabel</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="GenericSliceView" name="sliceView" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+       <horstretch>1</horstretch>
+       <verstretch>1</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>40</width>
+       <height>40</height>
+      </size>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_4">
+      <item>
+       <widget class="CrosshairsInteractionMode" name="imCrosshairs" native="true"/>
+      </item>
+      <item>
+       <widget class="CrosshairsInteractionMode" name="imZoomPan" native="true"/>
+      </item>
+      <item>
+       <widget class="ThumbnailInteractionMode" name="imThumbnail" native="true"/>
+      </item>
+      <item>
+       <widget class="PolygonDrawingInteractionMode" name="imPolygon" native="true"/>
+      </item>
+      <item>
+       <widget class="SnakeROIInteractionMode" name="imSnakeROI" native="true"/>
+      </item>
+      <item>
+       <widget class="PaintbrushInteractionMode" name="imPaintbrush" native="true"/>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+  <action name="actionAccept">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/popup_ok_16.png</normaloff>:/root/popup_ok_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Accept Polygon</string>
+   </property>
+   <property name="iconText">
+    <string>accept</string>
+   </property>
+   <property name="toolTip">
+    <string>Incorporates the polygon into the segmentation.</string>
+   </property>
+   <property name="shortcut">
+    <string>Return</string>
+   </property>
+  </action>
+  <action name="actionPaste">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/popup_paste_16.png</normaloff>:/root/popup_paste_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Paste Last Polygon</string>
+   </property>
+   <property name="iconText">
+    <string>paste last polygon</string>
+   </property>
+   <property name="toolTip">
+    <string>Pastes the last polygon that you have accepted in this slice view. You can then move the vertices in the pasted polygon to fit image data. This can be more efficient than drawing a new polygon when performing segmentation across multiple slices.</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+V</string>
+   </property>
+  </action>
+  <action name="actionComplete">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/popup_edit_16.png</normaloff>:/root/popup_edit_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Complete Polygon and Edit</string>
+   </property>
+   <property name="iconText">
+    <string>complete</string>
+   </property>
+   <property name="toolTip">
+    <string>Finishes drawing the polygon by connecting the last point to the first. The window will enter "editing" mode, where you can modify the polygon.</string>
+   </property>
+   <property name="shortcut">
+    <string>Return</string>
+   </property>
+  </action>
+  <action name="actionUndo">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/popup_undo_16.png</normaloff>:/root/popup_undo_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Undo Last Point</string>
+   </property>
+   <property name="iconText">
+    <string>undo last point</string>
+   </property>
+   <property name="toolTip">
+    <string>Deletes the last point added to the polygon</string>
+   </property>
+   <property name="shortcut">
+    <string>Backspace</string>
+   </property>
+  </action>
+  <action name="actionClearDrawing">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/popup_clear_16.png</normaloff>:/root/popup_clear_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Clear Drawing</string>
+   </property>
+   <property name="iconText">
+    <string>clear</string>
+   </property>
+   <property name="toolTip">
+    <string>Clears the current polygon so you can start drawing from scratch</string>
+   </property>
+   <property name="shortcut">
+    <string>Esc</string>
+   </property>
+  </action>
+  <action name="actionDeleteSelected">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/popup_delete_16.png</normaloff>:/root/popup_delete_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Trim Selected Vertices</string>
+   </property>
+   <property name="iconText">
+    <string>trim</string>
+   </property>
+   <property name="toolTip">
+    <string>Deletes the selected vertices in the polygon</string>
+   </property>
+   <property name="shortcut">
+    <string>-</string>
+   </property>
+  </action>
+  <action name="actionSplitSelected">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/popup_split_16.png</normaloff>:/root/popup_split_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Split Selected Edges</string>
+   </property>
+   <property name="iconText">
+    <string>split</string>
+   </property>
+   <property name="toolTip">
+    <string>Splits each selected edge in the polygon by inserting a new vertex in the middle</string>
+   </property>
+   <property name="shortcut">
+    <string>+</string>
+   </property>
+  </action>
+  <action name="actionClearPolygon">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/popup_clear_16.png</normaloff>:/root/popup_clear_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Clear Polygon</string>
+   </property>
+   <property name="iconText">
+    <string>clear</string>
+   </property>
+   <property name="toolTip">
+    <string>Deletes the entire polygon, so you can draw a new one from scratch</string>
+   </property>
+   <property name="shortcut">
+    <string>Esc</string>
+   </property>
+  </action>
+  <action name="actionCompleteAndAccept">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/popup_ok_16.png</normaloff>:/root/popup_ok_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Complete Polygon and Accept</string>
+   </property>
+   <property name="toolTip">
+    <string>Finishes drawing the polygon by connecting the last point to the first, then incorporates the polygon into the segmentation. This bypasses the editing mode.</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Return</string>
+   </property>
+  </action>
+  <action name="actionZoom_In">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/icons8_zoomin_16.png</normaloff>:/root/icons8_zoomin_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Zoom In</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Up</string>
+   </property>
+   <property name="shortcutContext">
+    <enum>Qt::WidgetWithChildrenShortcut</enum>
+   </property>
+  </action>
+  <action name="actionZoom_Out">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/icons8_zoomout_16.png</normaloff>:/root/icons8_zoomout_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Zoom Out</string>
+   </property>
+   <property name="toolTip">
+    <string>Zoom Out</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Down</string>
+   </property>
+   <property name="shortcutContext">
+    <enum>Qt::WidgetWithChildrenShortcut</enum>
+   </property>
+  </action>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>GenericSliceView</class>
+   <extends>QWidget</extends>
+   <header>GenericSliceView.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>CrosshairsInteractionMode</class>
+   <extends>QWidget</extends>
+   <header>CrosshairsInteractionMode.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>ThumbnailInteractionMode</class>
+   <extends>QWidget</extends>
+   <header>ThumbnailInteractionMode.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>PolygonDrawingInteractionMode</class>
+   <extends>QWidget</extends>
+   <header>PolygonDrawingInteractionMode.h</header>
+   <container>1</container>
+   <slots>
+    <slot>onAcceptPolygon()</slot>
+    <slot>onPastePolygon()</slot>
+    <slot>onSplitSelected()</slot>
+    <slot>onDeleteSelected()</slot>
+    <slot>onClearPolygon()</slot>
+    <slot>onCloseLoopAndEdit()</slot>
+    <slot>onUndoLastPoint()</slot>
+    <slot>onCancelDrawing()</slot>
+    <slot>onCloseLoopAndAccept()</slot>
+   </slots>
+  </customwidget>
+  <customwidget>
+   <class>SnakeROIInteractionMode</class>
+   <extends>QWidget</extends>
+   <header>SnakeROIInteractionMode.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>PaintbrushInteractionMode</class>
+   <extends>QWidget</extends>
+   <header>PaintbrushInteractionMode.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>actionComplete</sender>
+   <signal>triggered()</signal>
+   <receiver>imPolygon</receiver>
+   <slot>onCloseLoopAndEdit()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>440</x>
+     <y>168</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionUndo</sender>
+   <signal>triggered()</signal>
+   <receiver>imPolygon</receiver>
+   <slot>onUndoLastPoint()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>466</x>
+     <y>195</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionClearDrawing</sender>
+   <signal>triggered()</signal>
+   <receiver>imPolygon</receiver>
+   <slot>onCancelDrawing()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>486</x>
+     <y>211</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionDeleteSelected</sender>
+   <signal>triggered()</signal>
+   <receiver>imPolygon</receiver>
+   <slot>onDeleteSelected()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>407</x>
+     <y>188</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionSplitSelected</sender>
+   <signal>triggered()</signal>
+   <receiver>imPolygon</receiver>
+   <slot>onSplitSelected()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>499</x>
+     <y>179</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionClearPolygon</sender>
+   <signal>triggered()</signal>
+   <receiver>imPolygon</receiver>
+   <slot>onClearPolygon()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>470</x>
+     <y>188</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionPaste</sender>
+   <signal>triggered()</signal>
+   <receiver>imPolygon</receiver>
+   <slot>onPastePolygon()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>426</x>
+     <y>204</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionAccept</sender>
+   <signal>triggered()</signal>
+   <receiver>imPolygon</receiver>
+   <slot>onAcceptPolygon()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>452</x>
+     <y>132</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionCompleteAndAccept</sender>
+   <signal>triggered()</signal>
+   <receiver>imPolygon</receiver>
+   <slot>onCloseLoopAndAccept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>452</x>
+     <y>132</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/GUI/Qt/Components/SnakeToolROIPanel.cxx b/GUI/Qt/Components/SnakeToolROIPanel.cxx
new file mode 100644
index 0000000..1b62b25
--- /dev/null
+++ b/GUI/Qt/Components/SnakeToolROIPanel.cxx
@@ -0,0 +1,75 @@
+#include "SnakeToolROIPanel.h"
+#include "ui_SnakeToolROIPanel.h"
+
+#include <SNAPQtCommon.h>
+#include <QtSpinBoxCoupling.h>
+#include <QtWidgetArrayCoupling.h>
+#include <GlobalUIModel.h>
+#include <SnakeROIModel.h>
+#include <MainImageWindow.h>
+#include "SnakeROIResampleModel.h"
+#include "GlobalState.h"
+
+#include "ResampleDialog.h"
+
+SnakeToolROIPanel::SnakeToolROIPanel(QWidget *parent) :
+  SNAPComponent(parent),
+  ui(new Ui::SnakeToolROIPanel)
+{
+  ui->setupUi(this);
+  m_ResampleDialog = new ResampleDialog(this);
+}
+
+SnakeToolROIPanel::~SnakeToolROIPanel()
+{
+  delete ui;
+}
+
+void SnakeToolROIPanel::SetModel(GlobalUIModel *model)
+{
+  // Store the model
+  m_Model = model;
+
+  // Pass the model to the resample dialog
+  m_ResampleDialog->SetModel(model->GetSnakeROIResampleModel());
+
+  // Hook up the couplings for the ROI size controls
+  makeArrayCoupling(
+        ui->inIndexX, ui->inIndexY, ui->inIndexZ,
+        model->GetSnakeROIIndexModel());
+
+  makeArrayCoupling(
+        ui->inSizeX, ui->inSizeY, ui->inSizeZ,
+        model->GetSnakeROISizeModel());
+}
+
+void SnakeToolROIPanel::on_btnResetROI_clicked()
+{
+  // Reset the ROI
+  m_Model->GetSnakeROIModel(0)->ResetROI();
+}
+
+void SnakeToolROIPanel::on_btnAuto_clicked()
+{
+  // TODO: Check that the label configuration is valid
+
+  // Handle resampling if requested
+  if(ui->chkResample->isChecked())
+    {
+    if(m_ResampleDialog->exec() != QDialog::Accepted)
+      return;
+    }
+  else
+    {
+    // Make sure that no interpolation is applied
+    m_Model->GetSnakeROIResampleModel()->Reset();
+    m_Model->GetSnakeROIResampleModel()->Accept();
+    }
+
+  // Switch to crosshairs mode
+  m_Model->GetGlobalState()->SetToolbarMode(CROSSHAIRS_MODE);
+
+  // Show the snake panel
+  MainImageWindow *main = findParentWidget<MainImageWindow>(this);
+  main->OpenSnakeWizard();
+}
diff --git a/GUI/Qt/Components/SnakeToolROIPanel.h b/GUI/Qt/Components/SnakeToolROIPanel.h
new file mode 100644
index 0000000..cfb0e64
--- /dev/null
+++ b/GUI/Qt/Components/SnakeToolROIPanel.h
@@ -0,0 +1,35 @@
+#ifndef SNAKETOOLROIPANEL_H
+#define SNAKETOOLROIPANEL_H
+
+#include <SNAPComponent.h>
+
+class GlobalUIModel;
+class ResampleDialog;
+
+namespace Ui {
+class SnakeToolROIPanel;
+}
+
+class SnakeToolROIPanel : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit SnakeToolROIPanel(QWidget *parent = 0);
+  ~SnakeToolROIPanel();
+
+  void SetModel(GlobalUIModel *);
+
+private slots:
+  void on_btnResetROI_clicked();
+
+  void on_btnAuto_clicked();
+
+private:
+  Ui::SnakeToolROIPanel *ui;
+
+  GlobalUIModel *m_Model;
+  ResampleDialog *m_ResampleDialog;
+};
+
+#endif // SNAKETOOLROIPANEL_H
diff --git a/GUI/Qt/Components/SnakeToolROIPanel.ui b/GUI/Qt/Components/SnakeToolROIPanel.ui
new file mode 100644
index 0000000..c618710
--- /dev/null
+++ b/GUI/Qt/Components/SnakeToolROIPanel.ui
@@ -0,0 +1,342 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SnakeToolROIPanel</class>
+ <widget class="QWidget" name="SnakeToolROIPanel">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>215</width>
+    <height>439</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">* {
+font-size: 12px;
+}
+
+QSpinBox {
+font-size: 11px;
+}
+</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>160</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+      </font>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">* {
+font-size: 11px;
+}
+</string>
+     </property>
+     <property name="text">
+      <string>This tool selects the region of interest (ROI) for automatic segmentation.</string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line_2">
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_4">
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+      </font>
+     </property>
+     <property name="text">
+      <string>ROI Dimensions</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_6" native="true">
+     <layout class="QGridLayout" name="gridLayout_3">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <property name="spacing">
+       <number>4</number>
+      </property>
+      <item row="0" column="0" rowspan="2" colspan="3">
+       <widget class="QLabel" name="label_3">
+        <property name="font">
+         <font>
+          <pointsize>-1</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>Corner position (x,y,z):</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QSpinBox" name="inIndexX">
+        <property name="maximumSize">
+         <size>
+          <width>64</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="buttonSymbols">
+         <enum>QAbstractSpinBox::NoButtons</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QSpinBox" name="inIndexY">
+        <property name="maximumSize">
+         <size>
+          <width>64</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="buttonSymbols">
+         <enum>QAbstractSpinBox::NoButtons</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="2">
+       <widget class="QSpinBox" name="inIndexZ">
+        <property name="maximumSize">
+         <size>
+          <width>64</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="buttonSymbols">
+         <enum>QAbstractSpinBox::NoButtons</enum>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_7" native="true">
+     <layout class="QGridLayout" name="gridLayout_4">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <property name="spacing">
+       <number>4</number>
+      </property>
+      <item row="0" column="0" rowspan="2" colspan="3">
+       <widget class="QLabel" name="label_2">
+        <property name="font">
+         <font>
+          <pointsize>-1</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>Size (x,y,z):</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QSpinBox" name="inSizeX">
+        <property name="maximumSize">
+         <size>
+          <width>64</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="buttonSymbols">
+         <enum>QAbstractSpinBox::NoButtons</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QSpinBox" name="inSizeY">
+        <property name="maximumSize">
+         <size>
+          <width>64</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="buttonSymbols">
+         <enum>QAbstractSpinBox::NoButtons</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="2">
+       <widget class="QSpinBox" name="inSizeZ">
+        <property name="maximumSize">
+         <size>
+          <width>64</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="buttonSymbols">
+         <enum>QAbstractSpinBox::NoButtons</enum>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_3" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_3">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QPushButton" name="btnResetROI">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>120</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>-1</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>Reset ROI</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line">
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>10</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="chkResample">
+        <property name="toolTip">
+         <string>When this option is selected, you will have an option to change the resolution of the region of interest (i.e., subsample or supersample) before running automatic segmentation.</string>
+        </property>
+        <property name="text">
+         <string>Resample ROI</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_2" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QPushButton" name="btnAuto">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>120</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>-1</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>Segment 3D</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/SnakeWizardPanel.cxx b/GUI/Qt/Components/SnakeWizardPanel.cxx
new file mode 100644
index 0000000..51ecfef
--- /dev/null
+++ b/GUI/Qt/Components/SnakeWizardPanel.cxx
@@ -0,0 +1,475 @@
+#include "SnakeWizardPanel.h"
+#include "ui_SnakeWizardPanel.h"
+#include "SpeedImageDialog.h"
+#include "SnakeParameterDialog.h"
+#include "GlobalUIModel.h"
+#include "SnakeWizardModel.h"
+#include "QtCursorOverride.h"
+#include "QtComboBoxCoupling.h"
+#include "QtWidgetActivator.h"
+#include "QtDoubleSliderWithEditorCoupling.h"
+#include <QtAbstractItemViewCoupling.h>
+#include <QtPagedWidgetCoupling.h>
+#include "QtSpinBoxCoupling.h"
+#include "QtDoubleSpinBoxCoupling.h"
+#include "QtSliderCoupling.h"
+#include "QtRadioButtonCoupling.h"
+#include "ColorLabelQuickListWidget.h"
+#include "IRISException.h"
+#include <QMessageBox>
+#include <QTimer>
+#include <IRISApplication.h>
+#include <QToolBar>
+
+Q_DECLARE_METATYPE(PreprocessingMode)
+
+/**
+ * An item model for editing bubble data
+ */
+void BubbleItemModel::setSourceModel(SnakeWizardModel *model)
+{
+  m_Model = model;
+  LatentITKEventNotifier::connect(
+        model, SnakeWizardModel::BubbleListUpdateEvent(),
+        this, SLOT(onBubbleListUpdate()));
+  LatentITKEventNotifier::connect(
+        model, SnakeWizardModel::BubbleDefaultRadiusUpdateEvent(),
+        this, SLOT(onBubbleValuesUpdate()));
+}
+
+int BubbleItemModel::rowCount(const QModelIndex &parent) const
+{
+  // Only top-level items exist
+  if(parent.isValid())
+    {
+    return 0;
+    }
+  else
+    {
+    std::vector<Bubble> &ba = m_Model->GetParent()->GetDriver()->GetBubbleArray();
+    return ba.size();
+    }
+}
+
+int BubbleItemModel::columnCount(const QModelIndex &parent) const
+{
+  return 4;
+}
+
+QVariant BubbleItemModel::data(const QModelIndex &index, int role) const
+{
+  std::vector<Bubble> &ba = m_Model->GetParent()->GetDriver()->GetBubbleArray();
+  Bubble &b = ba[index.row()];
+  if(role == Qt::EditRole || role == Qt::DisplayRole)
+    {
+    if(index.column()==3)
+      return QString("%1").arg(b.radius);
+    else
+      return QString("%1").arg(b.center[index.column()]+1);
+    }
+  else if(role == Qt::UserRole)
+    {
+    // This is so that the selection model coupling works
+    return index.row();
+    }
+  return QVariant();
+}
+
+bool BubbleItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+  std::vector<Bubble> &ba = m_Model->GetParent()->GetDriver()->GetBubbleArray();
+  Bubble b = ba[index.row()];
+  bool modified = false;
+
+  if(index.column()==3)
+    {
+    bool convok;
+    double dv = value.toDouble(&convok);
+    if(convok && dv > 0 && b.radius != dv)
+      {
+      b.radius = dv;
+      modified = true;
+      }
+    }
+  else
+    {
+    bool convok;
+    int iv = value.toInt(&convok);
+    if(convok && b.center[index.column()]+1 != iv)
+      {
+      b.center[index.column()] = iv-1;
+      modified = true;
+      }
+    }
+
+  if(modified)
+    return m_Model->UpdateBubble(index.row(), b);
+
+  return false;
+}
+
+Qt::ItemFlags BubbleItemModel::flags(const QModelIndex &index) const
+{
+  Qt::ItemFlags flags =
+      Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
+  return flags;
+}
+
+QVariant BubbleItemModel::headerData(
+    int section, Qt::Orientation orientation, int role) const
+{
+  if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
+    {
+    switch(section)
+      {
+      case 0 : return tr("X");
+      case 1 : return tr("Y");
+      case 2 : return tr("Z");
+      case 3 : return tr("Radius");
+      }
+    }
+  return QVariant();
+}
+
+void BubbleItemModel::onBubbleListUpdate()
+{
+  emit layoutChanged();
+}
+
+void BubbleItemModel::onBubbleValuesUpdate()
+{
+  emit dataChanged(this->index(0,0),
+                   this->index(this->rowCount(QModelIndex())-1,3));
+}
+
+
+
+SnakeWizardPanel::SnakeWizardPanel(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::SnakeWizardPanel)
+{
+  ui->setupUi(this);
+
+  m_SpeedDialog = new SpeedImageDialog(this);
+  m_ParameterDialog = new SnakeParameterDialog(this);
+
+  // Hook up the timer!
+  m_EvolutionTimer = new QTimer(this);
+  connect(m_EvolutionTimer, SIGNAL(timeout()), this, SLOT(idleCallback()));
+
+  // Hook up the quick label selector
+  connect(ui->boxLabelQuickList, SIGNAL(actionTriggered(QAction *)),
+          this, SLOT(onClassifyQuickLabelSelection()));
+
+  // Adjust the shortcuts for increase/decrease behavior
+  ui->actionIncreaseBubbleRadius->setShortcuts(
+        ui->actionIncreaseBubbleRadius->shortcuts() << QKeySequence('='));
+
+  ui->actionDecreaseBubbleRadius->setShortcuts(
+        ui->actionDecreaseBubbleRadius->shortcuts() << QKeySequence('_'));
+
+  this->addAction(ui->actionIncreaseBubbleRadius);
+  this->addAction(ui->actionDecreaseBubbleRadius);
+}
+
+SnakeWizardPanel::~SnakeWizardPanel()
+{
+  delete ui;
+}
+
+#include "QtToolbarCoupling.h"
+
+void SnakeWizardPanel::SetModel(GlobalUIModel *model)
+{
+  // Store and pass on the models
+  m_ParentModel = model;
+  m_Model = model->GetSnakeWizardModel();
+  m_SpeedDialog->SetModel(m_Model);
+  m_ParameterDialog->SetModel(model->GetSnakeParameterModel());
+
+  // Couple widgets to models
+  makeCoupling(ui->inBubbleRadius, m_Model->GetBubbleRadiusModel());
+
+
+  // Couple the preprocessing mode combo box
+  makeCoupling(ui->inPreprocessMode, m_Model->GetPreprocessingModeModel());
+
+  // Couple the preprocessing mode stack
+  std::map<PreprocessingMode, QWidget *> preproc_page_map;
+  preproc_page_map[PREPROCESS_THRESHOLD] = ui->pgThreshold;
+  preproc_page_map[PREPROCESS_EDGE] = ui->pgEdge;
+  preproc_page_map[PREPROCESS_GMM] = ui->pgCluster;
+  preproc_page_map[PREPROCESS_RF] = ui->pgClassify;
+  preproc_page_map[PREPROCESS_NONE] = ui->pgUserSpeed;
+  makePagedWidgetCoupling(ui->stackPreprocess, m_Model->GetPreprocessingModeModel(),
+                          preproc_page_map);
+
+  // Couple the thresholding controls
+  makeCoupling(ui->inThreshLowerSlider, m_Model->GetThresholdLowerModel());
+  makeCoupling(ui->inThreshLowerSpin, m_Model->GetThresholdLowerModel());
+  makeCoupling(ui->inThreshUpperSlider, m_Model->GetThresholdUpperModel());
+  makeCoupling(ui->inThreshUpperSpin, m_Model->GetThresholdUpperModel());
+  makeRadioGroupCoupling(ui->grpThreshMode, m_Model->GetThresholdModeModel());
+
+  // Activation of thresholding controls
+  activateOnFlag(ui->inThreshLowerSlider, m_Model, SnakeWizardModel::UIF_LOWER_THRESHOLD_ENABLED);
+  activateOnFlag(ui->inThreshLowerSpin, m_Model, SnakeWizardModel::UIF_LOWER_THRESHOLD_ENABLED);
+  activateOnFlag(ui->inThreshUpperSlider, m_Model, SnakeWizardModel::UIF_UPPER_THRESHOLD_ENABLED);
+  activateOnFlag(ui->inThreshUpperSpin, m_Model, SnakeWizardModel::UIF_UPPER_THRESHOLD_ENABLED);
+
+  // Couple the clustering controls
+  makeCoupling(ui->inClusterCount, m_Model->GetNumberOfClustersModel());
+  makeCoupling(ui->inClusterActive, m_Model->GetForegroundClusterModel());
+
+  // Couple the classification controls
+  makeCoupling(ui->inClassifyForeground, m_Model->GetForegroundClassColorLabelModel());
+  makeCoupling(ui->inClassifyTrees, m_Model->GetForestSizeModel());
+
+  // Couple the edge preprocessing controls
+  makeCoupling(ui->inEdgeScale, m_Model->GetEdgePreprocessingSigmaModel());
+  makeCoupling(ui->inEdgeScaleSlider, m_Model->GetEdgePreprocessingSigmaModel());
+
+  // Initialize the label quick list
+  ui->boxLabelQuickList->SetModel(m_Model->GetParent());
+
+  // Set up a model for the bubbles table
+  BubbleItemModel *biModel = new BubbleItemModel(this);
+  biModel->setSourceModel(m_Model);
+  ui->tableBubbleList->setModel(biModel);
+
+  makeCoupling((QAbstractItemView *) ui->tableBubbleList,
+               m_Model->GetActiveBubbleModel());
+
+  makeCoupling(ui->inStepSize, m_Model->GetStepSizeModel());
+  makeCoupling(ui->outIteration, m_Model->GetEvolutionIterationModel());
+
+  // Activation flags
+  /*
+  activateOnNotFlag(ui->pgPreproc, m_Model,
+                    SnakeWizardModel::UIF_PREPROCESSING_ACTIVE);
+                    */
+
+  activateOnFlag(ui->btnNextPreproc, m_Model,
+                 SnakeWizardModel::UIF_CAN_GENERATE_SPEED);
+
+  activateOnFlag(ui->btnRemoveBubble, m_Model,
+                 SnakeWizardModel::UIF_BUBBLE_SELECTED);
+
+  activateOnFlag(ui->btnBubbleNext, m_Model,
+                 SnakeWizardModel::UIF_INITIALIZATION_VALID);
+}
+
+void SnakeWizardPanel::Initialize()
+{
+  // Initialize the model
+  m_Model->OnSnakeModeEnter();
+
+  // Go to the right page
+  ui->stack->setCurrentWidget(ui->pgPreproc);
+}
+
+void SnakeWizardPanel::on_btnNextPreproc_clicked()
+{
+  // Compute the speed image
+  m_Model->ApplyPreprocessing();
+
+  // Finish preprocessing
+  m_Model->CompletePreprocessing();
+
+  // Initialize the model
+  m_Model->OnBubbleModeEnter();
+
+  // Move to the bubble page
+  ui->stack->setCurrentWidget(ui->pgBubbles);
+}
+
+void SnakeWizardPanel::on_btnAddBubble_clicked()
+{
+  m_Model->AddBubbleAtCursor();
+}
+
+void SnakeWizardPanel::on_btnRemoveBubble_clicked()
+{
+  m_Model->RemoveBubbleAtCursor();
+}
+
+void SnakeWizardPanel::on_btnBubbleNext_clicked()
+{
+  // Call the initialization code
+  try
+  {
+    // Handle cursor
+    QtCursorOverride curse(Qt::WaitCursor);
+
+    // Initialize the evolution layers
+    m_Model->OnEvolutionPageEnter();
+
+    // Move to the evolution page
+    ui->stack->setCurrentWidget(ui->pgEvolution);
+  }
+  catch(IRISException &exc)
+  {
+    QMessageBox::warning(this, "ITK-SNAP", exc.what(), QMessageBox::Ok);
+  }
+}
+
+void SnakeWizardPanel::on_btnBubbleBack_clicked()
+{
+  // Move to the preprocessing page
+  ui->stack->setCurrentWidget(ui->pgPreproc);
+
+  // Tell the model
+  m_Model->OnBubbleModeBack();
+}
+
+void SnakeWizardPanel::on_stack_currentChanged(int page)
+{
+  // The stack at the top follows the stack at the bottom
+  ui->stackStepInfo->setCurrentIndex(page);
+}
+
+void SnakeWizardPanel::on_btnPlay_toggled(bool checked)
+{
+  // This is where we toggle the snake evolution!
+  if(checked)
+    m_EvolutionTimer->start(10);
+  else
+    m_EvolutionTimer->stop();
+}
+
+void SnakeWizardPanel::idleCallback()
+{
+  // Step the snake. If converged (returns true), stop playing
+  if(m_Model->PerformEvolutionStep())
+    ui->btnPlay->setChecked(false);
+}
+
+void SnakeWizardPanel::on_btnSingleStep_clicked()
+{
+  // Turn off the play button (will turn off the timer too)
+  ui->btnPlay->setChecked(false);
+
+  // Perform a single step
+  m_Model->PerformEvolutionStep();
+}
+
+
+void SnakeWizardPanel::on_btnEvolutionBack_clicked()
+{
+  // Turn off the play button (will turn off the timer too)
+  ui->btnPlay->setChecked(false);
+
+  // Tell the model to return to initialization state
+  m_Model->OnEvolutionPageBack();
+
+  // Flip to previous page
+  ui->stack->setCurrentWidget(ui->pgBubbles);
+}
+
+void SnakeWizardPanel::on_btnEvolutionNext_clicked()
+{
+  // Turn off the play button (will turn off the timer too)
+  ui->btnPlay->setChecked(false);
+
+  // Tell the model to return to initialization state
+  m_Model->OnEvolutionPageFinish();
+
+  // Tell parent to hide this window
+  emit wizardFinished();
+}
+
+void SnakeWizardPanel::on_btnRewind_clicked()
+{
+  // Turn off the play button (will turn off the timer too)
+  ui->btnPlay->setChecked(false);
+
+  // Tell the model to return to initialization state
+  m_Model->RewindEvolution();
+}
+
+void SnakeWizardPanel::on_btnEvolutionParameters_clicked()
+{
+  m_ParameterDialog->show();
+  m_ParameterDialog->activateWindow();
+  m_ParameterDialog->raise();
+}
+
+void SnakeWizardPanel::on_btnCancel_clicked()
+{
+  // Turn off the play button (will turn off the timer too)
+  ui->btnPlay->setChecked(false);
+
+  // Make sure all dialogs are closed
+  m_SpeedDialog->close();
+  m_ParameterDialog->close();
+
+  // Tell the model to return to initialization state
+  m_Model->OnCancelSegmentation();
+
+  // Tell parent to hide this window
+  emit wizardFinished();
+}
+
+void SnakeWizardPanel::on_actionIncreaseBubbleRadius_triggered()
+{
+  ui->inBubbleRadius->stepUp();
+}
+
+void SnakeWizardPanel::on_actionDecreaseBubbleRadius_triggered()
+{
+  ui->inBubbleRadius->stepDown();
+}
+
+void SnakeWizardPanel::on_btnClusterIterate_clicked()
+{
+  m_Model->PerformClusteringIteration();
+}
+
+void SnakeWizardPanel::on_btnClusterIterateMany_clicked()
+{
+  for(int i = 0; i < 10; i++)
+    m_Model->PerformClusteringIteration();
+}
+
+void SnakeWizardPanel::on_btnClusterReinitialize_clicked()
+{
+  m_Model->ReinitializeClustering();
+}
+
+void SnakeWizardPanel::on_btnClassifyTrain_clicked()
+{
+  try
+  {
+    m_Model->TrainClassifier();
+  }
+  catch (IRISException &exc)
+  {
+    ReportNonLethalException(this, exc, "Classification Failed");
+  }
+}
+
+void SnakeWizardPanel::on_btnThreshDetail_clicked()
+{
+  m_SpeedDialog->ShowDialog();
+}
+
+void SnakeWizardPanel::on_btnClusterDetail_clicked()
+{
+  m_SpeedDialog->ShowDialog();
+}
+
+void SnakeWizardPanel::on_btnClassifyClearExamples_clicked()
+{
+  m_Model->ClearSegmentation();
+}
+
+void SnakeWizardPanel::onClassifyQuickLabelSelection()
+{
+  // Enter paintbrush mode - to help the user
+  m_Model->GetParent()->GetGlobalState()->SetToolbarMode(PAINTBRUSH_MODE);
+}
+
+void SnakeWizardPanel::on_btnEdgeDetail_clicked()
+{
+  m_SpeedDialog->ShowDialog();
+}
diff --git a/GUI/Qt/Components/SnakeWizardPanel.h b/GUI/Qt/Components/SnakeWizardPanel.h
new file mode 100644
index 0000000..731b8d6
--- /dev/null
+++ b/GUI/Qt/Components/SnakeWizardPanel.h
@@ -0,0 +1,134 @@
+#ifndef SNAKEWIZARDPANEL_H
+#define SNAKEWIZARDPANEL_H
+
+#include <QWidget>
+#include <QAbstractItemModel>
+
+namespace Ui {
+class SnakeWizardPanel;
+}
+
+class SpeedImageDialog;
+class GlobalUIModel;
+class SnakeWizardModel;
+class QTimer;
+class SnakeParameterDialog;
+class QToolBar;
+
+class BubbleItemModel : public QAbstractTableModel
+{
+  Q_OBJECT
+
+public:
+  BubbleItemModel(QObject *parent) : QAbstractTableModel(parent) {}
+  virtual ~BubbleItemModel() {}
+
+  void setSourceModel(SnakeWizardModel *model);
+
+  virtual int rowCount(const QModelIndex &parent) const;
+  virtual int columnCount(const QModelIndex &parent) const;
+  virtual QVariant data(const QModelIndex &index, int role) const;
+  virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
+
+  virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+
+  virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+public slots:
+
+  void onBubbleListUpdate();
+  void onBubbleValuesUpdate();
+
+private:
+  SnakeWizardModel *m_Model;
+};
+
+
+
+class SnakeWizardPanel : public QWidget
+{
+  Q_OBJECT
+
+public:
+  explicit SnakeWizardPanel(QWidget *parent = 0);
+  ~SnakeWizardPanel();
+
+  void SetModel(GlobalUIModel *model);
+
+  /**
+    Put the panel into the initial state, i.e., ready to perform preprocessing.
+    You must call this method before showing the panel.
+    */
+  void Initialize();
+
+signals:
+
+  void wizardFinished();
+
+private slots:
+
+  void on_btnNextPreproc_clicked();
+
+  void on_btnAddBubble_clicked();
+
+  void on_btnRemoveBubble_clicked();
+
+  void on_btnBubbleNext_clicked();
+
+  void on_btnBubbleBack_clicked();
+
+  void on_stack_currentChanged(int arg1);
+
+  void on_btnPlay_toggled(bool checked);
+
+  void idleCallback();
+
+  void on_btnSingleStep_clicked();
+
+
+  void on_btnEvolutionBack_clicked();
+
+  void on_btnEvolutionNext_clicked();
+
+  void on_btnRewind_clicked();
+
+  void on_btnEvolutionParameters_clicked();
+
+  void on_btnCancel_clicked();
+
+  void on_actionIncreaseBubbleRadius_triggered();
+
+  void on_actionDecreaseBubbleRadius_triggered();
+
+  void on_btnClusterIterate_clicked();
+
+  void on_btnClusterIterateMany_clicked();
+
+  void on_btnClusterReinitialize_clicked();
+
+  void on_btnClassifyTrain_clicked();
+
+  void on_btnThreshDetail_clicked();
+
+  void on_btnClusterDetail_clicked();
+
+  void on_btnClassifyClearExamples_clicked();
+
+  // Slot called when a quick-label is selected in the classify pane
+  void onClassifyQuickLabelSelection();
+
+  void on_btnEdgeDetail_clicked();
+
+private:
+
+  SpeedImageDialog *m_SpeedDialog;
+  SnakeParameterDialog *m_ParameterDialog;
+  GlobalUIModel *m_ParentModel;
+  SnakeWizardModel *m_Model;
+
+  QTimer *m_EvolutionTimer;
+
+  Ui::SnakeWizardPanel *ui;
+};
+
+#endif // SNAKEWIZARDPANEL_H
diff --git a/GUI/Qt/Components/SnakeWizardPanel.ui b/GUI/Qt/Components/SnakeWizardPanel.ui
new file mode 100644
index 0000000..030a8b0
--- /dev/null
+++ b/GUI/Qt/Components/SnakeWizardPanel.ui
@@ -0,0 +1,2081 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SnakeWizardPanel</class>
+ <widget class="QWidget" name="SnakeWizardPanel">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>177</width>
+    <height>680</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>177</width>
+    <height>16777215</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">* {
+font-size: 12px;
+}
+QGroupBox {
+  background-origin: content;
+  margin-top: 15px;
+  font-weight: bold;
+  font-size: 12px;
+  font-family: helvetica;
+  color: rgb(30,30,160);
+  background-color: rgb(237,237,237);
+  padding: 5px;
+  border-radius: 4px;
+  border: 1px solid rgb(130,130,130);
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+}
+
+</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_3">
+   <property name="spacing">
+    <number>8</number>
+   </property>
+   <property name="leftMargin">
+    <number>5</number>
+   </property>
+   <property name="topMargin">
+    <number>5</number>
+   </property>
+   <property name="rightMargin">
+    <number>5</number>
+   </property>
+   <property name="bottomMargin">
+    <number>5</number>
+   </property>
+   <item>
+    <widget class="QGroupBox" name="boxStepInfo">
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>60</height>
+      </size>
+     </property>
+     <property name="title">
+      <string>Current Stage</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout">
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QStackedWidget" name="stackStepInfo">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="currentIndex">
+         <number>0</number>
+        </property>
+        <widget class="QWidget" name="pgInfoPreproc">
+         <layout class="QVBoxLayout" name="verticalLayout_6">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QLabel" name="label_10">
+            <property name="maximumSize">
+             <size>
+              <width>16777215</width>
+              <height>16777215</height>
+             </size>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">font-size:10px;</string>
+            </property>
+            <property name="text">
+             <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:10px; font-weight:400; font-style:normal;">
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12px;">Step 1/3</span></p>
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12px; font-weight:600;">Preprocessing</span></p></body></html></string>
+            </property>
+            <property name="wordWrap">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+        <widget class="QWidget" name="pgInfoBubbles">
+         <layout class="QVBoxLayout" name="verticalLayout_8">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QLabel" name="label_11">
+            <property name="maximumSize">
+             <size>
+              <width>16777215</width>
+              <height>16777215</height>
+             </size>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">font-size:10px;</string>
+            </property>
+            <property name="text">
+             <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:10px; font-weight:400; font-style:normal;">
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12px;">Step 2/3</span></p>
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12px; font-weight:600;">Initialization</span></p></body></html></string>
+            </property>
+            <property name="wordWrap">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+        <widget class="QWidget" name="page">
+         <layout class="QVBoxLayout" name="verticalLayout_9">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QLabel" name="pgInfoEvolution">
+            <property name="maximumSize">
+             <size>
+              <width>16777215</width>
+              <height>16777215</height>
+             </size>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">font-size:10px;</string>
+            </property>
+            <property name="text">
+             <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:10px; font-weight:400; font-style:normal;">
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12px;">Step 3/3</span></p>
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12px; font-weight:600;">Evolution</span></p></body></html></string>
+            </property>
+            <property name="wordWrap">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="grpPreprocActions">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Actions:</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QStackedWidget" name="stack">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="currentIndex">
+         <number>0</number>
+        </property>
+        <widget class="QWidget" name="pgPreproc">
+         <layout class="QVBoxLayout" name="verticalLayout_7">
+          <property name="spacing">
+           <number>4</number>
+          </property>
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QWidget" name="widget_2" native="true">
+            <layout class="QHBoxLayout" name="horizontalLayout">
+             <property name="spacing">
+              <number>12</number>
+             </property>
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+             <item>
+              <widget class="QLabel" name="label_2">
+               <property name="text">
+                <string>Presegmentation mode</string>
+               </property>
+               <property name="wordWrap">
+                <bool>false</bool>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="QComboBox" name="inPreprocessMode">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="maximumSize">
+             <size>
+              <width>16777215</width>
+              <height>16777215</height>
+             </size>
+            </property>
+            <item>
+             <property name="text">
+              <string>Thresholding</string>
+             </property>
+            </item>
+            <item>
+             <property name="text">
+              <string>Clustering</string>
+             </property>
+            </item>
+            <item>
+             <property name="text">
+              <string>Supervised Classification</string>
+             </property>
+            </item>
+            <item>
+             <property name="text">
+              <string>Edge Attraction</string>
+             </property>
+            </item>
+           </widget>
+          </item>
+          <item>
+           <spacer name="verticalSpacer_3">
+            <property name="orientation">
+             <enum>Qt::Vertical</enum>
+            </property>
+            <property name="sizeType">
+             <enum>QSizePolicy::Fixed</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>20</width>
+              <height>5</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="Line" name="line">
+            <property name="frameShadow">
+             <enum>QFrame::Plain</enum>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget_4" native="true">
+            <layout class="QHBoxLayout" name="horizontalLayout_3">
+             <property name="spacing">
+              <number>12</number>
+             </property>
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="QStackedWidget" name="stackPreprocess">
+            <property name="toolTip">
+             <string>Lower threshold only</string>
+            </property>
+            <property name="currentIndex">
+             <number>2</number>
+            </property>
+            <widget class="QWidget" name="pgThreshold">
+             <layout class="QGridLayout" name="gridLayout_3">
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <property name="verticalSpacing">
+               <number>4</number>
+              </property>
+              <item row="2" column="0" colspan="2">
+               <spacer name="verticalSpacer_9">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>10</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="1" column="0" colspan="2">
+               <widget class="QWidget" name="grpThreshMode" native="true">
+                <property name="minimumSize">
+                 <size>
+                  <width>0</width>
+                  <height>40</height>
+                 </size>
+                </property>
+                <layout class="QHBoxLayout" name="horizontalLayout_5">
+                 <property name="spacing">
+                  <number>4</number>
+                 </property>
+                 <property name="leftMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="topMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="rightMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="bottomMargin">
+                  <number>0</number>
+                 </property>
+                 <item>
+                  <spacer name="horizontalSpacer_3">
+                   <property name="orientation">
+                    <enum>Qt::Horizontal</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>40</width>
+                     <height>20</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                 <item>
+                  <widget class="QToolButton" name="btnThreshUpper">
+                   <property name="maximumSize">
+                    <size>
+                     <width>28</width>
+                     <height>28</height>
+                    </size>
+                   </property>
+                   <property name="toolTip">
+                    <string>Upper and lower thresholds</string>
+                   </property>
+                   <property name="text">
+                    <string>...</string>
+                   </property>
+                   <property name="icon">
+                    <iconset resource="../Resources/SNAPResources.qrc">
+                     <normaloff>:/root/thresh_both.png</normaloff>:/root/thresh_both.png</iconset>
+                   </property>
+                   <property name="iconSize">
+                    <size>
+                     <width>22</width>
+                     <height>22</height>
+                    </size>
+                   </property>
+                   <property name="checkable">
+                    <bool>true</bool>
+                   </property>
+                   <property name="autoExclusive">
+                    <bool>true</bool>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QToolButton" name="btnThreshLower">
+                   <property name="maximumSize">
+                    <size>
+                     <width>28</width>
+                     <height>28</height>
+                    </size>
+                   </property>
+                   <property name="toolTip">
+                    <string><html><head/><body><p>Lower threshold only</p></body></html></string>
+                   </property>
+                   <property name="text">
+                    <string>...</string>
+                   </property>
+                   <property name="icon">
+                    <iconset resource="../Resources/SNAPResources.qrc">
+                     <normaloff>:/root/thresh_lower.png</normaloff>:/root/thresh_lower.png</iconset>
+                   </property>
+                   <property name="iconSize">
+                    <size>
+                     <width>22</width>
+                     <height>22</height>
+                    </size>
+                   </property>
+                   <property name="checkable">
+                    <bool>true</bool>
+                   </property>
+                   <property name="checked">
+                    <bool>true</bool>
+                   </property>
+                   <property name="autoExclusive">
+                    <bool>true</bool>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QToolButton" name="btnThreshTwoSided">
+                   <property name="maximumSize">
+                    <size>
+                     <width>28</width>
+                     <height>28</height>
+                    </size>
+                   </property>
+                   <property name="toolTip">
+                    <string>Upper threshold only</string>
+                   </property>
+                   <property name="text">
+                    <string>...</string>
+                   </property>
+                   <property name="icon">
+                    <iconset resource="../Resources/SNAPResources.qrc">
+                     <normaloff>:/root/thresh_upper.png</normaloff>:/root/thresh_upper.png</iconset>
+                   </property>
+                   <property name="iconSize">
+                    <size>
+                     <width>22</width>
+                     <height>22</height>
+                    </size>
+                   </property>
+                   <property name="checkable">
+                    <bool>true</bool>
+                   </property>
+                   <property name="autoExclusive">
+                    <bool>true</bool>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item row="4" column="0" colspan="2">
+               <widget class="QDoubleSlider" name="inThreshLowerSlider">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item row="8" column="0" colspan="2">
+               <widget class="QDoubleSlider" name="inThreshUpperSlider">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item row="3" column="1">
+               <widget class="QDoubleSpinBox" name="inThreshLowerSpin">
+                <property name="keyboardTracking">
+                 <bool>false</bool>
+                </property>
+               </widget>
+              </item>
+              <item row="6" column="1">
+               <widget class="QDoubleSpinBox" name="inThreshUpperSpin">
+                <property name="keyboardTracking">
+                 <bool>false</bool>
+                </property>
+               </widget>
+              </item>
+              <item row="6" column="0">
+               <widget class="QLabel" name="label_18">
+                <property name="text">
+                 <string><html><head/><body><p>Upper<br/>threshold:</p></body></html></string>
+                </property>
+               </widget>
+              </item>
+              <item row="10" column="0" colspan="2" alignment="Qt::AlignHCenter">
+               <widget class="QPushButton" name="btnThreshDetail">
+                <property name="minimumSize">
+                 <size>
+                  <width>120</width>
+                  <height>0</height>
+                 </size>
+                </property>
+                <property name="maximumSize">
+                 <size>
+                  <width>120</width>
+                  <height>16777215</height>
+                 </size>
+                </property>
+                <property name="text">
+                 <string>More ...</string>
+                </property>
+               </widget>
+              </item>
+              <item row="3" column="0">
+               <widget class="QLabel" name="label_15">
+                <property name="text">
+                 <string><html><head/><body><p>Lower<br/>threshold:</p></body></html></string>
+                </property>
+               </widget>
+              </item>
+              <item row="5" column="0" colspan="2">
+               <spacer name="verticalSpacer_8">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>10</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="9" column="0" colspan="2">
+               <spacer name="verticalSpacer_7">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>40</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="0" column="0" colspan="2">
+               <widget class="QLabel" name="label_19">
+                <property name="text">
+                 <string>Threshold mode:</string>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+            <widget class="QWidget" name="pgCluster">
+             <layout class="QGridLayout" name="gridLayout_4">
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="topMargin">
+               <number>12</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <property name="bottomMargin">
+               <number>12</number>
+              </property>
+              <property name="verticalSpacing">
+               <number>4</number>
+              </property>
+              <item row="2" column="0">
+               <widget class="QLabel" name="label_5">
+                <property name="text">
+                 <string><html><head/><body><p align="right">Foreground<br/>cluster:</p></body></html></string>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="1">
+               <widget class="QSpinBox" name="inClusterActive"/>
+              </item>
+              <item row="0" column="1">
+               <widget class="QSpinBox" name="inClusterCount"/>
+              </item>
+              <item row="6" column="0">
+               <spacer name="verticalSpacer_2">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>40</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="8" column="0" colspan="2" alignment="Qt::AlignHCenter">
+               <widget class="QPushButton" name="btnClusterDetail">
+                <property name="minimumSize">
+                 <size>
+                  <width>120</width>
+                  <height>0</height>
+                 </size>
+                </property>
+                <property name="maximumSize">
+                 <size>
+                  <width>120</width>
+                  <height>16777215</height>
+                 </size>
+                </property>
+                <property name="text">
+                 <string>More ...</string>
+                </property>
+               </widget>
+              </item>
+              <item row="0" column="0">
+               <widget class="QLabel" name="label_3">
+                <property name="text">
+                 <string><html><head/><body><p align="right">Number of<br/>clusters:</p></body></html></string>
+                </property>
+               </widget>
+              </item>
+              <item row="5" column="0" colspan="2">
+               <widget class="QWidget" name="widget_3" native="true">
+                <layout class="QHBoxLayout" name="horizontalLayout_4">
+                 <property name="spacing">
+                  <number>4</number>
+                 </property>
+                 <property name="leftMargin">
+                  <number>4</number>
+                 </property>
+                 <property name="topMargin">
+                  <number>4</number>
+                 </property>
+                 <property name="rightMargin">
+                  <number>4</number>
+                 </property>
+                 <property name="bottomMargin">
+                  <number>4</number>
+                 </property>
+                 <item>
+                  <spacer name="horizontalSpacer_4">
+                   <property name="orientation">
+                    <enum>Qt::Horizontal</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>40</width>
+                     <height>20</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                 <item>
+                  <widget class="QToolButton" name="btnClusterReinitialize">
+                   <property name="maximumSize">
+                    <size>
+                     <width>28</width>
+                     <height>28</height>
+                    </size>
+                   </property>
+                   <property name="toolTip">
+                    <string><html><head/><body><p>Reinitialize the clusters</p></body></html></string>
+                   </property>
+                   <property name="text">
+                    <string>...</string>
+                   </property>
+                   <property name="icon">
+                    <iconset resource="../Resources/SNAPResources.qrc">
+                     <normaloff>:/root/view-refresh-4.png</normaloff>:/root/view-refresh-4.png</iconset>
+                   </property>
+                   <property name="iconSize">
+                    <size>
+                     <width>22</width>
+                     <height>22</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QToolButton" name="btnClusterIterate">
+                   <property name="maximumSize">
+                    <size>
+                     <width>28</width>
+                     <height>28</height>
+                    </size>
+                   </property>
+                   <property name="toolTip">
+                    <string><html><head/><body><p>Perform one iteration of cluster computation</p></body></html></string>
+                   </property>
+                   <property name="text">
+                    <string>...</string>
+                   </property>
+                   <property name="icon">
+                    <iconset resource="../Resources/SNAPResources.qrc">
+                     <normaloff>:/root/media-playback-start-1x-4.png</normaloff>:/root/media-playback-start-1x-4.png</iconset>
+                   </property>
+                   <property name="iconSize">
+                    <size>
+                     <width>22</width>
+                     <height>22</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QToolButton" name="btnClusterIterateMany">
+                   <property name="maximumSize">
+                    <size>
+                     <width>28</width>
+                     <height>28</height>
+                    </size>
+                   </property>
+                   <property name="toolTip">
+                    <string><html><head/><body><p>Perform ten iterations of cluster computation</p></body></html></string>
+                   </property>
+                   <property name="text">
+                    <string>...</string>
+                   </property>
+                   <property name="icon">
+                    <iconset resource="../Resources/SNAPResources.qrc">
+                     <normaloff>:/root/media-playback-start-10x-4.png</normaloff>:/root/media-playback-start-10x-4.png</iconset>
+                   </property>
+                   <property name="iconSize">
+                    <size>
+                     <width>22</width>
+                     <height>22</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item row="4" column="0" colspan="2">
+               <widget class="QLabel" name="label_20">
+                <property name="text">
+                 <string>Clustering iteration:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="3" column="0">
+               <spacer name="verticalSpacer_10">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Fixed</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>10</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="1" column="0">
+               <spacer name="verticalSpacer_11">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Fixed</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>10</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </widget>
+            <widget class="QWidget" name="pgClassify">
+             <layout class="QGridLayout" name="gridLayout_5">
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <item row="13" column="0">
+               <widget class="QWidget" name="widget_8" native="true">
+                <layout class="QHBoxLayout" name="horizontalLayout_7">
+                 <property name="leftMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="topMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="rightMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="bottomMargin">
+                  <number>0</number>
+                 </property>
+                 <item>
+                  <widget class="QLabel" name="label_24">
+                   <property name="text">
+                    <string>Random forest size:</string>
+                   </property>
+                   <property name="wordWrap">
+                    <bool>true</bool>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QSpinBox" name="inClassifyTrees">
+                   <property name="toolTip">
+                    <string><html><head/><body><p>This parameter controls the number of trees in the random forest algorithm. Using a larger number of trees will make classification slower, but can improve accuracy.</p></body></html></string>
+                   </property>
+                   <property name="maximum">
+                    <number>1000</number>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item row="2" column="0">
+               <widget class="ColorLabelQuickListWidget" name="boxLabelQuickList" native="true">
+                <property name="minimumSize">
+                 <size>
+                  <width>0</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </widget>
+              </item>
+              <item row="10" column="0">
+               <widget class="QLabel" name="label_9">
+                <property name="text">
+                 <string>Foreground class:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="0">
+               <widget class="QLabel" name="label_12">
+                <property name="text">
+                 <string><html><head/><body><p>Use the paintbrush or polygon tools to mark examples of two or more tissue classes.</p></body></html></string>
+                </property>
+                <property name="wordWrap">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item row="5" column="0" alignment="Qt::AlignHCenter">
+               <widget class="QPushButton" name="btnClassifyClearExamples">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="minimumSize">
+                 <size>
+                  <width>120</width>
+                  <height>0</height>
+                 </size>
+                </property>
+                <property name="maximumSize">
+                 <size>
+                  <width>120</width>
+                  <height>16777215</height>
+                 </size>
+                </property>
+                <property name="toolTip">
+                 <string><html><head/><body><p>Clear all the examples of the tissue classes painted in the image. This is useful if you want to retrain your classifier using new examples. It is also a good idea to clear examples before pressing 'Next'.</p></body></html></string>
+                </property>
+                <property name="text">
+                 <string>Clear Examples</string>
+                </property>
+               </widget>
+              </item>
+              <item row="9" column="0">
+               <spacer name="verticalSpacer_6">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Fixed</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>10</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="12" column="0">
+               <spacer name="verticalSpacer_16">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Expanding</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>10</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="11" column="0">
+               <widget class="QComboBox" name="inClassifyForeground">
+                <property name="toolTip">
+                 <string><html><head/><body><p>Select the tissue class that you would like to perform segmentation on. The rest of the tissue classes you defined will be considered background.</p></body></html></string>
+                </property>
+               </widget>
+              </item>
+              <item row="4" column="0" alignment="Qt::AlignHCenter">
+               <widget class="QPushButton" name="btnClassifyTrain">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="minimumSize">
+                 <size>
+                  <width>120</width>
+                  <height>0</height>
+                 </size>
+                </property>
+                <property name="maximumSize">
+                 <size>
+                  <width>120</width>
+                  <height>16777215</height>
+                 </size>
+                </property>
+                <property name="toolTip">
+                 <string><html><head/><body><p>This button trains the random forest classifier. The classifier assigns a probability value to each voxel of belonging to the 'foreground' class vs. belonging to all other classes. You must train a classifier before proceeding to the text step.</p></body></html></string>
+                </property>
+                <property name="text">
+                 <string>Train Classifier</string>
+                </property>
+               </widget>
+              </item>
+              <item row="3" column="0">
+               <spacer name="verticalSpacer_14">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Fixed</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>10</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </widget>
+            <widget class="QWidget" name="pgUserSpeed">
+             <layout class="QGridLayout" name="gridLayout_7">
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <property name="horizontalSpacing">
+               <number>0</number>
+              </property>
+              <property name="verticalSpacing">
+               <number>4</number>
+              </property>
+              <item row="2" column="0" colspan="2">
+               <widget class="QPushButton" name="btnLoadSpeed">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="text">
+                 <string>Import Speed ...</string>
+                </property>
+               </widget>
+              </item>
+              <item row="6" column="1">
+               <widget class="QRadioButton" name="radioButton_2">
+                <property name="text">
+                 <string>Region
+competition</string>
+                </property>
+               </widget>
+              </item>
+              <item row="4" column="0" colspan="2">
+               <widget class="QLabel" name="label_22">
+                <property name="text">
+                 <string>Which version of active contour method is the speed image intended for?</string>
+                </property>
+                <property name="wordWrap">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item row="5" column="0">
+               <spacer name="horizontalSpacer_5">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Fixed</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="0" column="0" colspan="2">
+               <widget class="QLabel" name="label_21">
+                <property name="text">
+                 <string>Use this mode to perform segmentation using a speed image  computed outside of ITK-SNAP.</string>
+                </property>
+                <property name="wordWrap">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item row="5" column="1">
+               <widget class="QRadioButton" name="radioButton">
+                <property name="text">
+                 <string>Edge attraction</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="0" colspan="2">
+               <spacer name="verticalSpacer_13">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>40</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="3" column="0" colspan="2">
+               <spacer name="verticalSpacer_12">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>40</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </widget>
+            <widget class="QWidget" name="pgEdge">
+             <layout class="QGridLayout" name="gridLayout_6">
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <property name="verticalSpacing">
+               <number>4</number>
+              </property>
+              <item row="1" column="0" rowspan="2" colspan="3">
+               <widget class="QDoubleSlider" name="inEdgeScaleSlider">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item row="0" column="2">
+               <widget class="QDoubleSpinBox" name="inEdgeScale"/>
+              </item>
+              <item row="0" column="0" colspan="2">
+               <widget class="QLabel" name="label_23">
+                <property name="text">
+                 <string><html><head/><body><p>Smoothing<br/>factor:</p></body></html></string>
+                </property>
+               </widget>
+              </item>
+              <item row="4" column="0" colspan="3" alignment="Qt::AlignHCenter|Qt::AlignBottom">
+               <widget class="QPushButton" name="btnEdgeDetail">
+                <property name="minimumSize">
+                 <size>
+                  <width>120</width>
+                  <height>0</height>
+                 </size>
+                </property>
+                <property name="maximumSize">
+                 <size>
+                  <width>120</width>
+                  <height>16777215</height>
+                 </size>
+                </property>
+                <property name="text">
+                 <string>More ...</string>
+                </property>
+               </widget>
+              </item>
+              <item row="3" column="0">
+               <spacer name="verticalSpacer_15">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>196</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </widget>
+           </widget>
+          </item>
+          <item>
+           <widget class="Line" name="line_6">
+            <property name="frameShadow">
+             <enum>QFrame::Plain</enum>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget_5" native="true">
+            <layout class="QGridLayout" name="gridLayout_2">
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+             <property name="verticalSpacing">
+              <number>6</number>
+             </property>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget_9" native="true">
+            <layout class="QHBoxLayout" name="horizontalLayout_9">
+             <property name="spacing">
+              <number>4</number>
+             </property>
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+             <item>
+              <widget class="QPushButton" name="pushButton_7">
+               <property name="enabled">
+                <bool>false</bool>
+               </property>
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="maximumSize">
+                <size>
+                 <width>64</width>
+                 <height>16777215</height>
+                </size>
+               </property>
+               <property name="text">
+                <string>Back</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QPushButton" name="btnNextPreproc">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="maximumSize">
+                <size>
+                 <width>64</width>
+                 <height>16777215</height>
+                </size>
+               </property>
+               <property name="text">
+                <string>Next</string>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+        <widget class="QWidget" name="pgBubbles">
+         <layout class="QVBoxLayout" name="verticalLayout_4">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QLabel" name="label_6">
+            <property name="text">
+             <string>A. Place bubbles in the image to intialize the contour</string>
+            </property>
+            <property name="wordWrap">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="btnAddBubble">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="text">
+             <string>Add Bubble at Cursor</string>
+            </property>
+            <property name="shortcut">
+             <string>Return</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget_6" native="true">
+            <layout class="QVBoxLayout" name="verticalLayout_10">
+             <property name="spacing">
+              <number>0</number>
+             </property>
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_7">
+            <property name="text">
+             <string>Bubble radius:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QDoubleSliderWithEditor" name="inBubbleRadius">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_8">
+            <property name="text">
+             <string>Active bubbles:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QTableView" name="tableBubbleList">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="maximumSize">
+             <size>
+              <width>155</width>
+              <height>120</height>
+             </size>
+            </property>
+            <property name="font">
+             <font>
+              <pointsize>-1</pointsize>
+             </font>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">font-size: 10px;
+</string>
+            </property>
+            <property name="selectionMode">
+             <enum>QAbstractItemView::SingleSelection</enum>
+            </property>
+            <property name="selectionBehavior">
+             <enum>QAbstractItemView::SelectRows</enum>
+            </property>
+            <property name="showGrid">
+             <bool>true</bool>
+            </property>
+            <attribute name="horizontalHeaderDefaultSectionSize">
+             <number>32</number>
+            </attribute>
+            <attribute name="horizontalHeaderMinimumSectionSize">
+             <number>32</number>
+            </attribute>
+            <attribute name="horizontalHeaderShowSortIndicator" stdset="0">
+             <bool>false</bool>
+            </attribute>
+            <attribute name="horizontalHeaderStretchLastSection">
+             <bool>true</bool>
+            </attribute>
+            <attribute name="verticalHeaderVisible">
+             <bool>false</bool>
+            </attribute>
+            <attribute name="verticalHeaderCascadingSectionResizes">
+             <bool>true</bool>
+            </attribute>
+            <attribute name="verticalHeaderDefaultSectionSize">
+             <number>18</number>
+            </attribute>
+            <attribute name="verticalHeaderMinimumSectionSize">
+             <number>18</number>
+            </attribute>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="btnRemoveBubble">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="text">
+             <string>Delete Active Bubble</string>
+            </property>
+            <property name="shortcut">
+             <string>Backspace</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="Line" name="line_3">
+            <property name="frameShadow">
+             <enum>QFrame::Plain</enum>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_16">
+            <property name="text">
+             <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:12px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:13px;">C. Press 'Next&quot; to proceed to the next step.</span></p></body></html></string>
+            </property>
+            <property name="wordWrap">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget_13" native="true">
+            <layout class="QHBoxLayout" name="horizontalLayout_15">
+             <property name="spacing">
+              <number>4</number>
+             </property>
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+             <item>
+              <widget class="QPushButton" name="btnBubbleBack">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="maximumSize">
+                <size>
+                 <width>64</width>
+                 <height>16777215</height>
+                </size>
+               </property>
+               <property name="text">
+                <string>Back</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QPushButton" name="btnBubbleNext">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="maximumSize">
+                <size>
+                 <width>64</width>
+                 <height>16777215</height>
+                </size>
+               </property>
+               <property name="text">
+                <string>Next</string>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <spacer name="verticalSpacer_5">
+            <property name="orientation">
+             <enum>Qt::Vertical</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>20</width>
+              <height>0</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget_11" native="true">
+            <layout class="QHBoxLayout" name="horizontalLayout_8">
+             <property name="spacing">
+              <number>12</number>
+             </property>
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+            </layout>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+        <widget class="QWidget" name="pgEvolution">
+         <layout class="QVBoxLayout" name="verticalLayout_5">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QWidget" name="widget_14" native="true">
+            <layout class="QHBoxLayout" name="horizontalLayout_12">
+             <property name="spacing">
+              <number>12</number>
+             </property>
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+             <item>
+              <widget class="QLabel" name="label_13">
+               <property name="maximumSize">
+                <size>
+                 <width>16777215</width>
+                 <height>16777215</height>
+                </size>
+               </property>
+               <property name="text">
+                <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:12px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:13px;">A. Configure the parameters of the contour evolution differential equation</span></p></body></html></string>
+               </property>
+               <property name="wordWrap">
+                <bool>true</bool>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget_15" native="true">
+            <layout class="QHBoxLayout" name="horizontalLayout_2">
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+             <item>
+              <widget class="QPushButton" name="btnEvolutionParameters">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="text">
+                <string>Set Parameters ...</string>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="Line" name="line_5">
+            <property name="frameShadow">
+             <enum>QFrame::Plain</enum>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget_16" native="true">
+            <layout class="QHBoxLayout" name="horizontalLayout_13">
+             <property name="spacing">
+              <number>12</number>
+             </property>
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+             <item>
+              <widget class="QLabel" name="label_14">
+               <property name="text">
+                <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:12px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:13px;">B. Execute and control the evolution</span></p></body></html></string>
+               </property>
+               <property name="wordWrap">
+                <bool>true</bool>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget" native="true">
+            <layout class="QHBoxLayout" name="horizontalLayout_6">
+             <property name="spacing">
+              <number>4</number>
+             </property>
+             <property name="leftMargin">
+              <number>4</number>
+             </property>
+             <property name="topMargin">
+              <number>4</number>
+             </property>
+             <property name="rightMargin">
+              <number>4</number>
+             </property>
+             <property name="bottomMargin">
+              <number>4</number>
+             </property>
+             <item>
+              <spacer name="horizontalSpacer">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>5</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+             <item>
+              <widget class="QToolButton" name="btnRewind">
+               <property name="text">
+                <string>...</string>
+               </property>
+               <property name="icon">
+                <iconset>
+                 <normalon>:/root/media-seek-backward-4.png</normalon>
+                </iconset>
+               </property>
+               <property name="iconSize">
+                <size>
+                 <width>22</width>
+                 <height>22</height>
+                </size>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QToolButton" name="btnPlay">
+               <property name="text">
+                <string>...</string>
+               </property>
+               <property name="icon">
+                <iconset resource="../Resources/SNAPResources.qrc">
+                 <normaloff>:/root/media-playback-start-4.png</normaloff>
+                 <normalon>:/root/media-playback-pause-4.png</normalon>
+                 <activeoff>:/root/media-playback-start-4.png</activeoff>
+                 <activeon>:/root/media-playback-pause-4.png</activeon>
+                 <selectedon>:/root/media-playback-pause-4.png</selectedon>:/root/media-playback-start-4.png</iconset>
+               </property>
+               <property name="iconSize">
+                <size>
+                 <width>22</width>
+                 <height>22</height>
+                </size>
+               </property>
+               <property name="checkable">
+                <bool>true</bool>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QToolButton" name="btnSingleStep">
+               <property name="text">
+                <string>...</string>
+               </property>
+               <property name="icon">
+                <iconset>
+                 <normalon>:/root/media-playback-singlestep.png</normalon>
+                </iconset>
+               </property>
+               <property name="iconSize">
+                <size>
+                 <width>22</width>
+                 <height>22</height>
+                </size>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <spacer name="horizontalSpacer_2">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>5</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget_7" native="true">
+            <property name="minimumSize">
+             <size>
+              <width>0</width>
+              <height>0</height>
+             </size>
+            </property>
+            <layout class="QGridLayout" name="gridLayout" columnstretch="1,1">
+             <property name="sizeConstraint">
+              <enum>QLayout::SetDefaultConstraint</enum>
+             </property>
+             <property name="leftMargin">
+              <number>4</number>
+             </property>
+             <property name="topMargin">
+              <number>4</number>
+             </property>
+             <property name="rightMargin">
+              <number>4</number>
+             </property>
+             <property name="bottomMargin">
+              <number>4</number>
+             </property>
+             <property name="horizontalSpacing">
+              <number>12</number>
+             </property>
+             <property name="verticalSpacing">
+              <number>2</number>
+             </property>
+             <item row="0" column="0">
+              <widget class="QLabel" name="label">
+               <property name="text">
+                <string>Step size:</string>
+               </property>
+              </widget>
+             </item>
+             <item row="0" column="1">
+              <widget class="QLabel" name="label_4">
+               <property name="text">
+                <string>Iteration:</string>
+               </property>
+              </widget>
+             </item>
+             <item row="1" column="1">
+              <widget class="QSpinBox" name="outIteration">
+               <property name="readOnly">
+                <bool>true</bool>
+               </property>
+               <property name="buttonSymbols">
+                <enum>QAbstractSpinBox::NoButtons</enum>
+               </property>
+               <property name="maximum">
+                <number>9999</number>
+               </property>
+              </widget>
+             </item>
+             <item row="1" column="0">
+              <widget class="QSpinBox" name="inStepSize"/>
+             </item>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="Line" name="line_4">
+            <property name="frameShadow">
+             <enum>QFrame::Plain</enum>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_17">
+            <property name="text">
+             <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:12px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:13px;">C. Press 'Finish&quot; to accept the result.</span></p></body></html></string>
+            </property>
+            <property name="wordWrap">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget_18" native="true">
+            <layout class="QHBoxLayout" name="horizontalLayout_16">
+             <property name="spacing">
+              <number>4</number>
+             </property>
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+             <item>
+              <widget class="QPushButton" name="btnEvolutionBack">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="maximumSize">
+                <size>
+                 <width>64</width>
+                 <height>16777215</height>
+                </size>
+               </property>
+               <property name="text">
+                <string>Back</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QPushButton" name="btnEvolutionNext">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="maximumSize">
+                <size>
+                 <width>64</width>
+                 <height>16777215</height>
+                </size>
+               </property>
+               <property name="text">
+                <string>Finish</string>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <spacer name="verticalSpacer">
+            <property name="orientation">
+             <enum>Qt::Vertical</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>20</width>
+              <height>0</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+         </layout>
+        </widget>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_4">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QPushButton" name="btnCancel">
+     <property name="text">
+      <string>Cancel Segmentation</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+  <action name="actionIncreaseBubbleRadius">
+   <property name="text">
+    <string>Increase bubble radius</string>
+   </property>
+   <property name="shortcut">
+    <string>+</string>
+   </property>
+  </action>
+  <action name="actionDecreaseBubbleRadius">
+   <property name="text">
+    <string>Decrease bubble radius</string>
+   </property>
+   <property name="toolTip">
+    <string>Decrease bubble radius</string>
+   </property>
+   <property name="shortcut">
+    <string>-</string>
+   </property>
+  </action>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QDoubleSliderWithEditor</class>
+   <extends>QSlider</extends>
+   <header location="global">QDoubleSliderWithEditor.h</header>
+  </customwidget>
+  <customwidget>
+   <class>ColorLabelQuickListWidget</class>
+   <extends>QWidget</extends>
+   <header>ColorLabelQuickListWidget.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>QDoubleSlider</class>
+   <extends>QSlider</extends>
+   <header location="global">QDoubleSlider.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/SynchronizationInspector.cxx b/GUI/Qt/Components/SynchronizationInspector.cxx
new file mode 100644
index 0000000..7d52e82
--- /dev/null
+++ b/GUI/Qt/Components/SynchronizationInspector.cxx
@@ -0,0 +1,41 @@
+#include "SynchronizationInspector.h"
+#include "ui_SynchronizationInspector.h"
+#include "SynchronizationModel.h"
+#include "QtSpinBoxCoupling.h"
+#include "QtCheckBoxCoupling.h"
+
+SynchronizationInspector::SynchronizationInspector(QWidget *parent) :
+  QWidget(parent),
+  ui(new Ui::SynchronizationInspector)
+{
+  ui->setupUi(this);
+
+  // TODO: add the code to support multiple channels
+  ui->panelChannel->setVisible(false);
+}
+
+SynchronizationInspector::~SynchronizationInspector()
+{
+  delete ui;
+}
+
+void SynchronizationInspector::SetModel(SynchronizationModel *model)
+{
+  m_Model = model;
+
+  // Do couplings
+  makeCoupling(ui->chkSync, model->GetSyncEnabledModel());
+  makeCoupling(ui->chkCursor, model->GetSyncCursorModel());
+  makeCoupling(ui->chkZoom, model->GetSyncZoomModel());
+  makeCoupling(ui->chkPan, model->GetSyncPanModel());
+  makeCoupling(ui->chkCamera, model->GetSyncCameraModel());
+
+  // The checkboxes should be deactivated when the sync model is off
+  makeBooleanNamedPropertyCoupling(ui->panelProperties, "enabled",
+                                   model->GetSyncEnabledModel());
+
+  // The checkboxes should be deactivated when the sync model is off
+  makeBooleanNamedPropertyCoupling(ui->inChannel, "enabled",
+                                   model->GetSyncEnabledModel());
+
+}
diff --git a/GUI/Qt/Components/SynchronizationInspector.h b/GUI/Qt/Components/SynchronizationInspector.h
new file mode 100644
index 0000000..0e8f7c3
--- /dev/null
+++ b/GUI/Qt/Components/SynchronizationInspector.h
@@ -0,0 +1,28 @@
+#ifndef SYNCHRONIZATIONINSPECTOR_H
+#define SYNCHRONIZATIONINSPECTOR_H
+
+#include <QWidget>
+
+namespace Ui {
+class SynchronizationInspector;
+}
+
+class SynchronizationModel;
+
+class SynchronizationInspector : public QWidget
+{
+  Q_OBJECT
+  
+public:
+  explicit SynchronizationInspector(QWidget *parent = 0);
+  ~SynchronizationInspector();
+
+  void SetModel(SynchronizationModel *model);
+  
+private:
+  Ui::SynchronizationInspector *ui;
+
+  SynchronizationModel *m_Model;
+};
+
+#endif // SYNCHRONIZATIONINSPECTOR_H
diff --git a/GUI/Qt/Components/SynchronizationInspector.ui b/GUI/Qt/Components/SynchronizationInspector.ui
new file mode 100644
index 0000000..69d36ed
--- /dev/null
+++ b/GUI/Qt/Components/SynchronizationInspector.ui
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SynchronizationInspector</class>
+ <widget class="QWidget" name="SynchronizationInspector">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>162</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">*  {
+font-size: 12px;
+}
+</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QCheckBox" name="chkSync">
+     <property name="styleSheet">
+      <string notr="true">font-weight:bold;</string>
+     </property>
+     <property name="text">
+      <string>Synchronization</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="spacing">
+      <number>0</number>
+     </property>
+     <property name="leftMargin">
+      <number>20</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="font">
+        <font>
+         <pointsize>-1</pointsize>
+        </font>
+       </property>
+       <property name="styleSheet">
+        <string notr="true">font-size:10px;</string>
+       </property>
+       <property name="text">
+        <string>Share state with other 
+ITK-SNAP windows</string>
+       </property>
+       <property name="scaledContents">
+        <bool>false</bool>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+       </property>
+       <property name="wordWrap">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line_2">
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="midLineWidth">
+      <number>1</number>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_3">
+     <property name="text">
+      <string>Properties to sync:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="panelProperties" native="true">
+     <property name="enabled">
+      <bool>true</bool>
+     </property>
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="leftMargin">
+       <number>20</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QCheckBox" name="chkCursor">
+        <property name="text">
+         <string>Cursor position</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="chkZoom">
+        <property name="text">
+         <string>Zoom level</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="chkPan">
+        <property name="text">
+         <string>Pan</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="chkCamera">
+        <property name="text">
+         <string>3D viewpoint</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line_3">
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="midLineWidth">
+      <number>1</number>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="panelChannel" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="spacing">
+       <number>6</number>
+      </property>
+      <property name="leftMargin">
+       <number>20</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Channel:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QSpinBox" name="inChannel"/>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/ViewPanel3D.cxx b/GUI/Qt/Components/ViewPanel3D.cxx
new file mode 100644
index 0000000..349ec15
--- /dev/null
+++ b/GUI/Qt/Components/ViewPanel3D.cxx
@@ -0,0 +1,288 @@
+#include "ViewPanel3D.h"
+#include "ui_ViewPanel3D.h"
+#include "GlobalUIModel.h"
+#include "Generic3DModel.h"
+#include "itkCommand.h"
+#include "IRISException.h"
+#include <QMessageBox>
+#include "MainImageWindow.h"
+#include "SNAPQtCommon.h"
+#include "QtWidgetActivator.h"
+#include "DisplayLayoutModel.h"
+#include <QtCore>
+#include <qtconcurrentrun.h>
+#include "itkProcessObject.h"
+#include <QMenu>
+
+
+
+
+ViewPanel3D::ViewPanel3D(QWidget *parent) :
+  SNAPComponent(parent),
+  ui(new Ui::ViewPanel3D)
+{
+  ui->setupUi(this);
+
+  // Set up timer for continuous update rendering
+  m_RenderTimer = new QTimer();
+  m_RenderTimer->setInterval(100);
+  connect(m_RenderTimer, SIGNAL(timeout()), SLOT(onTimer()));
+
+  // Create a progress command
+  m_RenderProgressCommand = CommandType::New();
+  m_RenderProgressCommand->SetCallbackFunction(this, &ViewPanel3D::ProgressCallback);
+
+  // Connect the progress event
+  ui->progressBar->setRange(0, 1000);
+  QObject::connect(this, SIGNAL(renderProgress(int)), ui->progressBar, SLOT(setValue(int)),
+                   Qt::DirectConnection);
+
+  // Set up the context menu
+  m_DropMenu = new QMenu(this);
+  m_DropMenu->setStyleSheet("font-size:11px;");
+  m_DropMenu->addAction(ui->actionReset_Viewpoint);
+  m_DropMenu->addAction(ui->actionSave_Viewpoint);
+  m_DropMenu->addAction(ui->actionRestore_Viewpoint);
+  m_DropMenu->addSeparator();
+  m_DropMenu->addAction(ui->actionContinuous_Update);
+  m_DropMenu->addSeparator();
+  m_DropMenu->addAction(ui->actionClear_Rendering);
+
+  // Make the actions globally accessible
+  this->addActions(m_DropMenu->actions());
+}
+
+ViewPanel3D::~ViewPanel3D()
+{
+  delete ui;
+}
+
+GenericView3D *ViewPanel3D::Get3DView()
+{
+  return ui->view3d;
+}
+
+void ViewPanel3D::onModelUpdate(const EventBucket &bucket)
+{
+  GlobalState *gs = m_Model->GetParentUI()->GetGlobalState();
+  if(bucket.HasEvent(DisplayLayoutModel::ViewPanelLayoutChangeEvent()))
+    {
+    UpdateExpandViewButton();
+    }
+
+  if(bucket.HasEvent(ValueChangedEvent(), gs->GetToolbarMode3DModel()))
+    {
+    UpdateActionButtons();
+    }
+}
+
+void ViewPanel3D::on_btnUpdateMesh_clicked()
+{
+  try
+    {
+    // Tell the model to update itself
+    m_Model->UpdateSegmentationMesh(m_Model->GetParentUI()->GetProgressCommand());
+    // m_Model->UpdateSegmentationMesh(m_RenderProgressCommand);
+    }
+  catch(IRISException & IRISexc)
+    {
+    QMessageBox::warning(this, "Problem generating mesh", IRISexc.what());
+    }
+
+  // TODO: Delete this later - should be automatic!
+  ui->view3d->repaint();
+}
+
+void ViewPanel3D::Initialize(GlobalUIModel *globalUI)
+{
+  // Save the model
+  m_GlobalUI = globalUI;
+  m_Model = globalUI->GetModel3D();
+  ui->view3d->SetModel(m_Model);
+
+  // Set activations
+  activateOnFlag(ui->btnAccept, m_Model, Generic3DModel::UIF_MESH_ACTION_PENDING);
+  activateOnFlag(ui->btnCancel, m_Model, Generic3DModel::UIF_MESH_ACTION_PENDING);
+  activateOnFlag(ui->btnFlip, m_Model, Generic3DModel::UIF_FLIP_ENABLED);
+  activateOnFlag(ui->btnUpdateMesh, m_Model, Generic3DModel::UIF_MESH_DIRTY);
+  activateOnFlag(ui->actionRestore_Viewpoint, m_Model, Generic3DModel::UIF_CAMERA_STATE_SAVED);
+
+  // Listen to layout events
+  connectITK(m_Model->GetParentUI()->GetDisplayLayoutModel(),
+             DisplayLayoutModel::ViewPanelLayoutChangeEvent());
+
+  // Listen to changes in active tool to adjust button visibility
+  connectITK(m_Model->GetParentUI()->GetGlobalState()->GetToolbarMode3DModel(),
+             ValueChangedEvent());
+
+  // Set up the buttons
+  this->UpdateActionButtons();
+
+  // Start the timer
+  m_RenderTimer->start();
+}
+
+void ViewPanel3D::UpdateExpandViewButton()
+{
+  // Get the layout a pplied when the button is pressed
+  DisplayLayoutModel *dlm = m_GlobalUI->GetDisplayLayoutModel();
+  DisplayLayoutModel::ViewPanelLayout layout =
+      dlm->GetViewPanelExpandButtonActionModel(3)->GetValue();
+
+  // Set the tooltip
+  if(layout == DisplayLayoutModel::VIEW_ALL)
+    {
+    ui->btnExpand->setIcon(QIcon(":/root/dl_fourviews.png"));
+    ui->btnExpand->setToolTip("Restore the four-panel display configuration");
+    }
+  else
+    {
+    ui->btnExpand->setIcon(QIcon(":/root/dl_3d.png"));
+    ui->btnExpand->setToolTip("Expand the 3D view to occupy the entire window");
+    }
+}
+
+// This method is run in a concurrent thread
+void ViewPanel3D::UpdateMeshesInBackground()
+{
+  // Make sure the model actually requires updating
+  if(m_Model && m_Model->CheckState(Generic3DModel::UIF_MESH_DIRTY))
+    {
+    m_Model->UpdateSegmentationMesh(m_RenderProgressCommand);
+    }
+}
+
+void ViewPanel3D::ProgressCallback(itk::Object *source, const itk::EventObject &)
+{
+  itk::ProcessObject *po = static_cast<itk::ProcessObject *>(source);
+
+  m_RenderProgressMutex.lock();
+  m_RenderProgressValue = po->GetProgress();
+  m_RenderProgressMutex.unlock();
+}
+
+void ViewPanel3D::on_btnScreenshot_clicked()
+{
+  MainImageWindow *window = findParentWidget<MainImageWindow>(this);
+  window->ExportScreenshot(3);
+}
+
+void ViewPanel3D::on_btnAccept_clicked()
+{
+  if(!m_Model->AcceptAction())
+    {
+    QMessageBox::information(this, "No voxels were updated",
+                             "The 3D operation did not update any voxels in "
+                             "the segmentation. Check that the foreground and "
+                             "background labels are selected correctly.");
+    }
+}
+
+void ViewPanel3D::on_btnCancel_clicked()
+{
+  m_Model->CancelAction();
+}
+
+void ViewPanel3D::on_btnExpand_clicked()
+{
+  // Get the layout applied when the button is pressed
+  DisplayLayoutModel *dlm = m_GlobalUI->GetDisplayLayoutModel();
+  DisplayLayoutModel::ViewPanelLayout layout =
+      dlm->GetViewPanelExpandButtonActionModel(3)->GetValue();
+
+  // Apply this layout
+  dlm->GetViewPanelLayoutModel()->SetValue(layout);
+}
+
+void ViewPanel3D::onTimer()
+{
+  if(!m_RenderFuture.isRunning())
+    {
+    // Does work need to be done?
+    if(m_Model && ui->actionContinuous_Update->isChecked()
+       && m_Model->CheckState(Generic3DModel::UIF_MESH_DIRTY))
+      {
+      // Launch the worker thread
+      m_RenderProgressValue = 0;
+      m_RenderElapsedTicks = 0;
+      m_RenderFuture = QtConcurrent::run(this, &ViewPanel3D::UpdateMeshesInBackground);
+      }
+    else
+      {
+      ui->progressBar->setVisible(false);
+      }
+    }
+  else
+    {
+    // We only want to show progress after some minimum timeout (1 sec)
+    if((++m_RenderElapsedTicks) > 10)
+      {
+      ui->progressBar->setVisible(true);
+
+      m_RenderProgressMutex.lock();
+      emit renderProgress((int)(1000 * m_RenderProgressValue));
+      m_RenderProgressMutex.unlock();
+      }
+    }
+}
+
+void ViewPanel3D::on_actionReset_Viewpoint_triggered()
+{
+  m_Model->ResetView();
+}
+
+void ViewPanel3D::on_actionSave_Viewpoint_triggered()
+{
+  m_Model->SaveCameraState();
+}
+
+void ViewPanel3D::on_actionRestore_Viewpoint_triggered()
+{
+  m_Model->RestoreCameraState();
+}
+
+void ViewPanel3D::on_actionContinuous_Update_triggered()
+{
+  ui->btnUpdateMesh->setVisible(!ui->actionContinuous_Update->isChecked());
+}
+
+void ViewPanel3D::on_btnMenu_pressed()
+{
+  m_DropMenu->popup(QCursor::pos());
+  ui->btnMenu->setDown(false);
+}
+
+void ViewPanel3D::on_btnFlip_clicked()
+{
+  m_Model->FlipAction();
+}
+
+void ViewPanel3D::UpdateActionButtons()
+{
+  ToolbarMode3DType mode = m_Model->GetParentUI()->GetGlobalState()->GetToolbarMode3D();
+  switch(mode)
+    {
+    case TRACKBALL_MODE:
+    case CROSSHAIRS_3D_MODE:
+      ui->btnAccept->setVisible(false);
+      ui->btnCancel->setVisible(false);
+      ui->btnFlip->setVisible(false);
+      break;
+    case SPRAYPAINT_MODE:
+      ui->btnAccept->setVisible(true);
+      ui->btnCancel->setVisible(true);
+      ui->btnFlip->setVisible(false);
+      break;
+    case SCALPEL_MODE:
+      ui->btnAccept->setVisible(true);
+      ui->btnCancel->setVisible(true);
+      ui->btnFlip->setVisible(true);
+      break;
+    }
+}
+
+void ViewPanel3D::on_actionClear_Rendering_triggered()
+{
+  m_Model->ClearRenderingAction();
+
+}
diff --git a/GUI/Qt/Components/ViewPanel3D.h b/GUI/Qt/Components/ViewPanel3D.h
new file mode 100644
index 0000000..6ec2420
--- /dev/null
+++ b/GUI/Qt/Components/ViewPanel3D.h
@@ -0,0 +1,109 @@
+#ifndef VIEWPANEL3D_H
+#define VIEWPANEL3D_H
+
+#include <SNAPComponent.h>
+#include "Generic3DModel.h"
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QDebug>
+#include <QTimer>
+#include <QFutureWatcher>
+#include <itkCommand.h>
+
+namespace Ui {
+  class ViewPanel3D;
+}
+
+namespace itk {
+  template <class T> class MemberCommand;
+}
+
+class Generic3DModel;
+class GenericView3D;
+class QMenu;
+
+
+class ViewPanel3D : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit ViewPanel3D(QWidget *parent = 0);
+  ~ViewPanel3D();
+
+  // Register with the global model
+  void Initialize(GlobalUIModel *model);
+
+  GenericView3D *Get3DView();
+
+signals:
+
+  void renderProgress(int progress);
+
+private slots:
+  virtual void onModelUpdate(const EventBucket &bucket);
+
+  void on_btnUpdateMesh_clicked();
+
+  void on_btnScreenshot_clicked();
+
+  void on_btnAccept_clicked();
+
+  void on_btnCancel_clicked();
+
+  void on_btnExpand_clicked();
+
+  void onTimer();
+
+
+  void on_actionReset_Viewpoint_triggered();
+
+  void on_actionSave_Viewpoint_triggered();
+
+  void on_actionRestore_Viewpoint_triggered();
+
+  void on_actionContinuous_Update_triggered();
+
+  void on_btnMenu_pressed();
+
+  void on_btnFlip_clicked();
+
+  void on_actionClear_Rendering_triggered();
+
+private:
+  Ui::ViewPanel3D *ui;
+
+  GlobalUIModel *m_GlobalUI;
+
+  Generic3DModel *m_Model;
+
+  QMenu *m_DropMenu;
+
+  QTimer *m_RenderTimer;
+
+  // A future used to track background rendering
+  QFuture<void> m_RenderFuture;
+
+  // A mutex on the progress value, which is accesed by multiple threads
+  mutable QMutex m_RenderProgressMutex;
+
+  // Progress of the rendering operation
+  double m_RenderProgressValue;
+
+  // Elapsed time since begin of render operation
+  int m_RenderElapsedTicks;
+
+  typedef itk::MemberCommand<ViewPanel3D> CommandType;
+  SmartPtr<CommandType> m_RenderProgressCommand;
+
+  void UpdateExpandViewButton();
+
+  void UpdateMeshesInBackground();
+
+  void UpdateActionButtons();
+
+  void ProgressCallback(itk::Object *source, const itk::EventObject &event);
+};
+
+#endif // VIEWPANEL3D_H
diff --git a/GUI/Qt/Components/ViewPanel3D.ui b/GUI/Qt/Components/ViewPanel3D.ui
new file mode 100644
index 0000000..0b0ac53
--- /dev/null
+++ b/GUI/Qt/Components/ViewPanel3D.ui
@@ -0,0 +1,312 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ViewPanel3D</class>
+ <widget class="QWidget" name="ViewPanel3D">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>462</width>
+    <height>470</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>2</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="GenericView3D" name="view3d" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="toolbar" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="spacing">
+       <number>4</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QToolButton" name="btnUpdateMesh">
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>update</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_3">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>10</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>10</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnAccept">
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Accept 3D editing operation</string>
+        </property>
+        <property name="text">
+         <string>accept</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnFlip">
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Flip the direction of the cut plane</string>
+        </property>
+        <property name="text">
+         <string>flip</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnCancel">
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Cancel 3D editing operation</string>
+        </property>
+        <property name="text">
+         <string>cancel</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QProgressBar" name="progressBar">
+        <property name="maximumSize">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="value">
+         <number>24</number>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnExpand">
+        <property name="maximumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Expand this view to occupy the entire window</string>
+        </property>
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="icon">
+         <iconset resource="../Resources/SNAPResources.qrc">
+          <normaloff>:/root/dl_3d.png</normaloff>:/root/dl_3d.png</iconset>
+        </property>
+        <property name="autoRaise">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnScreenshot">
+        <property name="maximumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Save a screenshot</string>
+        </property>
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="icon">
+         <iconset>
+          <normalon>:/root/screencapture2.gif</normalon>
+         </iconset>
+        </property>
+        <property name="autoRaise">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="btnMenu">
+        <property name="maximumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Additional 3D view controls</string>
+        </property>
+        <property name="icon">
+         <iconset resource="../Resources/SNAPResources.qrc">
+          <normaloff>:/root/open_popup_16.png</normaloff>:/root/open_popup_16.png</iconset>
+        </property>
+        <property name="iconSize">
+         <size>
+          <width>12</width>
+          <height>12</height>
+         </size>
+        </property>
+        <property name="autoRaise">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+  <action name="actionReset_Viewpoint">
+   <property name="text">
+    <string>Reset Viewpoint</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+K, K</string>
+   </property>
+  </action>
+  <action name="actionSave_Viewpoint">
+   <property name="text">
+    <string>Save Viewpoint</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+K, S</string>
+   </property>
+   <property name="shortcutContext">
+    <enum>Qt::WindowShortcut</enum>
+   </property>
+  </action>
+  <action name="actionRestore_Viewpoint">
+   <property name="text">
+    <string>Restore Viewpoint</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+K, R</string>
+   </property>
+  </action>
+  <action name="actionContinuous_Update">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Continuous Update</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+K, C</string>
+   </property>
+  </action>
+  <action name="actionClear_Rendering">
+   <property name="text">
+    <string>Clear 3D Display</string>
+   </property>
+   <property name="toolTip">
+    <string>Clears the meshes rendered in the 3D display</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+K, X</string>
+   </property>
+  </action>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>GenericView3D</class>
+   <extends>QWidget</extends>
+   <header>GenericView3D.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Components/VoxelIntensityQTableModel.cxx b/GUI/Qt/Components/VoxelIntensityQTableModel.cxx
new file mode 100644
index 0000000..d0e0f99
--- /dev/null
+++ b/GUI/Qt/Components/VoxelIntensityQTableModel.cxx
@@ -0,0 +1,116 @@
+#include "VoxelIntensityQTableModel.h"
+#include <GlobalUIModel.h>
+#include <IRISException.h>
+#include <IRISApplication.h>
+#include <GenericImageData.h>
+#include "LatentITKEventNotifier.h"
+#include "SNAPEvents.h"
+
+#include "LayerSelectionModel.h"
+
+VoxelIntensityQTableModel::VoxelIntensityQTableModel(QObject *parent) :
+    QAbstractTableModel(parent)
+{
+}
+
+void VoxelIntensityQTableModel::SetParentModel(GlobalUIModel *model)
+{
+  m_Model = model;
+
+  // Listen to changes in the model
+  LatentITKEventNotifier::connect(m_Model, CursorUpdateEvent(),
+                                  this, SLOT(onModelUpdate(const EventBucket &)));
+
+  // Listen to changes in the model
+  LatentITKEventNotifier::connect(m_Model, LayerChangeEvent(),
+                                  this, SLOT(onModelUpdate(const EventBucket &)));
+}
+
+int VoxelIntensityQTableModel::rowCount(const QModelIndex &parent) const
+{
+  return m_Model->GetLoadedLayersSelectionModel()->GetNumberOfLayers();
+}
+
+int VoxelIntensityQTableModel::columnCount(const QModelIndex &parent) const
+{
+  return 2;
+}
+
+#include <iomanip>
+
+QVariant VoxelIntensityQTableModel::data(const QModelIndex &index, int role) const
+{
+  if (role == Qt::DisplayRole)
+    {
+    // Get the corresponding layer
+    LayerIterator it =
+        m_Model->GetLoadedLayersSelectionModel()->GetNthLayer(index.row());
+
+    if(index.column() == 0)
+      {
+      return QString(it.GetLayer()->GetNickname().c_str());
+      }
+    else
+      {
+      // Get the cursor position
+      Vector3ui cursor = m_Model->GetDriver()->GetCursorPosition();
+
+      // TODO: do we want to use a tree model here to represent multi-channel
+      // images? For the time being, we can list all of the components, but
+      // we should really come up with something better
+      ImageWrapperBase *iw = it.GetLayer();
+      vnl_vector<double> voxel(iw->GetNumberOfComponents(), 0.0);
+      iw->GetVoxelMappedToNative(cursor, voxel.data_block());
+
+      if(voxel.size() > 1)
+        {
+        std::ostringstream oss;
+        for(int i = 0; i < voxel.size(); i++)
+          {
+          if(i > 0)
+            oss << ",";
+          oss << std::setprecision(3) << voxel[i];
+          }
+        return QString(oss.str().c_str());
+        }
+      else
+        {
+        return voxel[0];
+        }
+      }
+    }
+  return QVariant();
+}
+
+QVariant VoxelIntensityQTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+  if (role == Qt::DisplayRole)
+    {
+    if (orientation == Qt::Horizontal)
+      {
+      return section == 0 ? "Layer" : "Intensity";
+      }
+    }
+  return QVariant();
+}
+
+void VoxelIntensityQTableModel::onModelUpdate(const EventBucket &b)
+{
+  if(b.HasEvent(LayerChangeEvent()))
+    {
+    this->beginResetModel();
+    this->endResetModel();
+    }
+  else
+    {
+    int nr = rowCount();
+    if(nr > 0)
+      {
+      this->dataChanged(index(0,1), index(nr-1, 1));
+      }
+    }
+}
+
+
+
+
diff --git a/GUI/Qt/Components/VoxelIntensityQTableModel.h b/GUI/Qt/Components/VoxelIntensityQTableModel.h
new file mode 100644
index 0000000..a0f0a3c
--- /dev/null
+++ b/GUI/Qt/Components/VoxelIntensityQTableModel.h
@@ -0,0 +1,100 @@
+#ifndef VOXELINTENSITYQTABLEMODEL_H
+#define VOXELINTENSITYQTABLEMODEL_H
+
+#include <QAbstractTableModel>
+#include <RandomAccessCollectionModel.h>
+
+class GlobalUIModel;
+class EventBucket;
+
+class VoxelIntensityQTableModel : public QAbstractTableModel
+{
+  Q_OBJECT
+public:
+  explicit VoxelIntensityQTableModel(QObject *parent = 0);
+
+  void SetParentModel(GlobalUIModel *model);
+
+  int rowCount(const QModelIndex &parent = QModelIndex()) const ;
+  int columnCount(const QModelIndex &parent = QModelIndex()) const;
+  QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+  QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+signals:
+
+public slots:
+
+  void onModelUpdate(const EventBucket &);
+
+private:
+
+  GlobalUIModel *m_Model;
+};
+
+template <class TItem>
+class DefaultQtItemRowTraits
+{
+  virtual int GetColumnCount() = 0;
+  virtual QVariant GetItemData(TItem &, int, Qt::ItemDataRole) = 0;
+};
+
+
+/**
+  This class provides the interface between SNAP's random access collection
+  model (i.e., a list of items with cached random access), and the Qt list
+  and table widgets. This class relies on TItemRowTraits template parameter,
+  which describes how to map objects of type TItem to the cells in the table.
+  */
+template <class TItem, class TItemRowTraits = DefaultQtItemRowTraits<TItem> >
+class QtWrappedRandomAccessCollectionModel : public QAbstractItemModel
+{
+public:
+  // This is the internal model that we provide a wrapping around
+  typedef AbstractRandomAccessCollectionModel<TItem> WrappedModel;
+
+  // Get and set the wrapped model
+  irisGetSetMacro(WrappedModel, WrappedModel *)
+
+  // The traits for this object do not have to be static. We allow the
+  // user to pass it a traits object
+  TItemRowTraits &GetTraits() { return m_Traits; }
+
+  // Subclass standard functions
+  QModelIndex index(int row, int column,
+                    const QModelIndex &parent = QModelIndex()) const
+  {
+    return this->createIndex(row, column);
+  }
+
+  QModelIndex parent(const QModelIndex &child) const
+  {
+    return QModelIndex();
+  }
+
+  int rowCount(const QModelIndex &parent = QModelIndex()) const
+  {
+    return (int) m_WrappedModel->GetSize();
+  }
+
+  int columnCount(const QModelIndex &parent = QModelIndex()) const
+  {
+    return m_Traits.GetColumnCount();
+  }
+
+  QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
+  {
+    // Get the right item
+    TItem item = (*m_WrappedModel)[index.row()];
+    return m_Traits.GetItemData(item, index.column(), role);
+  }
+
+protected:
+
+  WrappedModel *m_WrappedModel;
+  TItemRowTraits m_Traits;
+};
+
+
+
+#endif // VOXELINTENSITYQTABLEMODEL_H
diff --git a/GUI/Qt/Components/ZoomInspector.cxx b/GUI/Qt/Components/ZoomInspector.cxx
new file mode 100644
index 0000000..b20557f
--- /dev/null
+++ b/GUI/Qt/Components/ZoomInspector.cxx
@@ -0,0 +1,96 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "ZoomInspector.h"
+#include "ui_ZoomInspector.h"
+
+#include "GlobalUIModel.h"
+#include "SliceWindowCoordinator.h"
+#include "QtWidgetActivator.h"
+#include "QtDoubleSpinBoxCoupling.h"
+#include "QtCheckBoxCoupling.h"
+#include <SNAPQtCommon.h>
+#include <vnl/vnl_math.h>
+
+ZoomInspector::ZoomInspector(QWidget *parent) :
+    SNAPComponent(parent),
+    ui(new Ui::ZoomInspector)
+{
+  ui->setupUi(this);
+
+}
+
+ZoomInspector::~ZoomInspector()
+{
+  delete ui;
+}
+
+
+void ZoomInspector::SetModel(GlobalUIModel *model)
+{
+  // Set the model
+  m_Model = model;
+
+  // Connect buttons to global actions
+  ui->btnResetViews->setAction("actionZoomToFitInAllViews");
+  ui->btnCenterViews->setAction("actionCenter_on_Cursor");
+
+  // Conditional activation of widgets
+  activateOnFlag(ui->inZoom, model, UIF_LINKED_ZOOM);
+  activateOnFlag(ui->btnZoom1, model, UIF_LINKED_ZOOM);
+  activateOnFlag(ui->btnZoom2, model, UIF_LINKED_ZOOM);
+  activateOnFlag(ui->btnZoom4, model, UIF_LINKED_ZOOM);
+
+  activateOnFlag(this, model, UIF_BASEIMG_LOADED);
+
+  // Couple the linked zoom checkbox
+  makeCoupling(ui->chkLinkedZoom,
+               model->GetSliceCoordinator()->GetLinkedZoomModel());
+
+  // Couple zoom widget to the linked zoom level
+  makeCoupling(ui->inZoom,
+               model->GetSliceCoordinator()->GetCommonZoomFactorModel());
+}
+
+void ZoomInspector::on_chkLinkedZoom_stateChanged(int state)
+{
+  m_Model->GetSliceCoordinator()->SetLinkedZoom(state == Qt::Checked);
+}
+
+void ZoomInspector::on_btnZoom1_pressed()
+{
+  m_Model->GetSliceCoordinator()->SetZoomPercentageInAllWindows(1);
+}
+
+void ZoomInspector::on_btnZoom2_pressed()
+{
+  m_Model->GetSliceCoordinator()->SetZoomPercentageInAllWindows(2);
+}
+
+void ZoomInspector::on_btnZoom4_pressed()
+{
+  m_Model->GetSliceCoordinator()->SetZoomPercentageInAllWindows(4);
+}
diff --git a/GUI/Qt/Components/ZoomInspector.h b/GUI/Qt/Components/ZoomInspector.h
new file mode 100644
index 0000000..d3aa850
--- /dev/null
+++ b/GUI/Qt/Components/ZoomInspector.h
@@ -0,0 +1,65 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef ZOOMINSPECTOR_H
+#define ZOOMINSPECTOR_H
+
+#include <SNAPComponent.h>
+#include <SNAPCommon.h>
+
+class GlobalUIModel;
+
+namespace Ui {
+    class ZoomInspector;
+}
+
+class ZoomInspector : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit ZoomInspector(QWidget *parent = 0);
+  ~ZoomInspector();
+
+  irisGetMacro(Model, GlobalUIModel *)
+
+  void SetModel(GlobalUIModel *model);
+
+private slots:
+
+  void on_chkLinkedZoom_stateChanged(int arg1);
+
+  void on_btnZoom1_pressed();
+  void on_btnZoom2_pressed();
+  void on_btnZoom4_pressed();
+
+private:
+  Ui::ZoomInspector *ui;
+
+  GlobalUIModel *m_Model;
+};
+
+#endif // ZOOMINSPECTOR_H
diff --git a/GUI/Qt/Components/ZoomInspector.ui b/GUI/Qt/Components/ZoomInspector.ui
new file mode 100644
index 0000000..5ff23b3
--- /dev/null
+++ b/GUI/Qt/Components/ZoomInspector.ui
@@ -0,0 +1,380 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ZoomInspector</class>
+ <widget class="QWidget" name="ZoomInspector">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>173</width>
+    <height>526</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>60</width>
+    <height>0</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">*  {
+font-size: 12px;
+}
+</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QCheckBox" name="chkLinkedZoom">
+     <property name="font">
+      <font>
+       <pointsize>-1</pointsize>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="focusPolicy">
+      <enum>Qt::TabFocus</enum>
+     </property>
+     <property name="text">
+      <string>Linked zoom</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="spacing">
+      <number>0</number>
+     </property>
+     <property name="leftMargin">
+      <number>20</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="font">
+        <font>
+         <pointsize>-1</pointsize>
+        </font>
+       </property>
+       <property name="styleSheet">
+        <string notr="true">font-size:10px;</string>
+       </property>
+       <property name="text">
+        <string>Maintains a common zoom factor in all slice views.</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+       </property>
+       <property name="wordWrap">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Fixed</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>10</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_4">
+     <property name="enabled">
+      <bool>true</bool>
+     </property>
+     <property name="text">
+      <string>Common zoom factor:</string>
+     </property>
+     <property name="margin">
+      <number>0</number>
+     </property>
+     <property name="indent">
+      <number>0</number>
+     </property>
+     <property name="buddy">
+      <cstring>inZoom</cstring>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <property name="spacing">
+      <number>4</number>
+     </property>
+     <item row="0" column="0">
+      <spacer name="horizontalSpacer_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeType">
+        <enum>QSizePolicy::Fixed</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item row="0" column="1" colspan="3">
+      <widget class="QDoubleSpinBox" name="inZoom">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+         <horstretch>1</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>120</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="font">
+        <font>
+         <pointsize>-1</pointsize>
+        </font>
+       </property>
+       <property name="keyboardTracking">
+        <bool>false</bool>
+       </property>
+       <property name="prefix">
+        <string/>
+       </property>
+       <property name="suffix">
+        <string> px/mm</string>
+       </property>
+       <property name="decimals">
+        <number>3</number>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1" colspan="3">
+      <layout class="QHBoxLayout" name="horizontalLayout_2">
+       <property name="spacing">
+        <number>4</number>
+       </property>
+       <item>
+        <widget class="QPushButton" name="btnZoom1">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>32</width>
+           <height>24</height>
+          </size>
+         </property>
+         <property name="styleSheet">
+          <string notr="true"/>
+         </property>
+         <property name="text">
+          <string>1x</string>
+         </property>
+         <property name="iconSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="btnZoom2">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>32</width>
+           <height>24</height>
+          </size>
+         </property>
+         <property name="baseSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>2x</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="btnZoom4">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>32</width>
+           <height>24</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>4x</string>
+         </property>
+         <property name="flat">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <spacer name="horizontalSpacer_3">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>0</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <property name="styleSheet">
+      <string notr="true">.QWidget { 
+	padding-left:50px; 
+}</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>2</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line">
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="lineWidth">
+      <number>1</number>
+     </property>
+     <property name="midLineWidth">
+      <number>1</number>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout_3"/>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_2" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_5">
+      <item>
+       <widget class="QActionButton" name="btnResetViews">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>1</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="baseSize">
+         <size>
+          <width>0</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>-1</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>Zoom to fit</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QActionButton" name="btnCenterViews">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>-1</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>Center on cursor</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>357</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QActionButton</class>
+   <extends>QPushButton</extends>
+   <header location="global">QActionButton.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Coupling/QtAbstractButtonCoupling.h b/GUI/Qt/Coupling/QtAbstractButtonCoupling.h
new file mode 100644
index 0000000..e0e44e7
--- /dev/null
+++ b/GUI/Qt/Coupling/QtAbstractButtonCoupling.h
@@ -0,0 +1,160 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTABSTRACTBUTTONCOUPLING_H
+#define QTABSTRACTBUTTONCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+#include "SNAPQtCommon.h"
+#include <QAbstractButton>
+#include <QColorDialog>
+#include <QColorButtonWidget.h>
+
+/**
+  Default traits for QColorButtonWidget, to be hooked up to a model of integer
+  3-vector that specifies color in the 0-255 range
+  */
+template <class TColorRep>
+class DefaultWidgetValueTraits< iris_vector_fixed<TColorRep, 3>, QColorButtonWidget>
+    : public WidgetValueTraitsBase<iris_vector_fixed<TColorRep, 3>, QColorButtonWidget *>
+{
+public:
+
+  typedef iris_vector_fixed<TColorRep, 3> ColorVec;
+
+  // Get the Qt signal that the widget fires when its value has changed. The
+  // value here is the selected item in the combo box.
+  const char *GetSignal()
+  {
+    return SIGNAL(valueChanged());
+  }
+
+  ColorVec GetValue(QColorButtonWidget *w)
+  {
+    QColor qclr = w->value();
+    return ColorVec(qclr.red(), qclr.green(), qclr.blue());
+  }
+
+  void SetValue(QColorButtonWidget *w, const ColorVec &value)
+  {
+    // We have to actually find the item
+    w->setValue(QColor(value[0],value[1],value[2]));
+  }
+
+  void SetValueToNull(QColorButtonWidget *w)
+  {
+    w->setValue(QColor());
+  }
+
+protected:
+};
+
+/**
+  Alternative traits for QColorButtonWidget, to be hooked up to a model of double
+  3-vector that specifies color in the 0-1 range
+  */
+template <>
+class DefaultWidgetValueTraits< iris_vector_fixed<double, 3>, QColorButtonWidget>
+    : public WidgetValueTraitsBase<iris_vector_fixed<double, 3>, QColorButtonWidget *>
+{
+public:
+
+  typedef iris_vector_fixed<double, 3> ColorVec;
+
+  // Get the Qt signal that the widget fires when its value has changed. The
+  // value here is the selected item in the combo box.
+  const char *GetSignal()
+  {
+    return SIGNAL(valueChanged());
+  }
+
+  ColorVec GetValue(QColorButtonWidget *w)
+  {
+    QColor qclr = w->value();
+    return ColorVec(qclr.red() / 255.0, qclr.green() / 255.0, qclr.blue() / 255.0);
+  }
+
+  void SetValue(QColorButtonWidget *w, const ColorVec &value)
+  {
+    // We have to actually find the item
+    Vector3i cint = to_int(value * 255.0);
+    w->setValue(QColor(cint[0], cint[1], cint[2]));
+  }
+
+  void SetValueToNull(QColorButtonWidget *w)
+  {
+    w->setValue(QColor());
+  }
+
+protected:
+};
+
+
+/**
+ * This traits class allows a color button widget to be hooked up to a model
+ * with a domain. However, the domain will be ignored.
+ */
+template <class TAtomic>
+class DefaultWidgetDomainTraits<NumericValueRange<TAtomic>, QColorButtonWidget>
+    : public WidgetDomainTraitsBase<NumericValueRange<TAtomic>, QColorButtonWidget *>
+{
+public:
+  typedef NumericValueRange<TAtomic> DomainType;
+  virtual void SetDomain(QColorButtonWidget *, const DomainType &) { }
+  virtual DomainType GetDomain(QColorButtonWidget *) { return DomainType(); }
+};
+
+
+/**
+ * A simple coupling between a button and a boolean value.
+ */
+template <>
+class DefaultWidgetValueTraits<bool, QAbstractButton>
+    : public WidgetValueTraitsBase<bool, QAbstractButton *>
+{
+public:
+  const char *GetSignal()
+  {
+    return SIGNAL(toggled(bool));
+  }
+
+  bool GetValue(QAbstractButton *w)
+  {
+    return w->isChecked();
+  }
+
+  void SetValue(QAbstractButton *w, const bool &value)
+  {
+    w->setChecked(value);
+  }
+
+  void SetValueToNull(QAbstractButton *w)
+  {
+    w->setChecked(false);
+  }
+};
+
+#endif // QTABSTRACTBUTTONCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtAbstractItemViewCoupling.h b/GUI/Qt/Coupling/QtAbstractItemViewCoupling.h
new file mode 100644
index 0000000..1789c5d
--- /dev/null
+++ b/GUI/Qt/Coupling/QtAbstractItemViewCoupling.h
@@ -0,0 +1,294 @@
+#ifndef QTABSTRACTITEMVIEWCOUPLING_H
+#define QTABSTRACTITEMVIEWCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+#include "SNAPQtCommon.h"
+#include <QAbstractItemModel>
+#include <QItemSelectionModel>
+#include <QAbstractItemView>
+#include <QModelIndex>
+#include <QStandardItemModel>
+#include <QAbstractProxyModel>
+#include <ColorLabel.h>
+
+/**
+ * Some Ideas:
+ *
+ * 1. Coupling between a selection model and an integer value. Treat the
+ *    domain as trivial.
+ *
+ * 2. Coupling between a model that represents a list of items with descriptors
+ *    and a QStandardItemModel. Mapping is through a coupling. This coupling
+ *    maps between rows in the descriptor and items in the item model.
+ */
+
+
+
+
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QAbstractItemView>
+    : public WidgetValueTraitsBase<TAtomic, QAbstractItemView *>
+{
+public:
+  const char *GetSignal()
+  {
+    return SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &));
+  }
+
+  virtual QObject *GetSignalEmitter(QObject *w)
+  {
+    QAbstractItemView *view = dynamic_cast<QAbstractItemView *>(w);
+    return view ? view->selectionModel() : NULL;
+  }
+
+  TAtomic GetValue(QAbstractItemView *w)
+  {
+    // Get the UserData associated with the current item    
+    QModelIndex icur = w->currentIndex();
+    QModelIndex irow = w->model()->index(icur.row(), 0, w->currentIndex().parent());
+    return irow.data(Qt::UserRole).value<TAtomic>();
+  }
+
+  bool FindRowRecursive(QAbstractItemView *w, QModelIndex parent, const TAtomic &value)
+  {
+    for(int i = 0; i < w->model()->rowCount(parent); i++)
+      {
+      QModelIndex index = w->model()->index(i, 0, parent);
+      TAtomic val = w->model()->data(index, Qt::UserRole).value<TAtomic>();
+      if(val == value)
+        {
+        w->setCurrentIndex(index);
+        return true;
+        }
+      else if(FindRowRecursive(w, index, value))
+        {
+        return true;
+        }
+      }
+    return false;
+  }
+
+  void SetValue(QAbstractItemView *w, const TAtomic &value)
+  {
+    // Find the item in the model
+    FindRowRecursive(w, QModelIndex(), value);
+  }
+
+  void SetValueToNull(QAbstractItemView *w)
+  {
+    QModelIndex index = w->model()->index(-1, 0);
+    w->setCurrentIndex(index);
+  }
+};
+
+
+template <class TItemDomain, class TRowTraits>
+class QStandardItemModelWidgetDomainTraits :
+    public WidgetDomainTraitsBase<TItemDomain, QAbstractItemView *>
+{
+public:
+  // The information about the item type are taken from the domain
+  typedef typename TItemDomain::ValueType AtomicType;
+  typedef typename TItemDomain::DescriptorType DescriptorType;
+  typedef TItemDomain DomainType;
+
+  // Navigate through proxy models until we find a standard item model in the
+  // view. Allows couplings to be installed on views with proxies
+  QStandardItemModel *GetTopLevelModel(QAbstractItemView *w)
+  {
+    QAbstractItemModel *model = w->model();
+    while(model)
+      {
+      QStandardItemModel *msi = dynamic_cast<QStandardItemModel *>(model);
+      if(msi)
+        return msi;
+
+      QAbstractProxyModel *mpx = dynamic_cast<QAbstractProxyModel *>(model);
+      if(mpx)
+        model = mpx->sourceModel();
+      }
+    return NULL;
+  }
+
+  void SetDomain(QAbstractItemView *w, const DomainType &domain)
+  {
+    // Remove everything from the model
+    QStandardItemModel *model = GetTopLevelModel(w);
+    if(!model)
+      return;
+
+    model->clear();
+    model->setColumnCount(TRowTraits::columnCount());
+
+    // Populate
+    for(typename DomainType::const_iterator it = domain.begin();
+        it != domain.end(); ++it)
+      {
+      // Get the key/value pair
+      AtomicType value = domain.GetValue(it);
+      const DescriptorType &row = domain.GetDescription(it);
+
+      // Use the row traits to map information to the widget
+      QList<QStandardItem *> rlist;
+      for(int j = 0; j < model->columnCount(); j++)
+        {
+        QStandardItem *item = new QStandardItem();
+        TRowTraits::updateItem(item, j, value, row);
+        rlist.append(item);
+        }
+      model->appendRow(rlist);
+      }
+  }
+
+  void UpdateDomainDescription(QAbstractItemView *w, const DomainType &domain)
+  {
+    // Remove everything from the model
+    QStandardItemModel *model = GetTopLevelModel(w);
+    if(!model)
+      return;
+
+    // This is not the most efficient way of doing things, because we
+    // are still linearly parsing through the widget and updating rows.
+    // But at least the actual modifications to the widget are limited
+    // to the rows that have been modified.
+    //
+    // What would be more efficient is to have a list of ids which have
+    // been modified and update only those. Or even better, implement all
+    // of this using an AbstractItemModel
+    int nrows = model->rowCount();
+    for(int i = 0; i < nrows; i++)
+      {
+      QStandardItem *item = model->item(i);
+      AtomicType id = TRowTraits::getItemValue(item);
+      typename DomainType::const_iterator it = domain.find(id);
+      if(it != domain.end())
+        {
+        const DescriptorType &row = domain.GetDescription(it);
+        for(int j = 0; j <  model->columnCount(); j++)
+          TRowTraits::updateItem(model->item(i,j), j, id, row);
+        }
+      }
+  }
+
+  TItemDomain GetDomain(QAbstractItemView *w)
+  {
+    // We don't actually pull the widget because the domain is fully specified
+    // by the model.
+    return DomainType();
+  }
+};
+
+class SingleColumnColorLabelToQSIMCouplingRowTraits
+{
+public:
+
+  static int columnCount() { return 1; }
+
+  static void updateItem(QStandardItem *item, int column, LabelType label, const ColorLabel &cl)
+  {
+    // Handle the timestamp - if the timestamp has not changed, don't need to update
+    unsigned long ts = item->data(Qt::UserRole+1).toLongLong();
+    if(ts == cl.GetTimeStamp().GetMTime())
+      return;
+
+    // The description
+    QString text = QString::fromUtf8(cl.GetLabel());
+
+    // The color
+    QColor fill(cl.GetRGB(0), cl.GetRGB(1), cl.GetRGB(2));
+
+    // Icon based on the color
+    QIcon ic = CreateColorBoxIcon(16, 16, fill);
+
+    // Create item and set its properties
+    item->setIcon(ic);
+    item->setText(text);
+    item->setData(label, Qt::UserRole);
+    item->setData(text, Qt::EditRole);
+    item->setData((qulonglong) cl.GetTimeStamp().GetMTime(), Qt::UserRole+1);
+  }
+
+  static LabelType getItemValue(QStandardItem *item)
+  {
+    return item->data(Qt::UserRole).value<LabelType>();
+  }
+};
+
+class TwoColumnColorLabelToQSIMCouplingRowTraits
+{
+public:
+
+  static int columnCount() { return 2; }
+
+  static void updateItem(QStandardItem *item, int column, LabelType label, const ColorLabel &cl)
+  {
+    // Handle the timestamp - if the timestamp has not changed, don't need to update
+    unsigned long ts = item->data(Qt::UserRole+1).toLongLong();
+    if(ts == cl.GetTimeStamp().GetMTime())
+      return;
+
+    // The description
+    if(column == 0)
+      {
+      QString text = QString("%1").arg(label);
+
+      // The color
+      QColor fill(cl.GetRGB(0), cl.GetRGB(1), cl.GetRGB(2));
+
+      // Icon based on the color
+      QIcon ic = CreateColorBoxIcon(16, 16, fill);
+
+      // Create item and set its properties
+      item->setIcon(ic);
+      item->setText(text);
+      item->setData(text, Qt::EditRole);
+      item->setData(label, Qt::UserRole);
+      }
+    else if(column == 1)
+      {
+      QString text = QString::fromUtf8(cl.GetLabel());
+      item->setText(text);
+      item->setData(text, Qt::EditRole);
+      }
+
+    // Update the timestamp
+    item->setData((qulonglong) cl.GetTimeStamp().GetMTime(), Qt::UserRole+1);
+  }
+
+  static LabelType getItemValue(QStandardItem *item)
+  {
+    return item->data(Qt::UserRole).value<LabelType>();
+  }
+};
+
+
+template<class TAtomic, class TItemDescriptor>
+class DefaultQSIMCouplingRowTraits
+{
+};
+
+template<>
+class DefaultQSIMCouplingRowTraits<LabelType, ColorLabel>
+    : public TwoColumnColorLabelToQSIMCouplingRowTraits
+{
+};
+
+template<class TDomain>
+class DefaultWidgetDomainTraits<TDomain, QAbstractItemView>
+    : public QStandardItemModelWidgetDomainTraits<
+        TDomain, DefaultQSIMCouplingRowTraits<typename TDomain::ValueType,
+                                              typename TDomain::DescriptorType> >
+{
+};
+
+template<>
+class DefaultWidgetDomainTraits<TrivialDomain, QAbstractItemView>
+{
+public:
+  void SetDomain(QAbstractItemView *w, const TrivialDomain &domain) {}
+  TrivialDomain GetDomain(QAbstractItemView *w) { return TrivialDomain(); }
+  void UpdateDomainDescription(QAbstractItemView *w, const TrivialDomain &domain) {}
+};
+
+
+#endif // QTABSTRACTITEMVIEWCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtActionCoupling.h b/GUI/Qt/Coupling/QtActionCoupling.h
new file mode 100644
index 0000000..fb6c241
--- /dev/null
+++ b/GUI/Qt/Coupling/QtActionCoupling.h
@@ -0,0 +1,36 @@
+#ifndef QTACTIONCOUPLING_H
+#define QTACTIONCOUPLING_H
+
+#include <QAction>
+
+/**
+  Default traits for a checkable QAction to a boolean
+  */
+template <>
+class DefaultWidgetValueTraits<bool, QAction>
+    : public WidgetValueTraitsBase<bool, QAction *>
+{
+public:
+  const char *GetSignal()
+  {
+    return SIGNAL(triggered(bool));
+  }
+
+  bool GetValue(QAction *w)
+  {
+    return w->isChecked();
+  }
+
+  void SetValue(QAction *w, const bool &value)
+  {
+    w->setChecked(value);
+  }
+
+  void SetValueToNull(QAction *w)
+  {
+    w->setChecked(false);
+  }
+
+};
+
+#endif // QTACTIONCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtActionGroupCoupling.h b/GUI/Qt/Coupling/QtActionGroupCoupling.h
new file mode 100644
index 0000000..fb1729a
--- /dev/null
+++ b/GUI/Qt/Coupling/QtActionGroupCoupling.h
@@ -0,0 +1,49 @@
+#ifndef QTACTIONGROUPCOUPLING_H
+#define QTACTIONGROUPCOUPLING_H
+
+#include <QtCheckableWidgetGroupCoupling.h>
+#include <QAction>
+#include <QActionGroup>
+
+/**
+ * Create a coupling between an enum (not necessarily starting with zero) and an
+ * QActionGroup containing a set of actions. The mapping from enum values to
+ * actions is provided by the actionMap parameter
+ */
+template <class TAtomic>
+void makeActionGroupCoupling(
+    QActionGroup *actionGroup,
+    std::map<TAtomic, QAction *> actionMap,
+    AbstractPropertyModel<TAtomic> *model)
+{
+  makeCheckableWidgetGroupCoupling(actionGroup, actionMap, model);
+}
+
+
+/**
+ * Create a coupling between an enum (starting with zero) and an QActionGroup
+ */
+template <class TAtomic>
+void makeActionGroupCoupling(
+    QActionGroup *w, AbstractPropertyModel<TAtomic> *model)
+{
+  QList<QAction *> kids = w->actions();
+  std::map<TAtomic, QAction *> buttonMap;
+  int iwidget = 0;
+  for(QList<QAction *>::const_iterator it = kids.begin(); it != kids.end(); ++it)
+    {
+    QAction *qab = dynamic_cast<QAction *>(*it);
+    if(qab)
+      buttonMap[static_cast<TAtomic>(iwidget++)] = qab;
+    }
+  makeCheckableWidgetGroupCoupling(w, buttonMap, model);
+}
+
+
+
+
+
+
+
+
+#endif // QTACTIONGROUPCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtCheckBoxCoupling.h b/GUI/Qt/Coupling/QtCheckBoxCoupling.h
new file mode 100644
index 0000000..f269ad0
--- /dev/null
+++ b/GUI/Qt/Coupling/QtCheckBoxCoupling.h
@@ -0,0 +1,59 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTCHECKBOXCOUPLING_H
+#define QTCHECKBOXCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+#include <QCheckBox>
+
+template <class TAtomic>
+struct DefaultWidgetValueTraits<TAtomic, QCheckBox>
+    : public WidgetValueTraitsBase<TAtomic, QCheckBox *>
+{
+public:
+  const char *GetSignal()
+  {
+    return SIGNAL(stateChanged(int));
+  }
+
+  TAtomic GetValue(QCheckBox *w)
+  {
+    return static_cast<TAtomic>(w->isChecked());
+  }
+
+  void SetValue(QCheckBox *w, const TAtomic &value)
+  {
+    w->setChecked(static_cast<bool>(value));
+  }
+
+  void SetValueToNull(QCheckBox *w)
+  {
+    w->setChecked(false);
+  }
+};
+
+#endif // QTCHECKBOXCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtCheckableWidgetGroupCoupling.h b/GUI/Qt/Coupling/QtCheckableWidgetGroupCoupling.h
new file mode 100644
index 0000000..db86f79
--- /dev/null
+++ b/GUI/Qt/Coupling/QtCheckableWidgetGroupCoupling.h
@@ -0,0 +1,97 @@
+#ifndef QTCHECKABLEWIDGETGROUPCOUPLING_H
+#define QTCHECKABLEWIDGETGROUPCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+
+template <class TAtomic, class TParentWidget, class TCheckableWidgetBase>
+struct RadioButtonGroupTraits :
+    public WidgetValueTraitsBase<TAtomic, TParentWidget *>
+{
+public:
+  typedef std::map<TAtomic, TCheckableWidgetBase *> ButtonMap;
+  typedef typename ButtonMap::iterator ButtonIterator;
+
+  RadioButtonGroupTraits(ButtonMap bm) : m_ButtonMap(bm) {}
+
+  TAtomic GetValue(TParentWidget *w)
+  {
+    // Figure out which button is checked
+    for(ButtonIterator it = m_ButtonMap.begin(); it != m_ButtonMap.end(); ++it)
+      {
+        TCheckableWidgetBase *qab = it->second;
+        if(qab->isChecked())
+          return it->first;
+      }
+
+    // This is ambiguous...
+    return static_cast<TAtomic>(0);
+  }
+
+  void SetValue(TParentWidget *w, const TAtomic &value)
+  {
+    // Set all the buttons
+    for(ButtonIterator it = m_ButtonMap.begin(); it != m_ButtonMap.end(); ++it)
+      {
+      TCheckableWidgetBase *qab = it->second;
+      qab->setChecked(it->first == value);
+      }
+  }
+
+  void SetValueToNull(TParentWidget *w)
+  {
+    // Set all the buttons
+    for(ButtonIterator it = m_ButtonMap.begin(); it != m_ButtonMap.end(); ++it)
+      {
+      TCheckableWidgetBase *qab = it->second;
+      qab->setChecked(false);
+      }
+  }
+
+protected:
+
+  ButtonMap m_ButtonMap;
+};
+
+
+template <class TAtomic, class TParentWidget, class TCheckableWidgetBase>
+void makeCheckableWidgetGroupCoupling(
+    TParentWidget *parentWidget,
+    std::map<TAtomic, TCheckableWidgetBase *> buttonMap,
+    AbstractPropertyModel<TAtomic> *model)
+{
+  typedef AbstractPropertyModel<TAtomic> ModelType;
+  typedef RadioButtonGroupTraits<TAtomic, TParentWidget, TCheckableWidgetBase> WidgetValueTraits;
+  typedef DefaultWidgetDomainTraits<TrivialDomain, TParentWidget> WidgetDomainTraits;
+
+  typedef PropertyModelToWidgetDataMapping<
+      ModelType, TParentWidget *,
+      WidgetValueTraits, WidgetDomainTraits> MappingType;
+
+  WidgetValueTraits valueTraits(buttonMap);
+  WidgetDomainTraits domainTraits;
+  MappingType *mapping = new MappingType(parentWidget, model, valueTraits, domainTraits);
+  QtCouplingHelper *h = new QtCouplingHelper(parentWidget, mapping);
+
+  // Populate the widget
+  mapping->InitializeWidgetFromModel();
+
+  // Listen to value change events from the model
+  LatentITKEventNotifier::connect(
+        model, ValueChangedEvent(),
+        h, SLOT(onPropertyModification(const EventBucket &)));
+
+  LatentITKEventNotifier::connect(
+        model, DomainChangedEvent(),
+        h, SLOT(onPropertyModification(const EventBucket &)));
+
+  // Listen to value change events for every child widget
+  typedef typename std::map<TAtomic, TCheckableWidgetBase *>::const_iterator Iter;
+  for(Iter it = buttonMap.begin(); it != buttonMap.end(); ++it)
+    {
+      TCheckableWidgetBase *qab = it->second;
+      h->connect(qab, SIGNAL(toggled(bool)), SLOT(onUserModification()));
+    }
+}
+
+
+#endif // QTCHECKABLEWIDGETGROUPCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtColorWheelCoupling.h b/GUI/Qt/Coupling/QtColorWheelCoupling.h
new file mode 100644
index 0000000..5f9544c
--- /dev/null
+++ b/GUI/Qt/Coupling/QtColorWheelCoupling.h
@@ -0,0 +1,51 @@
+#ifndef QTCOLORWHEELCOUPLING_H
+#define QTCOLORWHEELCOUPLING_H
+
+#include "ColorWheel.h"
+
+std::ostream &operator << (std::ostream &out, QColor color)
+{
+  out << color.red() << ", " << color.green() << ", " << color.blue();
+  return out;
+}
+
+template <class TColorRep>
+class DefaultWidgetValueTraits< iris_vector_fixed<TColorRep, 3>, ColorWheel>
+    : public WidgetValueTraitsBase<iris_vector_fixed<TColorRep, 3>, ColorWheel *>
+{
+public:
+
+  typedef iris_vector_fixed<TColorRep, 3> ColorVec;
+
+  // Get the Qt signal that the widget fires when its value has changed. The
+  // value here is the selected item in the combo box.
+  const char *GetSignal()
+  {
+    return SIGNAL(colorChange(const QColor &));
+  }
+
+  ColorVec GetValue(ColorWheel *w)
+  {
+    QColor qclr = w->color();
+    return ColorVec(qclr.red(), qclr.green(), qclr.blue());
+  }
+
+  void SetValue(ColorWheel *w, const ColorVec &value)
+  {
+    // We have to actually find the item
+    QColor newcol(value[0],value[1],value[2]);
+    if(newcol != w->color())
+      {
+      w->setColor(newcol);
+      }
+  }
+
+  void SetValueToNull(ColorWheel *w)
+  {
+    w->setColor(QColor());
+  }
+};
+
+
+
+#endif // QTCOLORWHEELCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtComboBoxCoupling.h b/GUI/Qt/Coupling/QtComboBoxCoupling.h
new file mode 100644
index 0000000..fe04a2c
--- /dev/null
+++ b/GUI/Qt/Coupling/QtComboBoxCoupling.h
@@ -0,0 +1,267 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTCOMBOBOXCOUPLING_H
+#define QTCOMBOBOXCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+#include "SNAPQtCommon.h"
+#include <ColorLabel.h>
+#include <QComboBox>
+
+// This is to allow the code below to work with DrawOverFilter
+Q_DECLARE_METATYPE(DrawOverFilter)
+
+/**
+  Default traits for mapping a numeric value (or any sort of key, actually)
+  to a row in a combo box
+  */
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QComboBox>
+    : public WidgetValueTraitsBase<TAtomic, QComboBox *>
+{
+public:
+  // Get the Qt signal that the widget fires when its value has changed. The
+  // value here is the selected item in the combo box.
+  const char *GetSignal()
+  {
+    return SIGNAL(currentIndexChanged(int));
+  }
+
+  TAtomic GetValue(QComboBox *w)
+  {
+    int index = w->currentIndex();
+    QVariant id = w->itemData(index);
+    return id.value<TAtomic>();
+  }
+
+  void SetValue(QComboBox *w, const TAtomic &value)
+  {
+    // We have to actually find the item. I looked up the Qt findItem
+    // method and it seems quite involved and also quite long. So we
+    // just do our own loop
+    for(int i = 0; i < w->count(); i++)
+      {
+      if(value == w->itemData(i).value<TAtomic>())
+        {
+        w->setCurrentIndex(i);
+        return;
+        }
+      }
+    w->setCurrentIndex(-1);
+  }
+
+  void SetValueToNull(QComboBox *w)
+  {
+    w->setCurrentIndex(-1);
+  }
+};
+
+/**
+  These are the row traits for adding and updating rows in combo boxes. This
+  class is further parameterized by the class TItemDesriptionTraits, which is
+  used to obtain the text and icon information from the value/description pairs
+  provided by the model.
+  */
+template <class TAtomic, class TDesc, class TItemDesriptionTraits>
+class TextAndIconComboBoxRowTraits
+{
+public:
+  static void removeAll(QComboBox *w)
+  {
+    w->clear();
+  }
+
+  static int getNumberOfRows(QComboBox *w)
+  {
+    return w->count();
+  }
+
+  static TAtomic getValueInRow(QComboBox *w, int i)
+  {
+    return w->itemData(i).value<TAtomic>();
+  }
+
+  static void appendRow(QComboBox *w, TAtomic label, const TDesc &desc)
+  {
+    // The description
+    QString text = TItemDesriptionTraits::GetText(label, desc); // QString text(cl.GetLabel());
+
+    // The icon
+    QIcon icon = TItemDesriptionTraits::GetIcon(label, desc);
+
+    // The icon signature - a value that can be used to check if the icon has changed
+    QVariant iconSig = TItemDesriptionTraits::GetIconSignature(label, desc);
+
+    // Icon based on the color
+    w->addItem(icon, text, QVariant::fromValue(label));
+    w->setItemData(w->count()-1, iconSig, Qt::UserRole + 1);
+  }
+
+  static void updateRowDescription(QComboBox *w, int index, const TDesc &desc)
+  {
+    // The current value
+    TAtomic label = w->itemData(index).value<TAtomic>();
+
+    // Get the properies and compare them to the color label
+    QVariant currentIconSig = w->itemData(index, Qt::UserRole + 1);
+    QVariant newIconSig = TItemDesriptionTraits::GetIconSignature(label, desc);
+
+    if(currentIconSig != newIconSig)
+      {
+      QIcon ic = TItemDesriptionTraits::GetIcon(label, desc);
+      w->setItemIcon(index, ic);
+      w->setItemData(index, newIconSig, Qt::UserRole + 1);
+      }
+
+    QString currentText = w->itemText(index);
+    QString newText = TItemDesriptionTraits::GetText(label, desc);
+
+    if(currentText != newText)
+      {
+      w->setItemText(index, newText);
+      }
+  }
+};
+
+template<class TAtomic>
+class StringRowDescriptionTraits
+{
+public:
+  static QString GetText(TAtomic label, const std::string &text)
+  {
+    return QString(text.c_str());
+  }
+
+  static QIcon GetIcon(TAtomic label, const std::string &text)
+  {
+    return QIcon();
+  }
+
+  static QVariant GetIconSignature(TAtomic label, const std::string &text)
+  {
+    return QVariant(0);
+  }
+};
+
+// TODO: this stuff should be replaced by coupling with the abstract item model
+// Specific traits for filling drawing color label combos
+class DrawingColorRowDescriptionTraits
+{
+public:
+
+  static QString GetText(LabelType label, const ColorLabel &cl)
+  {
+    return GetTitleForColorLabel(cl);
+  }
+
+  static QIcon GetIcon(LabelType label, const ColorLabel &cl)
+  {
+    QBrush brush = GetBrushForColorLabel(cl);
+    return CreateColorBoxIcon(16, 16, brush);
+  }
+
+  static QVariant GetIconSignature(LabelType label, const ColorLabel &cl)
+  {
+    return QColor(cl.GetRGB(0), cl.GetRGB(1), cl.GetRGB(2));
+  }
+};
+
+// Specific traits for filling draw-over color label combos
+class DrawOverFilterRowDescriptionTraits
+{
+public:
+
+  static QString GetText(DrawOverFilter filter, const ColorLabel &cl)
+  {
+    return GetTitleForDrawOverFilter(filter, cl);
+  }
+
+  static QIcon GetIcon(DrawOverFilter filter, const ColorLabel &cl)
+  {
+    QBrush brush = GetBrushForDrawOverFilter(filter, cl);
+    return CreateColorBoxIcon(16, 16, brush);
+  }
+
+  static QVariant GetIconSignature(DrawOverFilter filter, const ColorLabel &cl)
+  {
+    if(filter.CoverageMode == PAINT_OVER_ONE)
+      return DrawingColorRowDescriptionTraits::GetIconSignature(filter.DrawOverLabel, cl);
+    else
+      return QVariant(filter.CoverageMode);
+  }
+};
+
+/**
+  Use template specialization to generate default traits based on the model
+  */
+template <class TAtomic, class TDesc>
+class DefaultComboBoxRowTraits
+{
+};
+
+template <>
+class DefaultComboBoxRowTraits<LabelType, ColorLabel>
+    : public TextAndIconComboBoxRowTraits<LabelType, ColorLabel, DrawingColorRowDescriptionTraits>
+{
+};
+
+template <>
+class DefaultComboBoxRowTraits<DrawOverFilter, ColorLabel>
+    : public TextAndIconComboBoxRowTraits<DrawOverFilter, ColorLabel, DrawOverFilterRowDescriptionTraits>
+{
+};
+
+template<class TAtomic>
+class DefaultComboBoxRowTraits<TAtomic, std::string>
+    : public TextAndIconComboBoxRowTraits<TAtomic, std::string, StringRowDescriptionTraits<TAtomic> >
+{
+};
+
+
+// Define the defaults
+template <class TDomain>
+class DefaultWidgetDomainTraits<TDomain, QComboBox>
+    : public ItemSetWidgetDomainTraits<
+        TDomain, QComboBox,
+        DefaultComboBoxRowTraits<typename TDomain::ValueType,
+                                 typename TDomain::DescriptorType> >
+{
+};
+
+// Define the behavior with trivial domain. In this case, we assume that the combo
+// box was set up in the GUI to have userdata matching the items in the model
+template <>
+class DefaultWidgetDomainTraits<TrivialDomain, QComboBox>
+    : public WidgetDomainTraitsBase<TrivialDomain, QComboBox *>
+{
+public:
+  virtual void SetDomain(QComboBox *w, const TrivialDomain &domain) {}
+  virtual TrivialDomain GetDomain(QComboBox *w) { return TrivialDomain(); }
+};
+
+
+#endif // QTCOMBOBOXCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtDoubleSliderWithEditorCoupling.h b/GUI/Qt/Coupling/QtDoubleSliderWithEditorCoupling.h
new file mode 100644
index 0000000..c101e8d
--- /dev/null
+++ b/GUI/Qt/Coupling/QtDoubleSliderWithEditorCoupling.h
@@ -0,0 +1,84 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTDOUBLESLIDERWITHEDITORCOUPLING_H
+#define QTDOUBLESLIDERWITHEDITORCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+#include <QDoubleSliderWithEditor.h>
+
+/**
+  Default traits for the Qt Double Spin Box
+  */
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QDoubleSliderWithEditor>
+    : public WidgetValueTraitsBase<TAtomic, QDoubleSliderWithEditor *>
+{
+public:
+  const char *GetSignal()
+  {
+    return SIGNAL(valueChanged(double));
+  }
+
+  TAtomic GetValue(QDoubleSliderWithEditor *w)
+  {
+    return static_cast<TAtomic>(w->value());
+  }
+
+  void SetValue(QDoubleSliderWithEditor *w, const TAtomic &value)
+  {
+    w->setValue(static_cast<double>(value));
+  }
+
+
+  void SetValueToNull(QDoubleSliderWithEditor *w)
+  {
+    w->setValueToNull();
+  }
+};
+
+template <class TAtomic>
+class DefaultWidgetDomainTraits<NumericValueRange<TAtomic>, QDoubleSliderWithEditor>
+    : public WidgetDomainTraitsBase<NumericValueRange<TAtomic>, QDoubleSliderWithEditor *>
+{
+public:
+  void SetDomain(QDoubleSliderWithEditor *w, const NumericValueRange<TAtomic> &range)
+  {
+    w->setMinimum(range.Minimum);
+    w->setMaximum(range.Maximum);
+    w->setSingleStep(range.StepSize);
+  }
+
+  NumericValueRange<TAtomic> GetDomain(QDoubleSliderWithEditor *w)
+  {
+    return NumericValueRange<TAtomic>(
+          static_cast<TAtomic>(w->minimum()),
+          static_cast<TAtomic>(w->maximum()),
+          static_cast<TAtomic>(w->singleStep()));
+  }
+};
+
+#endif // QTDOUBLESLIDERWITHEDITORCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtDoubleSpinBoxCoupling.h b/GUI/Qt/Coupling/QtDoubleSpinBoxCoupling.h
new file mode 100644
index 0000000..8126247
--- /dev/null
+++ b/GUI/Qt/Coupling/QtDoubleSpinBoxCoupling.h
@@ -0,0 +1,98 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTDOUBLESPINBOXCOUPLING_H
+#define QTDOUBLESPINBOXCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+#include <QDoubleSpinBox>
+
+/**
+  Default traits for the Qt Double Spin Box
+  */
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QDoubleSpinBox>
+    : public WidgetValueTraitsBase<TAtomic, QDoubleSpinBox *>
+{
+public:
+  const char *GetSignal()
+  {
+    return SIGNAL(valueChanged(double));
+  }
+
+  TAtomic GetValue(QDoubleSpinBox *w)
+  {
+    return static_cast<TAtomic>(w->value());
+  }
+
+  void SetValue(QDoubleSpinBox *w, const TAtomic &value)
+  {
+    w->setSpecialValueText("");
+    w->setValue(static_cast<double>(value));
+  }
+
+
+  void SetValueToNull(QDoubleSpinBox *w)
+  {
+    w->setValue(w->minimum());
+    w->setSpecialValueText(" ");
+  }
+};
+
+template <class TAtomic>
+class DefaultWidgetDomainTraits<NumericValueRange<TAtomic>, QDoubleSpinBox>
+    : public WidgetDomainTraitsBase<NumericValueRange<TAtomic>, QDoubleSpinBox *>
+{
+public:
+  void SetDomain(QDoubleSpinBox *w, const NumericValueRange<TAtomic> &range)
+  {
+    w->setMinimum(range.Minimum);
+    w->setMaximum(range.Maximum);
+    w->setSingleStep(range.StepSize);
+
+    // Make sure the precision is smaller than the step size. This is a
+    // temporary fix. A better solution is to have the model provide the
+    // precision for the widget.
+    if(range.StepSize > 0)
+      {
+      double logstep = std::log10((double)range.StepSize);
+      int prec = std::max((int) (1 - floor(logstep)), 0);
+      w->setDecimals(prec);
+      }
+    else
+      w->setDecimals(0);
+  }
+
+  NumericValueRange<TAtomic> GetDomain(QDoubleSpinBox *w)
+  {
+    return NumericValueRange<TAtomic>(
+          static_cast<TAtomic>(w->minimum()),
+          static_cast<TAtomic>(w->maximum()),
+          static_cast<TAtomic>(w->singleStep()));
+  }
+};
+
+#endif // QTDOUBLESPINBOXCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtLabelCoupling.h b/GUI/Qt/Coupling/QtLabelCoupling.h
new file mode 100644
index 0000000..ba8e30b
--- /dev/null
+++ b/GUI/Qt/Coupling/QtLabelCoupling.h
@@ -0,0 +1,43 @@
+#ifndef QTLABELCOUPLING_H
+#define QTLABELCOUPLING_H
+
+#include "QtWidgetCoupling.h"
+#include "SNAPQtCommon.h"
+#include <iostream>
+#include <iomanip>
+#include <QLabel>
+
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QLabel>
+    : public WidgetValueTraitsBase<TAtomic, QLabel *>
+{
+public:
+
+  virtual TAtomic GetValue(QLabel *w)
+  {
+    std::istringstream iss(to_utf8(w->text()));
+    TAtomic value;
+    iss >> value;
+    return value;
+  }
+
+  virtual void SetValue(QLabel *w, const TAtomic &value)
+  {
+    std::ostringstream oss;
+    oss << value;
+    w->setText(from_utf8(oss.str()));
+  }
+
+  virtual void SetValueToNull(QLabel *w)
+  {
+    w->setText("");
+  }
+
+  virtual const char *GetSignal()
+  {
+    return NULL;
+  }
+};
+
+
+#endif // QTLABELCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtLineEditCoupling.h b/GUI/Qt/Coupling/QtLineEditCoupling.h
new file mode 100644
index 0000000..fea65a2
--- /dev/null
+++ b/GUI/Qt/Coupling/QtLineEditCoupling.h
@@ -0,0 +1,122 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTLINEEDITCOUPLING_H
+#define QTLINEEDITCOUPLING_H
+
+#include "QtWidgetCoupling.h"
+#include "SNAPQtCommon.h"
+#include <iostream>
+#include <iomanip>
+#include <QLineEdit>
+
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QLineEdit>
+    : public WidgetValueTraitsBase<TAtomic, QLineEdit *>
+{
+public:
+
+  virtual TAtomic GetValue(QLineEdit *w)
+  {
+    std::istringstream iss(to_utf8(w->text()));
+    TAtomic value;
+    iss >> value;
+    return value;
+  }
+
+  virtual void SetValue(QLineEdit *w, const TAtomic &value)
+  {
+    std::ostringstream oss;
+    oss << value;
+    w->setText(from_utf8(oss.str()));
+  }
+
+  virtual void SetValueToNull(QLineEdit *w)
+  {
+    w->setText("");
+  }
+
+  virtual const char *GetSignal()
+  {
+    return SIGNAL(textChanged(const QString &));
+  }
+};
+
+template<>
+class DefaultWidgetValueTraits<std::string, QLineEdit>
+    : public WidgetValueTraitsBase<std::string, QLineEdit *>
+{
+public:
+
+  virtual std::string GetValue(QLineEdit *w)
+  {
+    return to_utf8(w->text());
+  }
+
+  virtual void SetValue(QLineEdit *w, const std::string &value)
+  {
+    w->setText(from_utf8(value));
+  }
+
+  virtual void SetValueToNull(QLineEdit *w)
+  {
+    w->setText("");
+  }
+
+  virtual const char *GetSignal()
+  {
+    return SIGNAL(textChanged(const QString &));
+  }
+};
+
+
+
+/** Base class for traits that map between a numeric value and a text editor */
+template <class TAtomic, class QLineEdit>
+class FixedPrecisionRealToTextFieldWidgetTraits
+    : public DefaultWidgetValueTraits<TAtomic, QLineEdit>
+{
+public:
+
+  FixedPrecisionRealToTextFieldWidgetTraits(int precision)
+    : m_Precision(precision) {}
+
+  irisGetSetMacro(Precision, int)
+
+  virtual void SetValue(QLineEdit *w, const TAtomic &value)
+  {
+    std::ostringstream oss;
+    oss << std::setprecision(m_Precision) << value;
+    w->setText(oss.str().c_str());
+  }
+
+protected:
+
+  int m_Precision;
+};
+
+
+#endif // QTLINEEDITCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtListWidgetCoupling.h b/GUI/Qt/Coupling/QtListWidgetCoupling.h
new file mode 100644
index 0000000..0654551
--- /dev/null
+++ b/GUI/Qt/Coupling/QtListWidgetCoupling.h
@@ -0,0 +1,141 @@
+  #ifndef QTLISTWIDGETCOUPLING_H
+  #define QTLISTWIDGETCOUPLING_H
+
+  #include <QtWidgetCoupling.h>
+  #include "SNAPQtCommon.h"
+  #include <ColorLabel.h>
+  #include <QListWidget>
+
+
+  /**
+    Default traits for mapping a numeric value (or any sort of key, actually)
+    to a row in a list box
+    */
+  template <class TAtomic>
+  class DefaultWidgetValueTraits<TAtomic, QListWidget>
+      : public WidgetValueTraitsBase<TAtomic, QListWidget *>
+  {
+  public:
+    // Get the Qt signal that the widget fires when its value has changed. The
+    // value here is the selected item in the combo box.
+    const char *GetSignal()
+    {
+      return SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *));
+    }
+
+    TAtomic GetValue(QListWidget *w)
+    {
+      // Get the UserData associated with the current item
+      return w->currentItem()->data(Qt::UserRole).value<TAtomic>();
+    }
+
+    void SetValue(QListWidget *w, const TAtomic &value)
+    {
+      // Unset the current index
+      int row = -1;
+
+      // We have to actually find the item
+      for(int i = 0; i < w->count(); i++)
+        {
+        QModelIndex idx = w->model()->index(i, 0);
+        if(w->model()->data(idx, Qt::UserRole).value<TAtomic>() == value)
+          {
+          row = i;
+          break;
+          }
+        }
+
+      // Have we found it?
+      w->setCurrentRow(row);
+    }
+
+    void SetValueToNull(QListWidget *w)
+    {
+      w->setCurrentRow(-1);
+    }
+  };
+
+
+  template <class TAtomic>
+  class ListWidgetRowTraitsBase
+  {
+  public:
+    static void removeAll(QListWidget *w)
+    {
+      w->clear();
+    }
+
+    static int getNumberOfRows(QListWidget *w)
+    {
+      return w->count();
+    }
+
+    static TAtomic getValueInRow(QListWidget *w, int i)
+    {
+      return w->item(i)->data(Qt::UserRole).value<TAtomic>();
+    }
+  };
+
+  /**
+    Row traits for mapping a color label into a list widget entry
+    */
+  class ColorLabelToListWidgetTraits
+      : public ListWidgetRowTraitsBase<LabelType>
+  {
+  public:
+
+    static void appendRow(QListWidget *w, LabelType label, const ColorLabel &cl)
+    {
+      // The description
+      QString text(cl.GetLabel());
+
+      // The color
+      QColor fill(cl.GetRGB(0), cl.GetRGB(1), cl.GetRGB(2));
+
+      // Icon based on the color
+      QIcon ic = CreateColorBoxIcon(16, 16, fill);
+
+      // Create item and set its properties
+      QListWidgetItem *item = new QListWidgetItem(ic, text, w);
+      item->setData(Qt::UserRole, label);
+      item->setData(Qt::UserRole + 1, fill);
+      item->setData(Qt::EditRole, text);
+      // item->setFlags(item->flags() | Qt::ItemIsEditable);
+    }
+
+    static void updateRowDescription(QListWidget *w, int index, const ColorLabel &cl)
+    {
+      // Get the current item
+      QListWidgetItem *item = w->item(index);
+
+      // Get the properies and compare them to the color label
+      QColor currentFill = item->data(Qt::UserRole+1).value<QColor>();
+      QColor newFill(cl.GetRGB(0), cl.GetRGB(1), cl.GetRGB(2));
+
+      if(currentFill != newFill)
+        {
+        QIcon ic = CreateColorBoxIcon(16, 16, newFill);
+        item->setIcon(ic);
+        item->setData(Qt::UserRole + 1, newFill);
+        }
+
+      QString currentText = item->text();
+      QString newText(cl.GetLabel());
+
+      if(currentText != newText)
+        {
+        item->setText(newText);
+        item->setData(Qt::EditRole, newText);
+        }
+    }
+  };
+
+  // Define the defaults
+  template <class TDomain>
+  class DefaultWidgetDomainTraits<TDomain, QListWidget>
+      : public ItemSetWidgetDomainTraits<TDomain, QListWidget, ColorLabelToListWidgetTraits>
+  {
+  };
+
+
+  #endif // QTLISTWIDGETCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtPagedWidgetCoupling.h b/GUI/Qt/Coupling/QtPagedWidgetCoupling.h
new file mode 100644
index 0000000..7d9e01c
--- /dev/null
+++ b/GUI/Qt/Coupling/QtPagedWidgetCoupling.h
@@ -0,0 +1,106 @@
+#ifndef QTPAGEDWIDGETCOUPLING_H
+#define QTPAGEDWIDGETCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+#include <QTabWidget>
+#include <QStackedWidget>
+#include <map>
+
+/**
+ * Coupling for widgets such as Stack, Tab, etc. Each value of the
+ * coupled variable corresponds to a page in the widget
+ */
+
+template <class TAtomic, class TPagedWidget>
+struct PagedWidgetValueTraits :
+    public WidgetValueTraitsBase<TAtomic, TPagedWidget *>
+{
+public:
+  // There needs to be a map from the values of the atomic variable to
+  // the pages in the widget
+  typedef std::map<TAtomic, QWidget *> PageMap;
+  typedef typename PageMap::iterator PageIterator;
+
+  PagedWidgetValueTraits(PageMap pm) : m_PageMap(pm) {}
+
+  // The signal fired when the active page is changed
+  virtual const char *GetSignal()
+  {
+    return SIGNAL(currentChanged(int));
+  }
+
+
+  TAtomic GetValue(TPagedWidget *w)
+  {
+    // Figure out which button is checked
+    for(PageIterator it = m_PageMap.begin(); it != m_PageMap.end(); ++it)
+      {
+      if(it->second == w->currentWidget())
+        return it->first;
+      }
+
+    // This is ambiguous...
+    return static_cast<TAtomic>(0);
+  }
+
+  void SetValue(TPagedWidget *w, const TAtomic &value)
+  {
+    // Set all the buttons
+    QWidget *page = m_PageMap[value];
+    w->setCurrentWidget(page);
+  }
+
+  void SetValueToNull(TPagedWidget *w)
+  {
+    // Set all the buttons
+    w->setCurrentIndex(-1);
+  }
+
+protected:
+
+  PageMap m_PageMap;
+};
+
+template <class TDomain, class TPagedWidget>
+class DefaultPagedWidgetDomainTraits
+    : public WidgetDomainTraitsBase<TDomain, TPagedWidget *>
+{
+public:
+  // With a trivial domain, do nothing!
+  virtual void SetDomain(TPagedWidget *w, const TDomain &) {}
+
+  virtual TDomain GetDomain(TPagedWidget *w)
+    { return TDomain(); }
+
+};
+
+template <class TDomain>
+class DefaultWidgetDomainTraits<TDomain, QStackedWidget>
+    : public DefaultPagedWidgetDomainTraits<TDomain, QStackedWidget>
+{ };
+
+template <class TDomain>
+class DefaultWidgetDomainTraits<TDomain, QTabWidget>
+    : public DefaultPagedWidgetDomainTraits<TDomain, QTabWidget>
+{ };
+
+
+template <class TModel, class TPageWidget>
+void makePagedWidgetCoupling(
+    TPageWidget *w,
+    TModel *model,
+    std::map<typename TModel::ValueType, QWidget *> pageMap,
+    QtCouplingOptions opts = QtCouplingOptions())
+{
+  typedef typename TModel::ValueType ValueType;
+  typedef PagedWidgetValueTraits<ValueType, TPageWidget> WidgetValueTraits;
+
+  WidgetValueTraits traits(pageMap);
+
+  makeCoupling<TModel, TPageWidget, WidgetValueTraits>(w, model, traits, opts);
+}
+
+
+
+
+#endif // QTPAGEDWIDGETCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtRadioButtonCoupling.h b/GUI/Qt/Coupling/QtRadioButtonCoupling.h
new file mode 100644
index 0000000..6062d58
--- /dev/null
+++ b/GUI/Qt/Coupling/QtRadioButtonCoupling.h
@@ -0,0 +1,73 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTRADIOBUTTONCOUPLING_H
+#define QTRADIOBUTTONCOUPLING_H
+
+#include <QtCheckableWidgetGroupCoupling.h>
+#include <QRadioButton>
+#include <map>
+
+/**
+  Create a coupling between a widget containing a set of radio buttons
+  and a set of values of type TAtomic (true/false, enum, integer, etc).
+  The mapping of values to button widgets is provided in the third parameter.
+  */
+template <class TAtomic>
+void makeRadioGroupCoupling(
+    QWidget *parentWidget,
+    std::map<TAtomic, QAbstractButton *> buttonMap,
+    AbstractPropertyModel<TAtomic> *model)
+{
+  makeCheckableWidgetGroupCoupling(parentWidget, buttonMap, model);
+}
+
+
+/**
+  Create a coupling between a widget containing a set of radio buttons
+  and an enum. The values of the enum must be 0,1,2,... The order of the
+  radio button widgets in the parent widget *w should match the order of
+  the enum entries. This method only fits specific situations, in other
+  cases see the more general version above
+  */
+template <class TAtomic>
+void makeRadioGroupCoupling(
+    QWidget *w, AbstractPropertyModel<TAtomic> *model)
+{
+  const QObjectList &kids = w->children();
+  std::map<TAtomic, QAbstractButton *> buttonMap;
+  int iwidget = 0;
+  for(QObjectList::const_iterator it = kids.begin(); it != kids.end(); ++it)
+    {
+    QAbstractButton *qab = dynamic_cast<QAbstractButton *>(*it);
+    if(qab)
+      buttonMap[static_cast<TAtomic>(iwidget++)] = qab;
+    }
+  makeCheckableWidgetGroupCoupling(w, buttonMap, model);
+}
+
+
+#endif // QTRADIOBUTTONCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtScrollbarCoupling.h b/GUI/Qt/Coupling/QtScrollbarCoupling.h
new file mode 100644
index 0000000..8bb8132
--- /dev/null
+++ b/GUI/Qt/Coupling/QtScrollbarCoupling.h
@@ -0,0 +1,74 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+#ifndef QTSCROLLBARCOUPLING_H
+#define QTSCROLLBARCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+#include <QScrollBar>
+
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QScrollBar>
+    : public WidgetValueTraitsBase<TAtomic, QScrollBar *>
+{
+public:
+  const char *GetSignal()
+  {
+    return SIGNAL(valueChanged(int));
+  }
+
+  TAtomic GetValue(QScrollBar *w)
+  {
+    return static_cast<TAtomic>(w->value());
+  }
+
+  void SetValue(QScrollBar *w, const TAtomic &value)
+  {
+    w->setValue(static_cast<int>(value));
+  }
+};
+
+template <class TAtomic>
+class DefaultWidgetDomainTraits<NumericValueRange<TAtomic>, QScrollBar>
+    : public WidgetDomainTraitsBase<NumericValueRange<TAtomic>, QScrollBar *>
+{
+public:
+  void SetDomain(QScrollBar *w, const NumericValueRange<TAtomic> &range)
+  {
+    w->setMinimum(range.Minimum);
+    w->setMaximum(range.Maximum);
+    w->setSingleStep(range.StepSize);
+  }
+
+  NumericValueRange<TAtomic> GetDomain(QScrollBar *w)
+  {
+    return NumericValueRange<TAtomic>(
+          static_cast<TAtomic>(w->minimum()),
+          static_cast<TAtomic>(w->maximum()),
+          static_cast<TAtomic>(w->singleStep()));
+  }
+};
+
+#endif // QTSCROLLBARCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtSliderCoupling.h b/GUI/Qt/Coupling/QtSliderCoupling.h
new file mode 100644
index 0000000..5b909db
--- /dev/null
+++ b/GUI/Qt/Coupling/QtSliderCoupling.h
@@ -0,0 +1,120 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTSLIDERCOUPLING_H
+#define QTSLIDERCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+#include <QSlider>
+#include <QDoubleSlider.h>
+
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QSlider>
+    : public WidgetValueTraitsBase<TAtomic, QSlider *>
+{
+public:
+  const char *GetSignal()
+  {
+    return SIGNAL(valueChanged(int));
+  }
+
+  TAtomic GetValue(QSlider *w)
+  {
+    return static_cast<TAtomic>(w->value());
+  }
+
+  void SetValue(QSlider *w, const TAtomic &value)
+  {
+    w->setValue(static_cast<int>(value));
+  }
+};
+
+template <class TAtomic>
+class DefaultWidgetDomainTraits<NumericValueRange<TAtomic>, QSlider>
+    : public WidgetDomainTraitsBase<NumericValueRange<TAtomic>, QSlider *>
+{
+public:
+  void SetDomain(QSlider *w, const NumericValueRange<TAtomic> &range)
+  {
+    w->setMinimum(range.Minimum);
+    w->setMaximum(range.Maximum);
+    w->setSingleStep(range.StepSize);
+  }
+
+  NumericValueRange<TAtomic> GetDomain(QSlider *w)
+  {
+    return NumericValueRange<TAtomic>(
+          static_cast<TAtomic>(w->minimum()),
+          static_cast<TAtomic>(w->maximum()),
+          static_cast<TAtomic>(w->singleStep()));
+  }
+};
+
+
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QDoubleSlider>
+    : public WidgetValueTraitsBase<TAtomic, QDoubleSlider *>
+{
+public:
+  const char *GetSignal()
+  {
+    return SIGNAL(valueChanged(int));
+  }
+
+  TAtomic GetValue(QDoubleSlider *w)
+  {
+    return static_cast<TAtomic>(w->doubleValue());
+  }
+
+  void SetValue(QDoubleSlider *w, const TAtomic &value)
+  {
+    w->setDoubleValue(static_cast<double>(value));
+  }
+};
+
+template <class TAtomic>
+class DefaultWidgetDomainTraits<NumericValueRange<TAtomic>, QDoubleSlider>
+    : public WidgetDomainTraitsBase<NumericValueRange<TAtomic>, QDoubleSlider *>
+{
+public:
+  void SetDomain(QDoubleSlider *w, const NumericValueRange<TAtomic> &range)
+  {
+    w->setDoubleMinimum(range.Minimum);
+    w->setDoubleMaximum(range.Maximum);
+    w->setDoubleSingleStep(range.StepSize);
+  }
+
+  NumericValueRange<TAtomic> GetDomain(QDoubleSlider *w)
+  {
+    return NumericValueRange<TAtomic>(
+          static_cast<TAtomic>(w->doubleMinimum()),
+          static_cast<TAtomic>(w->doubleMaximum()),
+          static_cast<TAtomic>(w->doubleSingleStep()));
+  }
+};
+
+
+#endif // QTSLIDERCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtSpinBoxCoupling.h b/GUI/Qt/Coupling/QtSpinBoxCoupling.h
new file mode 100644
index 0000000..1183db1
--- /dev/null
+++ b/GUI/Qt/Coupling/QtSpinBoxCoupling.h
@@ -0,0 +1,88 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTSPINBOXCOUPLING_H
+#define QTSPINBOXCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+#include <QSpinBox>
+
+/**
+  Default traits for the Qt Spin Box, coupled with a numeric value range
+  */
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QSpinBox>
+    : public WidgetValueTraitsBase<TAtomic, QSpinBox *>
+{
+public:
+  const char *GetSignal()
+  {
+    return SIGNAL(valueChanged(int));
+  }
+
+  TAtomic GetValue(QSpinBox *w)
+  {
+    return static_cast<TAtomic>(w->value());
+  }
+
+  void SetValue(QSpinBox *w, const TAtomic &value)
+  {
+    w->setSpecialValueText("");
+    w->setValue(static_cast<int>(value));
+  }
+
+
+  void SetValueToNull(QSpinBox *w)
+  {
+    w->setValue(w->minimum());
+    w->setSpecialValueText(" ");
+  }
+
+};
+
+template <class TAtomic>
+class DefaultWidgetDomainTraits<NumericValueRange<TAtomic>, QSpinBox>
+    : public WidgetDomainTraitsBase<NumericValueRange<TAtomic>, QSpinBox *>
+{
+public:
+
+  void SetDomain(QSpinBox *w, const NumericValueRange<TAtomic> &range)
+  {
+    w->setMinimum(range.Minimum);
+    w->setMaximum(range.Maximum);
+    w->setSingleStep(range.StepSize);
+  }
+
+  NumericValueRange<TAtomic> GetDomain(QSpinBox *w)
+  {
+    return NumericValueRange<TAtomic>(
+          static_cast<TAtomic>(w->minimum()),
+          static_cast<TAtomic>(w->maximum()),
+          static_cast<TAtomic>(w->singleStep()));
+  }
+};
+
+#endif // QTSPINBOXCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtTableWidgetCoupling.cxx b/GUI/Qt/Coupling/QtTableWidgetCoupling.cxx
new file mode 100644
index 0000000..b3f47bf
--- /dev/null
+++ b/GUI/Qt/Coupling/QtTableWidgetCoupling.cxx
@@ -0,0 +1,5 @@
+#include "QtTableWidgetCoupling.h"
+
+QtTableWidgetCoupling::QtTableWidgetCoupling()
+{
+}
diff --git a/GUI/Qt/Coupling/QtTableWidgetCoupling.h b/GUI/Qt/Coupling/QtTableWidgetCoupling.h
new file mode 100644
index 0000000..346f5ef
--- /dev/null
+++ b/GUI/Qt/Coupling/QtTableWidgetCoupling.h
@@ -0,0 +1,299 @@
+#ifndef QTTABLEWIDGETCOUPLING_H
+#define QTTABLEWIDGETCOUPLING_H
+
+#ifndef QTLISTWIDGETCOUPLING_H
+#define QTLISTWIDGETCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+#include "SNAPQtCommon.h"
+#include <ColorLabel.h>
+#include <QTableWidget>
+
+
+/**
+  Default traits for mapping a numeric value (or any sort of key, actually)
+  to a row in a table. This is similar to a list box, but with multiple
+  columns. TODO: unify this with ListWidget traits by using a Qt
+  AbstractItemModel
+
+  This coupling maps an integer value to a row index in a table. The value
+  in the table are specified by the domain of the associated model.
+  */
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QTableWidget>
+    : public WidgetValueTraitsBase<TAtomic, QTableWidget *>
+{
+public:
+  // Get the Qt signal that the widget fires when its value has changed. The
+  // value here is the selected item in the combo box.
+  const char *GetSignal()
+  {
+    return SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *));
+  }
+
+  TAtomic GetValue(QTableWidget *w)
+  {
+    // Get the UserData associated with the current item
+    TAtomic val = w->currentItem()->data(Qt::UserRole).value<TAtomic>();
+    return val;
+  }
+
+  void SetValue(QTableWidget *w, const TAtomic &value)
+  {
+    // We have to actually find the row
+    for(int i = 0; i < w->rowCount(); i++)
+      {
+      QTableWidgetItem *item = w->item(i, 0);
+      TAtomic stored_value = item->data(Qt::UserRole).value<TAtomic>();
+      if(stored_value == value)
+        {
+        w->setCurrentItem(item);
+        return;
+        }
+      }
+
+    // Have we found it?
+    w->setCurrentItem(NULL);
+  }
+
+  void SetValueToNull(QTableWidget *w)
+  {
+    // Have we found it?
+    w->setCurrentItem(NULL);
+  }
+};
+
+/** Default traits for mapping a matrix of values (int, double) to a table */
+template <class TElement>
+class DefaultWidgetValueTraits< vnl_matrix<TElement>, QTableWidget>
+    : public WidgetValueTraitsBase< vnl_matrix<TElement>, QTableWidget* >
+{
+public:
+  typedef vnl_matrix<TElement> TMatrix;
+
+  const char *GetSignal()
+  {
+    return SIGNAL(cellChanged(int, int));
+  }
+
+  TMatrix GetValue(QTableWidget *w)
+  {
+    // Extract the values from all cells in the widget
+    TMatrix mat(w->rowCount(), w->columnCount());
+    for(int r = 0; r < w->rowCount(); r++)
+      {
+      for(int c = 0; c < w->rowCount(); c++)
+        {
+        TElement val = w->item(r, c)->data(Qt::DisplayRole).value<TElement>();
+        mat(r, c) = val;
+        }
+      }
+    return mat;
+  }
+
+  void SetValue(QTableWidget *w, const TMatrix &mat)
+  {
+    // Adjust the sizes
+    if(w->rowCount() != mat.rows() || w->columnCount() != mat.columns())
+      {
+      w->setRowCount(mat.rows());
+      w->setColumnCount(mat.columns());
+      }
+
+    // Assign the values
+    for(int r = 0; r < w->rowCount(); r++)
+      {
+      for(int c = 0; c < w->rowCount(); c++)
+        {
+        TElement newval = mat(r,c);
+        QTableWidgetItem *item = w->item(r, c);
+        if(!item)
+          {
+          item = new QTableWidgetItem();
+          w->setItem(r, c, item);
+          item->setData(Qt::DisplayRole, QVariant(newval));
+          }
+        else
+          {
+          QVariant oldval = item->data(Qt::DisplayRole);
+          if(oldval.isNull() || oldval.value<TElement>() != newval)
+            {
+            item->setData(Qt::DisplayRole, QVariant(newval));
+            }
+          }
+        }
+      }
+  }
+
+  void SetValueToNull(QTableWidget *w)
+  {
+    // Have we found it?
+    w->clearContents();
+  }
+
+};
+
+
+template <class TAtomic, class TDesc, class TItemDesriptionTraits>
+class TextAndIconTableWidgetRowTraits
+{
+public:
+  static void removeAll(QTableWidget *w)
+  {
+    while(w->rowCount())
+      w->removeRow(0);
+  }
+
+  static int getNumberOfRows(QTableWidget *w)
+  {
+    return w->rowCount();
+  }
+
+  static TAtomic getValueInRow(QTableWidget *w, int i)
+  {
+    TAtomic value = w->item(i,0)->data(Qt::UserRole).value<TAtomic>();
+    return value;
+  }
+
+  static void appendRow(QTableWidget *w, TAtomic value, const TDesc &desc)
+  {
+    // Insert a row
+    int row = w->rowCount();
+    w->insertRow(row);
+
+    // Fill all the columns
+    for(int col = 0; col < w->columnCount(); col++)
+      {
+      // The description
+      QString text = TItemDesriptionTraits::GetText(value, desc, col);
+
+      // The icon
+      QIcon icon = TItemDesriptionTraits::GetIcon(value, desc, col);
+
+      // The icon signature - a value that can be used to check if the icon has changed
+      QVariant iconSig = TItemDesriptionTraits::GetIconSignature(value, desc, col);
+
+      // Set the item properties
+      QTableWidgetItem *item = new QTableWidgetItem();
+      item->setText(text);
+      item->setToolTip(text);
+      item->setIcon(icon);
+      item->setData(Qt::UserRole + 1, iconSig);
+      w->setItem(row, col, item);
+      }
+
+    // Set the item for the row
+    w->item(row, 0)->setData(Qt::UserRole, QVariant::fromValue(value));
+  }
+
+  static void updateRowDescription(QTableWidget *w, int row, const TDesc &desc)
+  {
+    // The current value
+    TAtomic value = w->item(row, 0)->data(Qt::UserRole).value<TAtomic>();
+
+    // Get the properies and compare them to the color label
+    for(int col = 0; col < w->columnCount(); col++)
+      {
+      QTableWidgetItem *item = w->item(row, col);
+
+      QVariant currentIconSig = item->data(Qt::UserRole + 1);
+      QVariant newIconSig = TItemDesriptionTraits::GetIconSignature(value, desc, col);
+
+      if(currentIconSig != newIconSig)
+        {
+        QIcon ic = TItemDesriptionTraits::GetIcon(value, desc, col);
+        item->setIcon(ic);
+        item->setData(Qt::UserRole + 1, newIconSig);
+        }
+
+      QString currentText = item->text();
+      QString newText = TItemDesriptionTraits::GetText(value, desc, col);
+
+      if(currentText != newText)
+        {
+        item->setText(newText);
+        item->setToolTip(newText);
+        }
+      }
+  }
+};
+
+
+/**
+ * Declare ItemSetWidgetDomainTraits to be the default domain traits for the
+ * QTableWidget, which makes it easy to use with makeMultiRowCoupling
+ */
+template <class TItemDomain, class TRowTraits>
+class DefaultMultiRowWidgetDomainTraits<TItemDomain, QTableWidget, TRowTraits>
+    : public ItemSetWidgetDomainTraits<TItemDomain, QTableWidget, TRowTraits>
+{};
+
+
+
+/**
+  Row traits for mapping a color label into a list widget entry
+
+class ColorLabelToListWidgetTraits
+    : public ListWidgetRowTraitsBase<LabelType>
+{
+public:
+
+  static void appendRow(QTableWidget *w, LabelType label, const ColorLabel &cl)
+  {
+    // The description
+    QString text(cl.GetLabel());
+
+    // The color
+    QColor fill(cl.GetRGB(0), cl.GetRGB(1), cl.GetRGB(2));
+
+    // Icon based on the color
+    QIcon ic = CreateColorBoxIcon(16, 16, fill);
+
+    // Create item and set its properties
+    QTableWidgetItem *item = new QTableWidgetItem(ic, text, w);
+    item->setData(Qt::UserRole, label);
+    item->setData(Qt::UserRole + 1, fill);
+    item->setData(Qt::EditRole, text);
+    // item->setFlags(item->flags() | Qt::ItemIsEditable);
+  }
+
+  static void updateRowDescription(QTableWidget *w, int index, const ColorLabel &cl)
+  {
+    // Get the current item
+    QTableWidgetItem *item = w->item(index);
+
+    // Get the properies and compare them to the color label
+    QColor currentFill = item->data(Qt::UserRole+1).value<QColor>();
+    QColor newFill(cl.GetRGB(0), cl.GetRGB(1), cl.GetRGB(2));
+
+    if(currentFill != newFill)
+      {
+      QIcon ic = CreateColorBoxIcon(16, 16, newFill);
+      item->setIcon(ic);
+      item->setData(Qt::UserRole + 1, newFill);
+      }
+
+    QString currentText = item->text();
+    QString newText(cl.GetLabel());
+
+    if(currentText != newText)
+      {
+      item->setText(newText);
+      item->setData(Qt::EditRole, newText);
+      }
+  }
+};
+
+// Define the defaults
+template <class TDomain>
+class DefaultWidgetDomainTraits<TDomain, QTableWidget>
+    : public ItemSetWidgetDomainTraits<TDomain, QTableWidget, ColorLabelToListWidgetTraits>
+{
+};
+
+*/
+
+#endif // QTLISTWIDGETCOUPLING_H
+
+
+#endif // QTTABLEWIDGETCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtToolbarCoupling.h b/GUI/Qt/Coupling/QtToolbarCoupling.h
new file mode 100644
index 0000000..85e096f
--- /dev/null
+++ b/GUI/Qt/Coupling/QtToolbarCoupling.h
@@ -0,0 +1,146 @@
+#ifndef QTTOOLBARCOUPLING_H
+#define QTTOOLBARCOUPLING_H
+
+#include "QtWidgetCoupling.h"
+#include "QToolBar"
+#include "QAbstractButton"
+#include <ColorLabel.h>
+#include <SNAPQtCommon.h>
+
+
+/**
+ * This class defines a coupling between a QToolbar in which there are a
+ * number of mutually exclusive actions, which are assigned a value of the
+ * TAtomic type using the 'data' parameter (using QAction::setData).
+ */
+template <class TAtomic>
+class DefaultWidgetValueTraits<TAtomic, QToolBar>
+    : public WidgetValueTraitsBase<TAtomic, QToolBar *>
+{
+public:
+
+  // Luckily a QToolBar provides a signal for us to use
+  virtual const char *GetSignal()
+  {
+    return SIGNAL(actionTriggered(QAction *));
+  }
+
+  // We must trigger the action that corresponds to the value. For this
+  // to work, we must set the user data of the action to the value
+  virtual void SetValue(QToolBar *w, const TAtomic &value)
+  {
+    foreach(QAction *action, w->actions())
+      {
+      if(value == action->data().value<TAtomic>())
+        action->setChecked(true);
+      else
+        action->setChecked(false);
+      }
+  }
+
+  // Get the value - i.e., the action that is currently checked
+  virtual TAtomic GetValue(QToolBar *w)
+  {
+    foreach(QAction *action, w->actions())
+      if(action->isChecked())
+        return action->data().value<TAtomic>();
+    return 0;
+  }
+
+  // Setting value to NULL means unchecking all actions
+  virtual void SetValueToNull(QToolBar *w)
+  {
+    foreach(QAction *action, w->actions())
+      {
+      action->setChecked(false);
+      }
+  }
+};
+
+
+
+/**
+ * This class populates an action group to match a domain that is a set of
+ * items. The actions in the action group are dynamically allocated
+ */
+/*
+template <class TItemDomain, class TRowTraits>
+class DefaultMultiRowWidgetDomainTraits<TItemDomain, QToolBar, TRowTraits> :
+    public WidgetDomainTraitsBase<TItemDomain, QToolBar *>
+{
+  // The information about the item type are taken from the domain
+  typedef typename TItemDomain::ValueType AtomicType;
+  typedef typename TItemDomain::DescriptorType DescriptorType;
+  typedef TItemDomain DomainType;
+
+  void SetDomain(QToolBar *w, const DomainType &domain)
+  {
+    // Remove all the actions from the toolbar
+    w->clear();
+
+    // Create an action group unless one already exists in the widget
+    QActionGroup *ag = w->findChild<QActionGroup *>();
+    if(ag == NULL)
+      ag = new QActionGroup(w);
+
+    // Populate the toolbar with actions
+    for(typename DomainType::const_iterator it = domain.begin();
+        it != domain.end(); ++it)
+      {
+      // Get the key/value pair
+      AtomicType value = domain.GetValue(it);
+      const DescriptorType &row = domain.GetDescription(it);
+
+      // Create an action and assign it to the action group
+      QAction *action = new QAction(w);
+      action->setActionGroup(ag);
+      action->setCheckable(true);
+      action->setData(QVariant::fromValue(value));
+
+      // Use the row traits to map information to the widget
+      TRowTraits::updateAction(action, row);
+      }
+  }
+
+  void UpdateDomainDescription(QToolBar *w, const DomainType &domain)
+  {
+    // Update each of the actions
+    foreach(QAction *action, w->actions())
+      {
+      AtomicType value = action->data().value<AtomicType>();
+      typename DomainType::const_iterator it = domain.find(value);
+      if(it != domain.end())
+        {
+        TRowTraits::updateAction(action, domain.GetDescription(it));
+        }
+      }
+  }
+
+  TItemDomain GetDomain(QToolBar *w)
+  {
+    // We don't actually pull the widget because the domain is fully specified
+    // by the model.
+    return DomainType();
+  }
+
+};
+*/
+
+/**
+ * A row traits that populates a QAction from a color label
+ *
+ * Use in conjunction with makeMultiRowCoupling
+ */
+/*
+class ColorLabelToQActionRowTraits
+{
+public:
+  static void updateAction(QAction *action, const ColorLabel &label)
+  {
+    action->setIcon(CreateColorBoxIcon(16, 16, GetBrushForColorLabel(label)));
+    action->setToolTip(QString::fromUtf8(label.GetLabel()));
+  }
+};
+*/
+
+#endif // QTTOOLBARCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtWidgetArrayCoupling.h b/GUI/Qt/Coupling/QtWidgetArrayCoupling.h
new file mode 100644
index 0000000..aa5b9c6
--- /dev/null
+++ b/GUI/Qt/Coupling/QtWidgetArrayCoupling.h
@@ -0,0 +1,433 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTWIDGETARRAYCOUPLING_H
+#define QTWIDGETARRAYCOUPLING_H
+
+#include <QtWidgetCoupling.h>
+
+/**
+  This class allows widget traits to be extended to an array of widgets. It
+  uses a child traits object to map between an iris_vector_fixed and an array
+  of widgets.
+  */
+template <class TAtomic, unsigned int VDim, class TWidget, class ChildTraits>
+class WidgetArrayValueTraits :
+    public WidgetValueTraitsBase< iris_vector_fixed<TAtomic, VDim>,
+                                  std::vector<TWidget *> >
+{
+public:
+  typedef iris_vector_fixed<TAtomic, VDim> ValueType;
+  typedef std::vector<TWidget *> WidgetArrayType;
+
+  /**
+    Constructor, takes the "child" traits object, i.e., the traits for the
+    individual widgets in the array
+    */
+  WidgetArrayValueTraits(ChildTraits childTraits)
+    : m_ChildTraits(childTraits) { m_CacheValid.fill(false); }
+
+  ValueType GetValue(WidgetArrayType wa)
+  {
+    ValueType value = m_CachedModelValue;
+    for(unsigned int i = 0; i < VDim; i++)
+      {
+      TAtomic valWidget = m_ChildTraits.GetValue(wa[i]);
+      if(!m_CacheValid[i] || valWidget != m_CachedWidgetValue[i])
+        {
+        value(i) = valWidget;
+        m_CacheValid[i] = false;
+        }
+      }
+    return value;
+  }
+
+  void SetValue(WidgetArrayType wa, const ValueType &value)
+  {
+    for(unsigned int i = 0; i < VDim; i++)
+      {
+      m_ChildTraits.SetValue(wa[i], value(i));
+      m_CachedModelValue[i] = value(i);
+      m_CachedWidgetValue[i] = m_ChildTraits.GetValue(wa[i]);
+      m_CacheValid[i] = true;
+      }
+  }
+
+  void SetValueToNull(WidgetArrayType wa)
+  {
+    for(unsigned int i = 0; i < VDim; i++)
+      m_ChildTraits.SetValueToNull(wa[i]);
+    m_CacheValid.fill(false);
+  }
+
+  const char *GetSignal()
+  {
+    return m_ChildTraits.GetSignal();
+  }
+
+protected:
+  ChildTraits m_ChildTraits;
+
+  // We must cache the values sent to each widget and the corresponding states
+  // of each widget. This is because some widgets change the value passed to
+  // them. If one of the widgets in the array is edited by the user, we only
+  // want that widget's value to be sent to the model, while using the cached
+  // values for the other widgets.
+  ValueType m_CachedModelValue, m_CachedWidgetValue;
+  iris_vector_fixed<bool, VDim> m_CacheValid;
+};
+
+/**
+  Before defining a vectorized domain traits object, we need to define some
+  traits that describe how different kinds of domains map between atomic
+  and vectorized versions.
+  */
+template <class TDomain, unsigned int VDim>
+class DomainVectorExpansion
+{
+
+};
+
+template <class TAtomic, unsigned int VDim>
+class DomainVectorExpansion<NumericValueRange<TAtomic>, VDim>
+{
+public:
+  typedef iris_vector_fixed<TAtomic, VDim> VectorType;
+  typedef NumericValueRange<VectorType> VectorDomainType;
+  typedef NumericValueRange<TAtomic> AtomicDomainType;
+
+  static AtomicDomainType GetNthElement(
+      const VectorDomainType &dvec, unsigned int n)
+  {
+    return AtomicDomainType(
+          dvec.Minimum(n), dvec.Maximum(n), dvec.StepSize(n));
+  }
+
+  static void UpdateNthElement(
+      VectorDomainType &dvec, unsigned int n, const AtomicDomainType &dat)
+  {
+    dvec.Minimum(n) = dat.Minimum;
+    dvec.Maximum(n) = dat.Maximum;
+    dvec.StepSize(n) = dat.StepSize;
+  }
+};
+
+template <unsigned int VDim>
+class DomainVectorExpansion<TrivialDomain, VDim>
+{
+public:
+  typedef TrivialDomain VectorDomainType;
+  typedef TrivialDomain AtomicDomainType;
+
+  static AtomicDomainType GetNthElement(
+      const VectorDomainType &dvec, unsigned int n)
+  {
+    return AtomicDomainType();
+  }
+
+  static void UpdateNthElement(
+      VectorDomainType &dvec, unsigned int n, const AtomicDomainType &dat) {}
+};
+
+
+template <class TVectorDomain, int VDim>
+class ComponentDomainTraits
+{
+};
+
+template <class TAtomic, int VDim>
+class ComponentDomainTraits<
+    NumericValueRange<iris_vector_fixed<TAtomic, VDim> >, VDim>
+{
+public:
+  typedef iris_vector_fixed<TAtomic, VDim> VectorType;
+  typedef NumericValueRange<TAtomic> AtomicDomainType;
+  typedef NumericValueRange<VectorType> VectorDomainType;
+
+  static AtomicDomainType GetNthElement(
+      const VectorDomainType &dvec, unsigned int n)
+  {
+    return AtomicDomainType(
+          dvec.Minimum(n), dvec.Maximum(n), dvec.StepSize(n));
+  }
+
+  static void UpdateNthElement(
+      VectorDomainType &dvec, unsigned int n, const AtomicDomainType &dat)
+  {
+    dvec.Minimum(n) = dat.Minimum;
+    dvec.Maximum(n) = dat.Maximum;
+    dvec.StepSize(n) = dat.StepSize;
+  }
+};
+
+template <int VDim>
+class ComponentDomainTraits<TrivialDomain, VDim>
+{
+public:
+  typedef TrivialDomain AtomicDomainType;
+  typedef TrivialDomain VectorDomainType;
+
+  static AtomicDomainType GetNthElement(
+      const VectorDomainType &dvec, unsigned int n)
+  {
+    return AtomicDomainType();
+  }
+
+  static void UpdateNthElement(
+      VectorDomainType &dvec, unsigned int n, const AtomicDomainType &dat) {}
+};
+
+
+template <class TVectorDomain, unsigned int VDim,
+          class TWidget, class ChildTraits>
+class WidgetArrayDomainTraits :
+    public WidgetDomainTraitsBase<TVectorDomain, std::vector<TWidget *> >
+{
+public:
+  typedef ComponentDomainTraits<TVectorDomain, VDim> ComponentTraitsType;
+  typedef TVectorDomain VectorDomainType;
+  typedef typename ComponentTraitsType::AtomicDomainType AtomicDomainType;
+  typedef std::vector<TWidget *> WidgetArrayType;
+
+  /**
+    Constructor, takes the "child" traits object, i.e., the traits for the
+    individual widgets in the array
+    */
+  WidgetArrayDomainTraits(ChildTraits childTraits)
+    : m_ChildTraits(childTraits) {}
+
+  void SetDomain(WidgetArrayType wa, const VectorDomainType &range)
+  {
+    for(unsigned int i = 0; i < VDim; i++)
+      {
+      AtomicDomainType di = ComponentTraitsType::GetNthElement(range, i);
+      m_ChildTraits.SetDomain(wa[i], di);
+      }
+  }
+
+  VectorDomainType GetDomain(WidgetArrayType wa)
+  {
+    VectorDomainType range;
+    for(unsigned int i = 0; i < VDim; i++)
+      {
+      AtomicDomainType ri = m_ChildTraits.GetDomain(wa[i]);
+      ComponentTraitsType::UpdateNthElement(range, i, ri);
+      }
+    return range;
+  }
+
+protected:
+  ChildTraits m_ChildTraits;
+};
+
+/**
+  Create a coupling between an model whose value is of a vector type and
+  an array of widgets of the same type. For example, this function allows
+  you to hook up a model wrapped around a Vector3d to a triple of spin boxes.
+  This is very convenient for dealing with input and output of vector data.
+  */
+
+template <class TModel, class TWidget>
+class DefaultComponentValueTraits : public DefaultWidgetValueTraits<
+  typename TModel::ValueType::element_type, TWidget>
+{
+};
+
+template <class TModel, class TWidget>
+class DefaultComponentDomainTraits : public DefaultWidgetDomainTraits<
+    typename ComponentDomainTraits<typename TModel::DomainType,
+                          TModel::ValueType::SIZE>::AtomicDomainType,
+    TWidget>
+{
+};
+
+
+/**
+  Create a coupling between a model and an array of widgets. See the more
+  convenient versions of this method below
+  */
+template <class TWidget,
+          class TModel,
+          class WidgetValueTraits,
+          class WidgetDomainTraits>
+void makeWidgetArrayCoupling(
+    std::vector<TWidget *> wa,
+    TModel *model,
+    WidgetValueTraits trValue,
+    WidgetDomainTraits trDomain)
+{
+  typedef std::vector<TWidget *> WidgetArray;
+  typedef typename TModel::ValueType VectorType;
+  typedef typename TModel::DomainType VectorDomainType;
+  typedef typename VectorType::element_type ElementType;
+  const int VDim = VectorType::SIZE;
+
+  // Define the array traits
+  typedef WidgetArrayValueTraits<
+      ElementType, VDim, TWidget, WidgetValueTraits> ArrayValueTraits;
+
+  typedef WidgetArrayDomainTraits<
+      VectorDomainType, VDim, TWidget, WidgetDomainTraits> ArrayDomainTraits;
+
+  // The class of the mapping
+  typedef PropertyModelToWidgetDataMapping<
+      TModel, WidgetArray,
+      ArrayValueTraits, ArrayDomainTraits> MappingType;
+
+  // Create the mapping
+  MappingType *mapping = new MappingType(
+        wa, model,
+        ArrayValueTraits(trValue),
+        ArrayDomainTraits(trDomain));
+
+  // Create the coupling helper (event handler). It's attached to the first
+  // widget, just for the purpose of this object being deleted later.
+  QtCouplingHelper *h = new QtCouplingHelper(wa.front(), mapping);
+
+  // Populate the widget (force the domain and value to be copied)
+  mapping->InitializeWidgetFromModel();
+
+  // Listen to value change events from the model
+  LatentITKEventNotifier::connect(
+        model, ValueChangedEvent(),
+        h, SLOT(onPropertyModification(const EventBucket &)));
+
+  LatentITKEventNotifier::connect(
+        model, DomainChangedEvent(),
+        h, SLOT(onPropertyModification(const EventBucket &)));
+
+  LatentITKEventNotifier::connect(
+        model, DomainDescriptionChangedEvent(),
+        h, SLOT(onPropertyModification(const EventBucket &)));
+
+  // Listen to value change events for this widget
+  for(int i = 0; i < VDim; i++)
+    {
+    h->connect(trValue.GetSignalEmitter(wa[i]),
+               trValue.GetSignal(), SLOT(onUserModification()));
+    }
+}
+
+/**
+  Create a coupling between a model and a triplet of widgets. The model must
+  be an AbstractPropertyModel templated over iris_vector_fixed<T,3> and some
+  compatible Domain object, i.e., NumericValueRange or TrivialDomain. The
+  caller can optionally pass traits objects for overriding the default behavior
+  of model-to-widget copying of values and domain information.
+  */
+template <class TModel, class TWidget,
+          class WidgetValueTraits, class WidgetDomainTraits>
+void makeArrayCoupling(
+    TWidget *w1, TWidget *w2, TWidget *w3,
+    TModel *model,
+    WidgetValueTraits trValue,
+    WidgetDomainTraits trDomain)
+{
+  // Create the array of widgets
+  typedef std::vector<TWidget *> WidgetArray;
+  WidgetArray wa(3);
+  wa[0] = w1; wa[1] = w2; wa[2] = w3;
+
+  // Call the parent method
+  makeWidgetArrayCoupling<
+      TWidget,TModel,WidgetValueTraits,WidgetDomainTraits>(
+        wa, model, trValue, trDomain);
+}
+
+template <class TModel, class TWidget,
+          class WidgetValueTraits>
+void makeArrayCoupling(
+    TWidget *w1, TWidget *w2, TWidget *w3,
+    TModel *model,
+    WidgetValueTraits trValue)
+{
+  typedef DefaultComponentDomainTraits<TModel,TWidget> WidgetDomainTraits;
+  makeArrayCoupling<TModel, TWidget, WidgetValueTraits, WidgetDomainTraits>
+      (w1,w2,w3,model,trValue,WidgetDomainTraits());
+}
+
+template <class TModel, class TWidget>
+void makeArrayCoupling(
+    TWidget *w1, TWidget *w2, TWidget *w3,
+    TModel *model)
+{
+  typedef DefaultComponentValueTraits<TModel,TWidget> WidgetValueTraits;
+  makeArrayCoupling<TModel, TWidget, WidgetValueTraits>
+      (w1,w2,w3,model,WidgetValueTraits());
+}
+
+
+/**
+  Create a coupling between a model and a pair of widgets. The model must
+  be an AbstractPropertyModel templated over iris_vector_fixed<T,2> and some
+  compatible Domain object, i.e., NumericValueRange or TrivialDomain. The
+  caller can optionally pass traits objects for overriding the default behavior
+  of model-to-widget copying of values and domain information.
+  */
+template <class TModel, class TWidget,
+          class WidgetValueTraits, class WidgetDomainTraits>
+void makeArrayCoupling(
+    TWidget *w1, TWidget *w2,
+    TModel *model,
+    WidgetValueTraits trValue,
+    WidgetDomainTraits trDomain)
+{
+  // Create the array of widgets
+  typedef std::vector<TWidget *> WidgetArray;
+  WidgetArray wa(2);
+  wa[0] = w1; wa[1] = w2;
+
+  // Call the parent method
+  makeWidgetArrayCoupling<
+      TWidget,TModel,WidgetValueTraits,WidgetDomainTraits>(
+        wa, model, trValue, trDomain);
+}
+
+template <class TModel, class TWidget,
+          class WidgetValueTraits>
+void makeArrayCoupling(
+    TWidget *w1, TWidget *w2,
+    TModel *model,
+    WidgetValueTraits trValue)
+{
+  typedef DefaultComponentDomainTraits<TModel,TWidget> WidgetDomainTraits;
+  makeArrayCoupling<TModel, TWidget, WidgetValueTraits, WidgetDomainTraits>
+      (w1,w2,model,trValue,WidgetDomainTraits());
+}
+
+template <class TModel, class TWidget>
+void makeArrayCoupling(
+    TWidget *w1, TWidget *w2,
+    TModel *model)
+{
+  typedef DefaultComponentValueTraits<TModel,TWidget> WidgetValueTraits;
+  makeArrayCoupling<TModel, TWidget, WidgetValueTraits>
+      (w1,w2,model,WidgetValueTraits());
+}
+
+
+
+#endif // QTWIDGETARRAYCOUPLING_H
diff --git a/GUI/Qt/Coupling/QtWidgetCoupling.h b/GUI/Qt/Coupling/QtWidgetCoupling.h
new file mode 100644
index 0000000..5e855b9
--- /dev/null
+++ b/GUI/Qt/Coupling/QtWidgetCoupling.h
@@ -0,0 +1,719 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+#ifndef QTWIDGETCOUPLING_H
+#define QTWIDGETCOUPLING_H
+
+#include <QWidget>
+#include <QVariant>
+#include <QAction>
+#include <PropertyModel.h>
+#include <SNAPCommon.h>
+#include <LatentITKEventNotifier.h>
+#include "QtWidgetActivator.h"
+
+/**
+  Abstract class for hierarchy of data mappings between widgets and models. The mapping
+  is created when a model is coupled to a widget. It handles mapping data from the model
+  to the widget (when the model executes an appropriate event) and from the widget to the
+  model. This abstract interface is generic and does not assume anything about the 
+  model or the widget. 
+  */
+class AbstractWidgetDataMapping
+{
+public:
+  virtual ~AbstractWidgetDataMapping() {}
+
+  // Called the first time the widget is coupled to the model
+  virtual void InitializeWidgetFromModel() = 0;
+
+  // Called when the widget is changed
+  virtual void UpdateModelFromWidget() = 0;
+
+  // Called when the model is changed (event bucket contains the events that
+  // have occured to the model, so we know what aspects of the widget need to
+  // be updated)
+  virtual void UpdateWidgetFromModel(const EventBucket &bucket) = 0;
+};
+
+
+/**
+  Data mapping between a property model (encapsulating a value and a domain) 
+  and an input widget of class TWidget. The behavior of this class is controlled
+  by the template parameters WidgetValueTraits and WidgetDomainTraits, which 
+  describe how values and domains are mapped to the specific widget. The traits
+  classes for common Qt widgets are in header files QtXXXCoupling.h
+  */
+template <class TModel, class TWidgetPtr,
+          class WidgetValueTraits, class WidgetDomainTraits>
+class PropertyModelToWidgetDataMapping : public AbstractWidgetDataMapping
+{
+public:
+
+  typedef TModel ModelType;
+  typedef typename ModelType::ValueType AtomicType;
+  typedef typename ModelType::DomainType DomainType;
+
+  /** 
+   * Constructor: set all the parameters of the mapping
+   */
+  PropertyModelToWidgetDataMapping(
+      TWidgetPtr w, ModelType *model,
+      WidgetValueTraits valueTraits, WidgetDomainTraits domainTraits)
+    : m_Widget(w), m_Model(model), m_Updating(false),
+      m_ValueTraits(valueTraits), m_DomainTraits(domainTraits),
+      m_CachedValueAvailable(false),
+      m_CachedDomainAvailable(false),
+      m_AllowUpdateInInvalidState(false),
+      m_LastBucketMTime(0) {}
+
+  /** 
+   * Called the first time the widget is coupled to the model in order to
+   * populate the widget from the model.
+   */
+  void InitializeWidgetFromModel()
+  {
+    // Call the update method, including updating the domain
+    this->DoUpdateWidgetFromModel(true, false);
+  }
+
+  /**
+   * Whether the user can update the model when it is in invalid state
+   */
+  irisSetMacro(AllowUpdateInInvalidState, bool)
+
+  /** 
+   * Respond to a change in the model
+   */
+  void UpdateWidgetFromModel(const EventBucket &bucket)
+  {
+    // Make sure we don't process the same event bucket twice
+    if(bucket.GetMTime() <= m_LastBucketMTime)
+      return;
+
+    // The bucket parameter tells us whether the domain changed or not
+    this->DoUpdateWidgetFromModel(
+          bucket.HasEvent(DomainChangedEvent()),
+          bucket.HasEvent(DomainDescriptionChangedEvent()));
+
+    // Store the bucket id
+    m_LastBucketMTime = bucket.GetMTime();
+  }
+
+  /**
+   * Respond to the user changing the value in the widget
+   */
+  void UpdateModelFromWidget()
+  {
+    if(!m_Updating)
+      {
+      AtomicType user_value = m_ValueTraits.GetValue(m_Widget);
+      AtomicType model_value;
+
+      // Get the current value and status from the model
+      // TODO: this information could be cached, and dirtied in the case of
+      // an event. Currently, we are doing a lot of unnecessary accesses to
+      // the model just to check hte validity and current value of th model
+      bool valid = m_Model->GetValueAndDomain(model_value, NULL);
+
+      // Note: if the model reports that the value is invalid, we are not
+      // allowing the user to mess with the value. This may have some odd
+      // consequences. We need to investigate.
+      if((valid && model_value != user_value)
+         || (!valid && m_AllowUpdateInInvalidState))
+        {
+        m_Model->SetValue(user_value);
+        m_CachedWidgetValue = user_value;
+        m_CachedValueAvailable = true;
+        }
+      }
+  }
+
+protected:
+
+  void DoUpdateWidgetFromModel(bool flagDomainChange, bool flagDomainDescriptionChange)
+  {
+    m_Updating = true;
+
+    // The value is always needed
+    AtomicType value;
+
+    // The domain should only be updated in the bucket contains the range
+    // event (the target range has been modified)
+    DomainType *domptr = NULL;
+    if(flagDomainChange || flagDomainDescriptionChange)
+      {
+      m_DomainTemp = m_DomainTraits.GetDomain(m_Widget);
+      domptr = &m_DomainTemp;
+      }
+
+    // Obtain the value from the model
+    if(m_Model->GetValueAndDomain(value, domptr))
+      {
+      // Update the domain if necessary. The updates to the domain never come
+      // in response to the user interaction with m_Widget, so it's safe to
+      // just call SetDomain without first checking if the change is 'real'.
+      if(flagDomainChange)
+        {
+        if(!m_CachedDomainAvailable || m_CachedWidgetDomain != m_DomainTemp)
+          {
+          m_DomainTraits.SetDomain(m_Widget, m_DomainTemp);
+
+          // Once the domain changes, the current cached value can no longer be
+          // trusted because the widget may have reconfigured.
+          m_CachedValueAvailable = false;
+
+          // Cache the domain if it is atomic (supports comparison operator)
+          if(m_DomainTemp.isAtomic())
+            {
+            m_CachedWidgetDomain = m_DomainTemp;
+            m_CachedDomainAvailable = true;
+            }
+          }
+        }
+      else if(flagDomainDescriptionChange)
+        {
+        m_DomainTraits.UpdateDomainDescription(m_Widget, m_DomainTemp);
+        }
+
+      // Before setting the value, we should check it against the cached value
+      if(!m_CachedValueAvailable || m_CachedWidgetValue != value)
+        {
+        m_ValueTraits.SetValue(m_Widget, value);
+        m_CachedWidgetValue = value;
+        m_CachedValueAvailable = true;
+        }
+      }
+    else
+      {
+      m_ValueTraits.SetValueToNull(m_Widget);
+      m_CachedValueAvailable = false;
+      }
+
+    m_Updating = false;
+  }
+
+private:
+
+  TWidgetPtr m_Widget;
+  ModelType *m_Model;
+  bool m_Updating;
+  WidgetValueTraits m_ValueTraits;
+  WidgetDomainTraits m_DomainTraits;
+
+  // Whether the user can update the model when it is in invalid state
+  bool m_AllowUpdateInInvalidState;
+
+  // A specific property of the widget that should be toggled when the model
+  // is in NULL state (visible/enabled)
+  QString m_NullStateProperty;
+
+  // A temporary copy of the domain
+  DomainType m_DomainTemp;
+  DomainType m_CachedWidgetDomain;
+
+  // We cache the last known value in the widget to avoid unnecessary updates
+  // of the widget in response to events generated from the model after the
+  // model has been updated in response to the widget.
+  AtomicType m_CachedWidgetValue;
+
+  // Whether or not the cached value can be used
+  bool m_CachedValueAvailable, m_CachedDomainAvailable;
+
+  // The last bucked ID handled by this widget. This is used to protect against
+  // updates being invoked twice with the same event bucket (seems like some
+  // sort of a Qt weirdness)
+  unsigned long m_LastBucketMTime;
+};
+
+
+/**
+  Base class for widget value traits. It specifies the methods that the traits
+  classes must provide. See the QtXXXCoupling.h files for concrete implementations.
+  */
+template <class TAtomic, class TWidgetPtr>
+class WidgetValueTraitsBase
+{
+public:
+  // Get the Qt signal that the widget fires when its value has changed
+  // For example { return SIGNAL(triggered()); }
+  virtual const char *GetSignal() { return NULL; }
+
+  // Get the widget that generates the signal above. Normally it's the same
+  // as the input widget, but in some cases, it's some other QObject that
+  // fires the signal, i.e., in QAbstractItemView, it would be the item
+  // selection model rather than the view itself
+  virtual QObject *GetSignalEmitter(QObject *w) { return w; }
+
+  // Get the value from the widget
+  virtual TAtomic GetValue(TWidgetPtr) = 0;
+
+  // Set the value of the widget
+  virtual void SetValue(TWidgetPtr, const TAtomic &) = 0;
+
+  // The default behavior for setting the widget to null is to do nothing.
+  // This should be overridden by child traits classes
+  virtual void SetValueToNull(TWidgetPtr) {}
+
+  virtual ~WidgetValueTraitsBase() {}
+};
+
+
+/**
+ * Widget value traits that connect a boolean property of a Qt widget with
+ * a boolean (or boolean-castable) value. These traits don't handle the
+ * property having a null value - probably should be addressed in the future
+ */
+template <class TAtomic>
+class WidgetBooleanNamedPropertyTraits
+    : public WidgetValueTraitsBase<TAtomic, QObject *>
+{
+public:
+  WidgetBooleanNamedPropertyTraits(const char *propertyName)
+    : m_Property(propertyName) {}
+
+  virtual TAtomic GetValue(QObject *w)
+  {
+    return qvariant_cast<TAtomic>(w->property(m_Property.c_str()));
+  }
+  virtual void SetValue(QObject *w, const TAtomic &value)
+  {
+    w->setProperty(m_Property.c_str(), value);
+  }
+
+protected:
+  std::string m_Property;
+};
+
+
+/**
+  Base class for widget domain traits. It specifies the methods that the traits
+  classes must provide. See the QtXXXCoupling.h files for concrete implementations.
+  */
+template <class TDomain, class TWidgetPtr>
+class WidgetDomainTraitsBase
+{
+public:
+  /**
+    Set the domain from the values in the model
+   */
+  virtual void SetDomain(TWidgetPtr w, const TDomain &domain) = 0;
+
+  /**
+    Update the description of the domain from the values in the model, without
+    changing the configuration of the domain. This is only relevant for some
+    kinds of domains, such as lists of items. In this case, we need to change
+    the presentation of the items to the user, while keeping the list of items
+    intact. By default, this does nothing.
+    */
+  virtual void UpdateDomainDescription(TWidgetPtr w, const TDomain &domain) {}
+
+  /**
+    Get the current value of the domain from the model. This is only
+    needed in cases that the model does not provide full domain information
+    (some information is coded in the widget by the developer). For widgets
+    where the model fully specifies the domain, it's safe to just return
+    a trivially initialized domain object.
+    */
+  virtual TDomain GetDomain(TWidgetPtr w) = 0;
+
+  virtual ~WidgetDomainTraitsBase() {}
+};
+
+/** Empty template for default value traits. Specialize for different Qt widgets */
+template <class TAtomic, class TWidget>
+class DefaultWidgetValueTraits {};
+
+/** Empty template for default domain traits. Specialize for different Qt widgets */
+template <class TDomain, class TWidget>
+class DefaultWidgetDomainTraits {};
+
+/** Default domain traits for models with a TrivialDomain. */
+template <class TWidget>
+class DefaultWidgetDomainTraits<TrivialDomain, TWidget>
+    : public WidgetDomainTraitsBase<TrivialDomain, TWidget *>
+{
+public:
+  // With a trivial domain, do nothing!
+  virtual void SetDomain(TWidget *w, const TrivialDomain &) {}
+
+  virtual TrivialDomain GetDomain(TWidget *w)
+    { return TrivialDomain(); }
+};
+
+/**
+ * Empty template for default domain traits for widgets that contain
+ * multiple rows. Specialize for different Qt widgets. One way to specialize
+ * is to derive from the class ItenSetWidgetDomainTraits below, although it
+ * is not the only way to specialize.
+ */
+template <class TDomain, class TWidget, class TRowTraits>
+class DefaultMultiRowWidgetDomainTraits {};
+
+/** 
+  Domain traits for widgets like combo boxes, list views and tables, which
+  present the user with a list of options, from which a single choice is 
+  selected. The actual widget-specific logic is handled by the TRowTraits
+  template parameter, which defines how an option description provided by
+  the model (TDesc) is appended as a row in the widget. TRowTraits should
+  provide static methods appendRow and removeAll.
+
+  The TItemDomain parameter needs to be a subclass of AbstractItemSetDomain
+  or provide the same signature.
+ */
+template <class TItemDomain, class TWidget, class TRowTraits>
+class ItemSetWidgetDomainTraits :
+    public WidgetDomainTraitsBase<TItemDomain, TWidget *>
+{
+public:
+
+  // The information about the item type are taken from the domain
+  typedef typename TItemDomain::ValueType AtomicType;
+  typedef typename TItemDomain::DescriptorType DescriptorType;
+  typedef TItemDomain DomainType;
+
+  void SetDomain(TWidget *w, const DomainType &domain)
+  {
+    // Remove all items from the widget
+    TRowTraits::removeAll(w);
+
+    // This is where we actually populate the widget
+    for(typename DomainType::const_iterator it = domain.begin();
+        it != domain.end(); ++it)
+      {
+      // Get the key/value pair
+      AtomicType value = domain.GetValue(it);
+      const DescriptorType &row = domain.GetDescription(it);
+
+      // Use the row traits to map information to the widget
+      TRowTraits::appendRow(w, value, row);
+      }
+  }
+
+  void UpdateDomainDescription(TWidget *w, const DomainType &domain)
+  {
+    // This is not the most efficient way of doing things, because we
+    // are still linearly parsing through the widget and updating rows.
+    // But at least the actual modifications to the widget are limited
+    // to the rows that have been modified.
+    //
+    // What would be more efficient is to have a list of ids which have
+    // been modified and update only those. Or even better, implement all
+    // of this using an AbstractItemModel
+    int nrows = TRowTraits::getNumberOfRows(w);
+    for(int i = 0; i < nrows; i++)
+      {
+      AtomicType id = TRowTraits::getValueInRow(w, i);
+      typename DomainType::const_iterator it = domain.find(id);
+      if(it != domain.end())
+        {
+        const DescriptorType &row = domain.GetDescription(it);
+        TRowTraits::updateRowDescription(w, i, row);
+        }
+      }
+  }
+
+
+
+  TItemDomain GetDomain(TWidget *w)
+  {
+    // We don't actually pull the widget because the domain is fully specified
+    // by the model.
+    return DomainType();
+  }
+};
+
+/**
+ * This Qt object is used to maintain the coupling between a model and a widget. It is 
+ * memory managed by Qt and attached to the Qt widget that is involved in the coupling.
+ */
+class QtCouplingHelper : public QObject
+{
+  Q_OBJECT
+
+public:
+  explicit QtCouplingHelper(QObject *widget, AbstractWidgetDataMapping *dm)
+    : QObject(widget)
+  {
+    m_DataMapping = dm;
+    setObjectName(QString("CouplingHelper:%1").arg(widget->objectName()));
+  }
+
+public slots:
+  void onUserModification()
+  {
+    m_DataMapping->UpdateModelFromWidget();
+  }
+
+  void onPropertyModification(const EventBucket &bucket)
+  {
+    m_DataMapping->UpdateWidgetFromModel(bucket);
+  }
+
+protected:
+  AbstractWidgetDataMapping *m_DataMapping;
+};
+
+/**
+  This class simplifies passing parameters to the makeCoupling functions.
+  */
+struct QtCouplingOptions
+{
+  enum Option
+  {
+    NO_OPTIONS = 0x0,
+
+    /**
+      This flag disconnects the Widget -> Model direction of the coupling. The
+      coupling will update the widget value and domain in response to changes
+      in the model, but it will not update the model from changes in the widget.
+      This is useful when we want to explicitly handle changes in the
+      widget. For example, if we need to check the validity of the value and/or
+      present a dialog box, we would use this option, and then set up an explicit
+      slot to handle changes from the widget and update the model.
+      */
+    UNIDIRECTIONAL = 0x1,
+
+    /**
+     * This flag makes it possible for the widget to write its value to the model
+     * when the model is in invalid state. By default, this is disabled and any
+     * changes by the user to a widget in invalid state are ignored, i.e. not
+     * sent to the model.
+     */
+    ALLOW_UPDATES_WHEN_INVALID = 0x2,
+
+    /**
+     * Whether the widget should be deactivated when the model is in Null state.
+     * Passing this option to makeCoupling will create a widget activator for the
+     * widget. Make sure no other activators are set on the widget
+     */
+    DEACTIVATE_WHEN_INVALID = 0x4
+  };
+
+  Q_DECLARE_FLAGS(Options, Option)
+
+  irisGetSetMacro(Options, Options)
+  irisGetSetMacro(SignalOverride, const char *)
+
+  bool IsUnidirectional()
+    { return m_Options.testFlag(UNIDIRECTIONAL); }
+
+  bool IsUpdateAllowedWhenInvalid()
+    { return m_Options.testFlag(ALLOW_UPDATES_WHEN_INVALID); }
+
+  bool IsDeactivatedWhenInvalid()
+    { return m_Options.testFlag(DEACTIVATE_WHEN_INVALID); }
+
+  QtCouplingOptions(Options opts = NO_OPTIONS)
+    : m_Options(opts), m_SignalOverride(NULL) {}
+
+  QtCouplingOptions(const char *signal, Options opts = NO_OPTIONS)
+    : m_Options(opts), m_SignalOverride(signal)  {}
+
+  QtCouplingOptions(const QtCouplingOptions &ref)
+    : m_Options(ref.m_Options), m_SignalOverride(ref.m_SignalOverride) {}
+
+private:
+
+  /**
+   * The options
+   */
+  Options m_Options;
+
+  /**
+    This value allow the default signal associated with a widget coupling
+    to be overriden. For each Qt widget, there is a default signal that we
+    have picked, but in some cases there may be a reason to choose a different
+    signal. The model is updated in response to this signal. When set to NULL
+    this means that the default signal will be used.
+    */
+  const char *m_SignalOverride;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QtCouplingOptions::Options)
+
+/**
+ * This function is the entry point into the coupling system between property models
+ * (values with a domain) and Qt widgets. There are three versions of this method. 
+ * All versions take a model and a widget as parameters. They differ in whether the
+ * user explicitly specifies the traits objects for the values and domains, or whether
+ * the default trait objects are used. 
+ *
+ * The last optional parameter allows the user to override the signal specified
+ * in the default value traits for the widget. This is the signal in response to
+ * which the model is updated from the widget
+ */ 
+template <class TModel, class TWidget,
+          class WidgetValueTraits, class WidgetDomainTraits>
+void makeCoupling(
+    TWidget *w,
+    TModel *model,
+    WidgetValueTraits valueTraits,
+    WidgetDomainTraits domainTraits,
+    QtCouplingOptions opts = QtCouplingOptions())
+{
+  typedef typename TModel::ValueType ValueType;
+  typedef typename TModel::DomainType DomainType;
+
+  typedef PropertyModelToWidgetDataMapping<
+      TModel, TWidget *,
+      WidgetValueTraits, WidgetDomainTraits> MappingType;
+
+  MappingType *mapping = new MappingType(w, model, valueTraits, domainTraits);
+
+  QtCouplingHelper *h = new QtCouplingHelper(w, mapping);
+
+  // Populate the widget (force the domain and value to be copied)
+  mapping->InitializeWidgetFromModel();
+
+  // Listen to value change events from the model
+  LatentITKEventNotifier::connect(
+        model, ValueChangedEvent(),
+        h, SLOT(onPropertyModification(const EventBucket &)));
+
+  LatentITKEventNotifier::connect(
+        model, DomainChangedEvent(),
+        h, SLOT(onPropertyModification(const EventBucket &)));
+
+  LatentITKEventNotifier::connect(
+        model, DomainDescriptionChangedEvent(),
+        h, SLOT(onPropertyModification(const EventBucket &)));
+
+  // Listen to change events on this widget, unless asked not to
+  if(!opts.IsUnidirectional())
+    {
+    const char *mysignal = (opts.GetSignalOverride())
+        ? opts.GetSignalOverride() : valueTraits.GetSignal();
+    QObject *emitter = valueTraits.GetSignalEmitter(w);
+    if(mysignal && emitter)
+      h->connect(emitter, mysignal, SLOT(onUserModification()));
+    }
+
+  // Set the allow-changes flag in the mapping
+  if(opts.IsUpdateAllowedWhenInvalid())
+    {
+    mapping->SetAllowUpdateInInvalidState(true);
+    }
+
+  // Create an activator
+  if(opts.IsDeactivatedWhenInvalid())
+    {
+    activateOnFlag(w, model, UIF_PROPERTY_IS_VALID);
+    }
+}
+
+template <class TModel, class TWidget, class WidgetValueTraits>
+void makeCoupling(TWidget *w,
+                  TModel *model,
+                  WidgetValueTraits trValue,
+                  QtCouplingOptions opts = QtCouplingOptions())
+{
+  typedef typename TModel::DomainType DomainType;
+  typedef DefaultWidgetDomainTraits<DomainType, TWidget> WidgetDomainTraits;
+  makeCoupling<TModel, TWidget,
+      WidgetValueTraits, WidgetDomainTraits>(
+        w, model, trValue, WidgetDomainTraits(), opts);
+}
+
+
+/**
+  Create a coupling between a numeric model and a Qt widget. The widget
+  will listen to the events from the model and update its value and range
+  accordingly. When the user interacts with the widget, the model will be
+  updated. The coupling fully automates mapping of data between Qt input
+  widgets and SNAP numeric models.
+
+  This version of the method uses default traits. There is also a version
+  that allows you to provide your own traits.
+*/
+template <class TModel, class TWidget>
+void makeCoupling(TWidget *w,
+                  TModel *model,
+                  QtCouplingOptions opts = QtCouplingOptions())
+{
+  typedef typename TModel::ValueType ValueType;
+  typedef DefaultWidgetValueTraits<ValueType, TWidget> WidgetValueTraits;
+  makeCoupling<TModel, TWidget,WidgetValueTraits>(
+        w, model, WidgetValueTraits(), opts);
+}
+
+
+/**
+  Create a coupling between a PropertyModel with some kind of an item set domain
+  and a Qt widget that holds multiple items or rows (QListView, QComboBox,
+  QToolBar, etc.). Unlike simple kinds of couplings (QLineEdit, etc), these
+  more complex couplings are parameterized by the type TRowTraits, which
+  describe the mapping of each item in the PropertyModel to each row in the
+  widget. This version of the coupling method takes TRowTraits as an extra
+  parameter, and creates an appropriate domain
+  */
+template <class TModel, class TWidget, class TRowTraits>
+void makeMultiRowCoupling(TWidget *w,
+                          TModel *model,
+                          TRowTraits rowTraits,
+                          QtCouplingOptions opts = QtCouplingOptions())
+{
+  typedef typename TModel::ValueType ValueType;
+  typedef DefaultWidgetValueTraits<ValueType, TWidget> WidgetValueTraits;
+
+  typedef typename TModel::DomainType DomainType;
+  typedef DefaultMultiRowWidgetDomainTraits<DomainType, TWidget, TRowTraits> WidgetDomainTraits;
+
+  makeCoupling<TModel, TWidget, WidgetValueTraits, WidgetDomainTraits>(
+        w, model, WidgetValueTraits(), WidgetDomainTraits(), opts);
+}
+
+/**
+ * Create a coupling between a boolean (or integer) model and a named property
+ * in a Qt widget, such as "visible". This allows us to hide/show and otherwise
+ * modify widgets in response to changes in the model layer.
+ */
+template <class TModel>
+void makeBooleanNamedPropertyCoupling(
+    QObject *w, const char *propertyName,
+    TModel *model,
+    QtCouplingOptions opts = QtCouplingOptions())
+{
+  // Create the traits for the property
+  typedef typename TModel::ValueType ValueType;
+  typedef WidgetBooleanNamedPropertyTraits<ValueType> TraitsType;
+  TraitsType traits(propertyName);
+
+  // Call the main coupling method
+  makeCoupling<TModel, QObject, TraitsType>(w, model, traits, opts);
+}
+
+/**
+ * Couple the visibility of a widget to a boolean or integer-valued model
+ */
+template <class TModel>
+void makeWidgetVisibilityCoupling(
+    QWidget *w, TModel *model,
+    QtCouplingOptions opts = QtCouplingOptions())
+{
+  makeBooleanNamedPropertyCoupling(w, "visible", model, opts);
+}
+
+#endif // QTWIDGETCOUPLING_H
diff --git a/GUI/Qt/External/ColorWheel/ColorWheel.cxx b/GUI/Qt/External/ColorWheel/ColorWheel.cxx
new file mode 100644
index 0000000..f9a1ef9
--- /dev/null
+++ b/GUI/Qt/External/ColorWheel/ColorWheel.cxx
@@ -0,0 +1,321 @@
+#include "ColorWheel.h"
+
+ColorWheel::ColorWheel(QWidget *parent) :
+  QWidget(parent),
+  initSize(300,300),
+  mouseDown(false),
+  margin(5),
+  m_WheelWidth(30),
+  current(Qt::red),
+  inWheel(false),
+  inSquare(false)
+{
+  resize(initSize);
+  //    setSizeIncrement(10,10);
+  setMinimumSize(200,200);
+  //    setMaximumSize(400,400);
+  setCursor(Qt::CrossCursor);
+
+  wheel = QImage(initSize, QImage::Format_ARGB32_Premultiplied);
+  wheel.fill(Qt::transparent);
+}
+
+QColor ColorWheel::color()
+{
+  return current;
+}
+
+void ColorWheel::setColor(const QColor &color)
+{
+  if(color.hue() != current.hue()){
+    hueChanged(color.hue());
+    }
+
+  if( color.saturation() != current.saturation()
+      || color.value() != current.value() ){
+    svChanged(color);
+    }
+}
+
+
+QColor ColorWheel::posColor(const QPoint &point)
+{
+  // if( ! wheel.valid(point) ) return QColor();
+  if(inWheel)
+    {
+    qreal hue = 0;
+    int r = qMin(width(), height()) / 2;
+    if( point.x() > r )
+      {
+      if(point.y() < r )
+        {
+        //1
+        hue = 90 - (qAtan2( (point.x() - r) , (r - point.y()) )  / 3.14 / 2 * 360);
+        }
+      else
+        {
+        //4
+        hue = 270 + (qAtan2( (point.x() - r) , (point.y() - r ) )  / 3.14 / 2 * 360);
+        }
+      }
+    else
+      {
+      if(point.y() < r )
+        {
+        //2
+        hue =  90 + (qAtan2( (r - point.x()) , (r - point.y()) )  / 3.14 / 2 * 360);
+        }
+      else
+        {
+        //3
+        hue =  270 - (qAtan2( (r - point.x()) , (point.y() - r ))  / 3.14 / 2 * 360);
+        }
+      }
+    return QColor::fromHsv(hue, current.saturation(), current.value() );
+    }
+  if(inSquare)
+    {
+    // region of the widget
+    int w = qMin(width(), height());
+    // radius of outer circle
+    qreal r = w/2-margin;
+    // radius of inner circle
+    qreal ir = r-m_WheelWidth;
+    // left corner of square
+    qreal m = w/2.0-ir/qSqrt(2);
+    QPoint p = point - QPoint(m, m);
+    qreal SquareWidth = 2*ir/qSqrt(2);
+    return QColor::fromHsvF( current.hueF(),
+                             std::min(std::max(p.x()/SquareWidth, 0.0), 1.0),
+                             std::min(std::max(p.y()/SquareWidth, 0.0), 1.0) );
+    }
+  return QColor();
+}
+
+QSize ColorWheel::sizeHint () const
+{
+  return QSize(height(),height());
+}
+QSize ColorWheel::minimumSizeHint () const
+{
+  return QSize(30,30);
+}
+
+void ColorWheel::mousePressEvent(QMouseEvent *event)
+{
+  lastPos = event->pos();
+  if(wheelRegion.contains(lastPos)){
+    inWheel = true;
+    inSquare = false;
+    QColor color = posColor(lastPos);
+    hueChanged(color.hue());
+    }else if(squareRegion.contains(lastPos)){
+    inWheel = false;
+    inSquare = true;
+    QColor color = posColor(lastPos);
+    svChanged(color);
+    }
+  mouseDown = true;
+}
+
+void ColorWheel::mouseMoveEvent(QMouseEvent *event)
+{
+  lastPos = event->pos();
+  if( !mouseDown ) return;
+  if(inWheel)
+    {
+    QColor color = posColor(lastPos);
+    hueChanged(color.hue());
+    }
+  else if(inSquare)
+    {
+    QColor color = posColor(lastPos);
+    svChanged(color);
+    }
+}
+
+void ColorWheel::mouseReleaseEvent(QMouseEvent *event)
+{
+  mouseDown = false;
+  inWheel = false;
+  inSquare = false;
+}
+
+void ColorWheel::resizeEvent(QResizeEvent *event)
+{
+  wheel = QImage(event->size(), QImage::Format_ARGB32_Premultiplied);
+  wheel.fill(Qt::transparent);
+  //    source = wheel;
+  //    source.fill(Qt::transparent);
+
+  drawWheel(event->size());
+  drawSquare(current.hue());
+  drawIndicator(current.hue());
+  drawPicker(current);
+  update();
+}
+
+void ColorWheel::paintEvent(QPaintEvent *event)
+{
+  QPainter painter(this);
+  QStyleOption opt;
+  opt.init(this);
+  painter.drawImage(0,0,wheel);
+  style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
+}
+
+#include <QPalette>
+void ColorWheel::drawWheel(const QSize &newSize)
+{
+
+  int r = qMin(newSize.width(), newSize.height());
+
+  QPainter painter(&wheel);
+  painter.setRenderHint(QPainter::Antialiasing);
+  // wheel.fill(Qt::white);
+  wheel.fill(Qt::transparent);
+
+  QConicalGradient conicalGradient(0, 0, 0);
+  conicalGradient.setColorAt(0.0, Qt::red);
+  conicalGradient.setColorAt(60.0/360.0, Qt::yellow);
+  conicalGradient.setColorAt(120.0/360.0, Qt::green);
+  conicalGradient.setColorAt(180.0/360.0, Qt::cyan);
+  conicalGradient.setColorAt(240.0/360.0, Qt::blue);
+  conicalGradient.setColorAt(300.0/360.0, Qt::magenta);
+  conicalGradient.setColorAt(1.0, Qt::red);
+
+  /* outer circle */
+  painter.translate(r / 2, r / 2);
+
+  QBrush brush(conicalGradient);
+  // painter.setPen(Qt::NoPen);
+
+  painter.setPen(Qt::darkGray);
+  painter.setBrush(brush);
+  painter.drawEllipse(QPoint(0,0),r/2-margin,r/2-margin);
+
+  /* inner circle */
+  painter.setBrush(palette().background().color());
+  painter.drawEllipse(QPoint(0,0),r/2-margin-m_WheelWidth,r/2-margin-m_WheelWidth);
+
+
+  //    QPainter painter2(&wheel);
+  //    painter2.drawImage(0,0,source);
+
+  //caculate wheel region
+  wheelRegion = QRegion(r/2, r/2, r-2*margin, r-2*margin, QRegion::Ellipse);
+  wheelRegion.translate(-(r-2*margin)/2, -(r-2*margin)/2);
+
+  int tmp = 2*(margin+m_WheelWidth);
+  QRegion subRe( r/2, r/2, r-tmp, r-tmp, QRegion::Ellipse );
+  subRe.translate(-(r-tmp)/2, -(r-tmp)/2);
+  wheelRegion -= subRe;
+}
+
+void ColorWheel::drawSquare(const int &hue)
+{
+  QPainter painter(&wheel);
+  painter.setRenderHint(QPainter::Antialiasing);
+
+  // region of the widget
+  int w = qMin(width(), height());
+  // radius of outer circle
+  qreal r = w/2-margin;
+  // radius of inner circle
+  qreal ir = r-m_WheelWidth;
+  // left corner of square
+  qreal m = w/2.0-ir/qSqrt(2);
+  painter.translate(m, m);
+  // painter.setPen(Qt::NoPen);
+  painter.setPen(Qt::darkGray);
+
+  QImage square(255,255,QImage::Format_ARGB32_Premultiplied);
+  QColor color;
+  QRgb vv;
+  for(int i=0;i<255;++i){
+    for(int j=0;j<255;++j){
+      color = QColor::fromHsv(hue,i,j);
+      vv = qRgb(color.red(),color.green(),color.blue());
+      square.setPixel(i,j,vv);
+      }
+    }
+  qreal SquareWidth = 2*ir/qSqrt(2);
+  square = square.scaled(SquareWidth,SquareWidth);
+  painter.drawImage(0,0,square);
+  painter.drawRect(0,0,SquareWidth,SquareWidth);
+
+  //    QPainter painter2(&wheel);
+  //    painter2.drawImage(0,0,source);
+
+  squareRegion = QRegion(m, m, SquareWidth, SquareWidth);
+}
+
+void ColorWheel::drawIndicator(const int &hue)
+{
+  QPainter painter(&wheel);
+  painter.setRenderHint(QPainter::Antialiasing);
+  painter.setPen(Qt::black);
+  painter.setBrush(Qt::NoBrush);
+
+  QPen pen = painter.pen();
+  pen.setWidth(2);
+  painter.setPen(pen);
+  qreal r = qMin(height(), width()) / 2.0;
+  painter.translate(r, r);
+  painter.rotate( -hue );
+  r = qMin(height(), width()) / 2.0 - margin - m_WheelWidth/2;
+  painter.drawEllipse(QPointF(r,0.0),4,4);
+}
+
+void ColorWheel::drawPicker(const QColor &color)
+{
+  QPainter painter(&wheel);
+  painter.setRenderHint(QPainter::Antialiasing);
+  QPen pen;
+
+  // region of the widget
+  int w = qMin(width(), height());
+  // radius of outer circle
+  qreal r = w/2-margin;
+  // radius of inner circle
+  qreal ir = r-m_WheelWidth;
+  // left corner of square
+  qreal m = w/2.0-ir/qSqrt(2);
+  painter.translate(m-4, m-4);
+  qreal SquareWidth = 2*ir/qSqrt(2);
+  qreal S = color.saturationF()*SquareWidth;
+  qreal V = color.valueF()*SquareWidth;
+
+  if(color.saturation() > 30 ||color.value() < 50){
+    pen.setColor(Qt::white);
+    }
+  pen.setWidth(2);
+  painter.setPen(pen);
+  painter.drawEllipse(S,V,8,8);
+}
+
+void ColorWheel::hueChanged(const int &hue)
+{
+  if( hue<0 )return;
+  int s = current.saturation();
+  int v = current.value();
+  current.setHsv(hue, s, v);
+  drawWheel(size());
+  drawSquare(hue);
+  drawIndicator(hue);
+  drawPicker(current);
+  repaint();
+  emit colorChange(current);
+}
+
+void ColorWheel::svChanged(const QColor &newcolor)
+{
+  int hue = current.hue();
+  current.setHsv(hue, newcolor.saturation(), newcolor.value());
+  drawWheel(size());
+  drawSquare(hue);
+  drawIndicator(hue);
+  drawPicker(newcolor);
+  repaint();
+  emit colorChange(current);
+}
diff --git a/GUI/Qt/External/ColorWheel/ColorWheel.h b/GUI/Qt/External/ColorWheel/ColorWheel.h
new file mode 100644
index 0000000..1902f6e
--- /dev/null
+++ b/GUI/Qt/External/ColorWheel/ColorWheel.h
@@ -0,0 +1,65 @@
+#ifndef COLORWHEEL_H
+#define COLORWHEEL_H
+
+/**
+ * From: https://github.com/liuyanghejerry/Qt-Plus/tree/master/develop/ColorWheel
+ * Imported: 03/16/2013
+ */
+
+#include <QWidget>
+#include <QPainter>
+#include <QResizeEvent>
+#include <QStyleOption>
+#include <QDebug>
+#include <QtCore/qmath.h>
+
+class ColorWheel : public QWidget
+{
+  Q_OBJECT
+
+  Q_PROPERTY(int wheelWidth READ wheelWidth WRITE setWheelWidth)
+
+
+public:
+  explicit ColorWheel(QWidget *parent = 0);
+
+  virtual QSize sizeHint () const;
+  virtual QSize minimumSizeHint () const;
+  QColor color();
+  void setColor(const QColor &color);
+
+  int wheelWidth() { return m_WheelWidth; }
+  void setWheelWidth(int value) { m_WheelWidth = value; this->update(); }
+
+signals:
+  QColor colorChange(const QColor &color);
+
+public slots:
+  void hueChanged(const int &hue);
+  void svChanged(const QColor &newcolor);
+protected:
+  void mousePressEvent(QMouseEvent *event);
+  void mouseMoveEvent(QMouseEvent *event);
+  void mouseReleaseEvent(QMouseEvent *event);
+  void resizeEvent(QResizeEvent *event);
+  void paintEvent(QPaintEvent *event);
+private:
+  QSize initSize;
+  QImage wheel;
+  bool mouseDown;
+  QPoint lastPos;
+  int margin;
+  int m_WheelWidth;
+  QRegion wheelRegion;
+  QRegion squareRegion;
+  QColor current;
+  bool inWheel;
+  bool inSquare;
+  QColor posColor(const QPoint &point);
+  void drawWheel(const QSize &newSize);
+  void drawIndicator(const int &hue);
+  void drawPicker(const QColor &color);
+  void drawSquare(const int &hue);
+};
+
+#endif // COLORWHEEL_H
diff --git a/GUI/Qt/ModelView/GMMTableModel.cxx b/GUI/Qt/ModelView/GMMTableModel.cxx
new file mode 100644
index 0000000..e7a7188
--- /dev/null
+++ b/GUI/Qt/ModelView/GMMTableModel.cxx
@@ -0,0 +1,351 @@
+#include "GMMTableModel.h"
+#include "SnakeWizardModel.h"
+#include "QtCheckBoxCoupling.h"
+#include "QtSpinBoxCoupling.h"
+#include <QCloseEvent>
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "UnsupervisedClustering.h"
+#include "GaussianMixtureModel.h"
+#include "ImageWrapperBase.h"
+#include "SNAPQtCommon.h"
+
+/* ============================================
+ * Qt MODEL Behind the Cluster Listing Table
+ * ============================================ */
+
+
+
+
+
+void GMMTableModel::SetParentModel(SnakeWizardModel *parent)
+{
+  m_ParentModel = parent;
+
+  LatentITKEventNotifier::connect(m_ParentModel,
+                                  SnakeWizardModel::GMMModifiedEvent(),
+                                  this, SLOT(onMixtureModelChange(const EventBucket &)));
+
+  LatentITKEventNotifier::connect(m_ParentModel,
+                                  itk::DeleteEvent(),
+                                  this, SLOT(onMixtureModelChange(const EventBucket &)));
+}
+
+void GMMTableModel::onMixtureModelChange(const EventBucket &b)
+{
+  if(b.HasEvent(itk::DeleteEvent()))
+    m_ParentModel = NULL;
+
+  this->layoutChanged();
+}
+
+GaussianMixtureModel *GMMTableModel::GetGMM() const
+{
+  if(!m_ParentModel)
+    return NULL;
+
+  // Get the unsupervised clustering class
+  UnsupervisedClustering *uc =
+    m_ParentModel->GetParent()->GetDriver()->GetClusteringEngine();
+
+  // If we are not in GMM mode, there is no uc!
+  if(!uc) return NULL;
+
+  // Get the number of clusters
+  return uc->GetMixtureModel();
+}
+
+int GMMTableModel::rowCount(const QModelIndex &parent) const
+{
+  // Get the number of clusters
+  GaussianMixtureModel *gmm = this->GetGMM();
+  return gmm ? gmm->GetNumberOfGaussians() : 0;
+}
+
+int GMMTableModel::columnCount(const QModelIndex &parent) const
+{
+  // Get the number of clusters
+  GaussianMixtureModel *gmm = this->GetGMM();
+  return gmm ? gmm->GetNumberOfComponents() + 3 : 0;
+}
+
+QVariant GMMTableModel::data(const QModelIndex &index, int role) const
+{
+  // Get the current row (cluster index)
+  int cluster = index.row();
+  Column ctype = columnType(index);
+
+  // Get a pointer to the GMM
+  GaussianMixtureModel *gmm = this->GetGMM();
+  assert(gmm);
+
+  // For first row, return checkboxes
+  if(role == Qt::CheckStateRole && ctype == COLUMN_PRIMARY)
+    {
+    return gmm->IsForeground(cluster) ? Qt::Checked : Qt::Unchecked;
+    }
+
+  else if((role == Qt::DisplayRole || role == Qt::EditRole) && ctype == COLUMN_WEIGHT)
+    {
+    double weight = gmm->GetWeight(cluster);
+    return QString::number(weight, 'f', 2);
+    }
+
+  else if((role == Qt::DisplayRole || role == Qt::EditRole) && ctype == COLUMN_MEAN)
+    {
+    double mean = m_ParentModel->GetClusterNativeMean(cluster, columnIndexInType(index));
+    return QString("%1").arg(mean, 8, 'g', -1);
+    }
+
+  else if((role == Qt::DisplayRole || role == Qt::EditRole)  && ctype == COLUMN_TRACE)
+    {
+    double var = m_ParentModel->GetClusterNativeTotalVariance(cluster);
+    return QString("%1").arg(var, 8, 'g', -1);
+    }
+
+  else if(role == Qt::TextAlignmentRole && ctype == COLUMN_PRIMARY)
+    {
+    return Qt::AlignCenter;
+    }
+
+  else if(role == Qt::TextAlignmentRole)
+    {
+    return Qt::AlignRight;
+    }
+
+  else return QVariant();
+}
+
+Qt::ItemFlags GMMTableModel::flags(const QModelIndex &index) const
+{
+  Qt::ItemFlags f = QAbstractTableModel::flags(index);
+  switch(columnType(index))
+    {
+    case COLUMN_PRIMARY:
+      return Qt::ItemIsUserCheckable | f;
+    case COLUMN_WEIGHT:
+      return Qt::ItemIsEditable | f;
+    case COLUMN_MEAN:
+      return Qt::ItemIsEditable | f;
+    default:
+      return f;
+    }
+}
+
+QVariant GMMTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+
+  if(orientation == Qt::Horizontal)
+    {
+    if(columnType(section) == COLUMN_PRIMARY)
+      {
+      if(role == Qt::DisplayRole)
+        return "Foreground";
+      else if(role == Qt::ToolTipRole)
+        return
+            "<p>Use this column to tag clusters as foreground or background.</p> "
+            "<p>Foreground clusters are added to the speed function; background "
+            "clusters are subtracted from the speed function.</p>";
+      }
+    else if(columnType(section) == COLUMN_WEIGHT)
+      {
+      if(role == Qt::DisplayRole)
+        return "Weight";
+      else if(role == Qt::ToolTipRole)
+        return
+            "<p>The relative weight of the cluster in the Gaussian mixture</p>";
+      }
+    else if(columnType(section) == COLUMN_TRACE)
+      {
+      if(role == Qt::DisplayRole)
+        return "Variance";
+      else if(role == Qt::ToolTipRole)
+        return
+            "<p>The overall variance of the cluster</p>"
+            "<p>Larger variance values result in smoother clusters</p>";
+      }
+    else if(columnType(section) == COLUMN_MEAN)
+      {
+      if(role == Qt::DisplayRole)
+        return QString("%1[%2]").arg((QChar) 0x03BC).arg(section-1);
+      else if(role == Qt::ToolTipRole)
+        {
+        // Get the component information
+        SnakeWizardModel::ComponentInfo ci =
+            m_ParentModel->GetLayerAndIndexForNthComponent(section-COLUMN_MEAN);
+        QString nick = from_utf8(ci.ImageWrapper->GetNickname());
+        return QString("<html><body>Cluster mean for image <b>%1</b>"
+                       " component <b>%2</b></body></html>").arg(nick).arg(ci.ComponentIndex);
+        }
+      }
+    }
+
+  else if(orientation == Qt::Vertical)
+    {
+    if(role == Qt::DisplayRole)
+      return QString("Cluster %1").arg(section+1);
+    else if(role == Qt::DecorationRole)
+      {
+      Vector3d rgb = ColorLabelTable::GetDefaultColorLabel(section+1).GetRGBAsDoubleVector();
+      return CreateColorBoxIcon(16, 16, to_unsigned_int(rgb * 255.0));
+      }
+    }
+
+  return QVariant();
+}
+
+bool GMMTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+  GaussianMixtureModel *gmm = this->GetGMM();
+  int ngauss = gmm->GetNumberOfGaussians()-1;
+
+  if(columnType(index) == COLUMN_PRIMARY)
+    {
+    bool state = value.toBool();
+
+    // TODO: it would be nice to do this in the mixture model class, without having to
+    // have a special method in the SpeedWizardModel class
+    if(m_ParentModel->SetClusterForegroundState(index.row(), state))
+      {
+      emit dataChanged(this->index(0,index.column()), this->index(ngauss, index.column()));
+      return true;
+      }
+    }
+  else if(columnType(index) == COLUMN_WEIGHT)
+    {
+    double weight = value.toDouble();
+    if(m_ParentModel->SetClusterWeight(index.row(), weight))
+      {
+      emit dataChanged(this->index(0,index.column()), this->index(ngauss, index.column()));
+      return true;
+      }
+    }
+
+  else if(columnType(index) == COLUMN_MEAN)
+    {
+    double mean = value.toDouble();
+    if(m_ParentModel->SetClusterNativeMean(
+         index.row(), columnIndexInType(index), mean))
+      {
+      emit dataChanged(index, index);
+      return true;
+      }
+    }
+
+  return false;
+}
+
+
+GMMTableModel::GMMTableModel(QObject *parent)
+  : QAbstractTableModel(parent)
+{
+  m_ParentModel = NULL;
+}
+
+GMMTableModel::Column GMMTableModel::columnType(int k) const
+{
+  GaussianMixtureModel *gmm = this->GetGMM();
+  if(!gmm)
+    return COLUMN_NONE;
+
+  int n = gmm->GetNumberOfComponents();
+
+  if(k == 0)
+    return COLUMN_PRIMARY;
+  else if(k == 1)
+    return COLUMN_WEIGHT;
+  else if(k >= 2 && k < 2 + n)
+    return COLUMN_MEAN;
+  else if (k == 2 + n)
+    return COLUMN_TRACE;
+  else
+    return COLUMN_NONE;
+}
+
+int GMMTableModel::columnIndexInType(int k) const
+{
+  if(columnType(k) == COLUMN_MEAN)
+    return k - 2;
+  else
+    return 0;
+}
+
+
+
+GMMItemDelegate::GMMItemDelegate(QObject *parent)
+  : QItemDelegate(parent)
+{
+
+}
+
+GMMTableModel::Column GMMItemDelegate::columnType(const QModelIndex &index) const
+{
+  const GMMTableModel *model = dynamic_cast<const GMMTableModel *>(index.model());
+  return model->columnType(index);
+}
+
+
+QWidget *GMMItemDelegate
+::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+
+  if(columnType(index) == GMMTableModel::COLUMN_WEIGHT)
+    {
+    QDoubleSpinBox *editor = new QDoubleSpinBox(parent);
+    editor->setMinimum(0.0);
+    editor->setMaximum(1.0);
+    editor->setSingleStep(0.01);
+    editor->setDecimals(2);
+
+    return editor;
+    }
+  else
+    {
+    return QItemDelegate::createEditor(parent, option, index);
+    }
+}
+
+void
+GMMItemDelegate
+::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+  if(columnType(index) == GMMTableModel::COLUMN_WEIGHT)
+    {
+    double value = index.model()->data(index, Qt::EditRole).toDouble();
+    QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
+    spinBox->setValue(value);
+    }
+  else
+    {
+    QItemDelegate::setEditorData(editor, index);
+    }
+}
+
+void GMMItemDelegate
+::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+{
+  if(columnType(index) == GMMTableModel::COLUMN_WEIGHT)
+    {
+    QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
+    spinBox->interpretText();
+    double value = spinBox->value();
+    model->setData(index, value, Qt::EditRole);
+    }
+  else
+    {
+    QItemDelegate::setModelData(editor, model, index);
+    }
+}
+
+void GMMItemDelegate
+::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+  if(columnType(index) == GMMTableModel::COLUMN_WEIGHT)
+    {
+    editor->setGeometry(option.rect);
+    }
+  else
+    {
+    QItemDelegate::updateEditorGeometry(editor, option, index);
+    }
+}
diff --git a/GUI/Qt/ModelView/GMMTableModel.h b/GUI/Qt/ModelView/GMMTableModel.h
new file mode 100644
index 0000000..be8b037
--- /dev/null
+++ b/GUI/Qt/ModelView/GMMTableModel.h
@@ -0,0 +1,91 @@
+#ifndef GMMTABLEMODEL_H
+#define GMMTABLEMODEL_H
+
+#include <QDialog>
+#include <QAbstractTableModel>
+#include <QItemDelegate>
+#include <SNAPCommon.h>
+
+class SnakeWizardModel;
+class ThresholdSettingsRenderer;
+class EdgePreprocessingSettingsRenderer;
+class GaussianMixtureModel;
+class EventBucket;
+
+/**
+ * The qt model for the GMM cluster list
+ */
+class GMMTableModel : public QAbstractTableModel
+{
+  Q_OBJECT
+
+public:
+
+  /** Classes of columns in the table */
+  enum Column {
+    COLUMN_PRIMARY,
+    COLUMN_TRACE,
+    COLUMN_MEAN,
+    COLUMN_WEIGHT,
+    COLUMN_NONE
+  };
+
+  GMMTableModel(QObject *parent);
+
+  Column columnType(int column) const;
+  Column columnType(const QModelIndex &index) const
+    { return columnType(index.column()); }
+
+  int columnIndexInType(int column) const;
+  int columnIndexInType(const QModelIndex &index) const
+    { return columnIndexInType(index.column()); }
+
+  virtual int rowCount(const QModelIndex &parent) const;
+
+  virtual int columnCount(const QModelIndex &parent) const;
+
+  virtual QVariant data(const QModelIndex &index, int role) const;
+
+  virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+
+  virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+  virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
+
+  void SetParentModel(SnakeWizardModel *parent);
+
+public slots:
+
+  void onMixtureModelChange(const EventBucket &);
+
+protected:
+
+  SnakeWizardModel *m_ParentModel;
+  GaussianMixtureModel *GetGMM() const;
+};
+
+/**
+ * The delegate model for the same
+ */
+class GMMItemDelegate : public QItemDelegate
+{
+  Q_OBJECT
+
+public:
+  GMMItemDelegate(QObject *parent = 0);
+
+  GMMTableModel::Column columnType(const QModelIndex &index) const;
+
+  QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+                        const QModelIndex &index) const;
+
+  void setEditorData(QWidget *editor, const QModelIndex &index) const;
+  void setModelData(QWidget *editor, QAbstractItemModel *model,
+                    const QModelIndex &index) const;
+
+  void updateEditorGeometry(QWidget *editor,
+                            const QStyleOptionViewItem &option, const QModelIndex &index) const;
+};
+
+
+#endif // GMMTABLEMODEL_H
diff --git a/GUI/Qt/Resources/COPYING b/GUI/Qt/Resources/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/GUI/Qt/Resources/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/GUI/Qt/Resources/SNAPResources.qrc b/GUI/Qt/Resources/SNAPResources.qrc
new file mode 100644
index 0000000..f11067a
--- /dev/null
+++ b/GUI/Qt/Resources/SNAPResources.qrc
@@ -0,0 +1,115 @@
+<RCC>
+    <qresource prefix="/root">
+        <file>paintbrush.gif</file>
+        <file>zoom3d.gif</file>
+        <file alias="zoom.gif">zoom.gif</file>
+        <file>spray.gif</file>
+        <file>snake.gif</file>
+        <file>screencapture2.gif</file>
+        <file>screencapture.gif</file>
+        <file>scalpel.gif</file>
+        <file>rotate3dTiny.gif</file>
+        <file>rotate3d.gif</file>
+        <file>rc.gif</file>
+        <file>rb.gif</file>
+        <file>ra.gif</file>
+        <file>poly.gif</file>
+        <file>outputintensity.gif</file>
+        <file>logo.gif</file>
+        <file>logo_new.gif</file>
+        <file>itkLogoSmallTransparentBackground.gif</file>
+        <file>formula03.gif</file>
+        <file>formula02.gif</file>
+        <file>formula01.gif</file>
+        <file>crosshair3Dtiny.gif</file>
+        <file>crosshair3D.gif</file>
+        <file alias="crosshair.gif">crosshair.gif</file>
+        <file alias="fltkbutton.png">fltkbutton.png</file>
+        <file alias="fltkbutton_pressed.png">fltkbutton_pressed.png</file>
+        <file alias="fltkpanel.png">fltkpanel.png</file>
+        <file alias="icontabwidget.css">icontabwidget.css</file>
+        <file alias="itksnap.css">itksnap.css</file>
+        <file>combo_all_labels.png</file>
+        <file>combo_visible_labels.png</file>
+        <file>dlg_error_32.png</file>
+        <file>dlg_warning_32.png</file>
+        <file>popup_edit_16.png</file>
+        <file>popup_ok_16.png</file>
+        <file>popup_paste_16.png</file>
+        <file>popup_clear_16.png</file>
+        <file>popup_delete_16.png</file>
+        <file>popup_split_16.png</file>
+        <file>popup_undo_16.png</file>
+        <file>delete_22.png</file>
+        <file alias="tools.png">tools.png</file>
+        <file>arrow_down_16.png</file>
+        <file>arrow_up_16.png</file>
+        <file>media-playback-pause-4.png</file>
+        <file>media-playback-start-4.png</file>
+        <file>media-playback-stop-4.png</file>
+        <file>media-seek-backward-4.png</file>
+        <file>media-skip-forward-4.png</file>
+        <file>media-playback-singlestep.png</file>
+        <file>edgefunction.png</file>
+        <file>revertaxis_16.png</file>
+        <file>dl_fourviews.png</file>
+        <file>dl_3d.png</file>
+        <file>dl_axial.png</file>
+        <file>dl_coronal.png</file>
+        <file>dl_sagittal.png</file>
+        <file>dl_toolbox.png</file>
+        <file>expand_16.png</file>
+        <file>brush_shape_adaptive.png</file>
+        <file>brush_shape_round.png</file>
+        <file>brush_shape_square.png</file>
+        <file>menu-arrow.png</file>
+        <file>network-wireless.png</file>
+        <file>mb_left.png</file>
+        <file>undo_22.png</file>
+        <file>redo_22.png</file>
+        <file>snap_splash_172.png</file>
+        <file>speed_bluegray.png</file>
+        <file>speed_redoverlay.png</file>
+        <file>layout_overlay_16.png</file>
+        <file>layout_tile_16.png</file>
+        <file>layer_Inspector_16.png</file>
+        <file>layer_invisible_16.png</file>
+        <file>layer_visible_16.png</file>
+        <file>triangle_small_down_16.png</file>
+        <file>triangle_small_right_16.png</file>
+        <file>lock_blue_16.png</file>
+        <file>lock_gray_16.png</file>
+        <file>fancyslider.css</file>
+        <file>save_22.png</file>
+        <file>open_popup_16.png</file>
+        <file>icons8_pin_16.png</file>
+        <file>icons8_unpin_16.png</file>
+        <file>icons8_down_18.png</file>
+        <file>icons8_invisible_16.png</file>
+        <file>icons8_up_18.png</file>
+        <file>icons8_visible_16.png</file>
+        <file>icons8_close_16.png</file>
+        <file>logo_square.png</file>
+        <file>logo_square_shadow.png</file>
+        <file>icons8_fantasy_16.png</file>
+        <file>COPYING</file>
+        <file>license.txt</file>
+        <file>icons8_zoomin_16.png</file>
+        <file>icons8_zoomout_16.png</file>
+        <file>credits.html</file>
+        <file>thresh_both.png</file>
+        <file>thresh_lower.png</file>
+        <file>thresh_upper.png</file>
+        <file>view-refresh-4.png</file>
+        <file>media-playback-start-1x-4.png</file>
+        <file>media-playback-start-10x-4.png</file>
+        <file>open_22.png</file>
+        <file>crosshair_cursor_bitmap.png</file>
+        <file>crosshair_cursor_mask.png</file>
+    </qresource>
+    <qresource prefix="/snapres">
+        <file>snapres/EdgeForcesExample.png</file>
+        <file>snapres/RegionForcesExample.png</file>
+        <file>snapres/SnakeParameterPreviewCurve.txt</file>
+    </qresource>
+</RCC>
diff --git a/GUI/Qt/Resources/arrow_down_16.png b/GUI/Qt/Resources/arrow_down_16.png
new file mode 100644
index 0000000..f5276c1
Binary files /dev/null and b/GUI/Qt/Resources/arrow_down_16.png differ
diff --git a/GUI/Qt/Resources/arrow_up_16.png b/GUI/Qt/Resources/arrow_up_16.png
new file mode 100644
index 0000000..77b58d8
Binary files /dev/null and b/GUI/Qt/Resources/arrow_up_16.png differ
diff --git a/GUI/Qt/Resources/brush_shape_adaptive.png b/GUI/Qt/Resources/brush_shape_adaptive.png
new file mode 100644
index 0000000..5629fa2
Binary files /dev/null and b/GUI/Qt/Resources/brush_shape_adaptive.png differ
diff --git a/GUI/Qt/Resources/brush_shape_round.png b/GUI/Qt/Resources/brush_shape_round.png
new file mode 100644
index 0000000..8638faa
Binary files /dev/null and b/GUI/Qt/Resources/brush_shape_round.png differ
diff --git a/GUI/Qt/Resources/brush_shape_square.png b/GUI/Qt/Resources/brush_shape_square.png
new file mode 100644
index 0000000..ac65437
Binary files /dev/null and b/GUI/Qt/Resources/brush_shape_square.png differ
diff --git a/GUI/Qt/Resources/combo_all_labels.png b/GUI/Qt/Resources/combo_all_labels.png
new file mode 100644
index 0000000..659bcaa
Binary files /dev/null and b/GUI/Qt/Resources/combo_all_labels.png differ
diff --git a/GUI/Qt/Resources/combo_visible_labels.png b/GUI/Qt/Resources/combo_visible_labels.png
new file mode 100644
index 0000000..d6e40c1
Binary files /dev/null and b/GUI/Qt/Resources/combo_visible_labels.png differ
diff --git a/GUI/Qt/Resources/configure.png b/GUI/Qt/Resources/configure.png
new file mode 100644
index 0000000..37288ce
Binary files /dev/null and b/GUI/Qt/Resources/configure.png differ
diff --git a/GUI/Qt/Resources/credits.html b/GUI/Qt/Resources/credits.html
new file mode 100644
index 0000000..2edd1e0
--- /dev/null
+++ b/GUI/Qt/Resources/credits.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" />
+<style type="text/css">
+p, li { white-space: pre-wrap; }
+h1, h2, h3, h4, h5, h6 { margin-top:1.5em; margin-bottom:0.6em; }:
+h3 { text-transform:uppercase; color:#666; font-weight:bold; letter-spacing:0.5px; font-size:0.9em; border-bottom:1px solid #999; margin-right:0em; }
+</style>
+</head>
+<body style="font-family:'Lucida Grande'; font-size:12px; font-weight:400; font-style:normal;">
+<h3>ITK-SNAP 3.x Team (2011 - Present)</h3>
+<p>Paul A. Yushkevich (University of Pennsylvania) - PI and Lead Developer <br />Guido Gerig (University of Utah) - Co-PI <br />Octavian Soldea (University of Pennsylvania) - Developer <br />Yang Gao (University of Utah) - Developer <br />Baohua Wu (University of Pennsylvania) - Developer <br />Michael Stauffer (University of Pennsylvania) - Developer <br />Supported by the U.S. National Institute of Biomedical Imaging and BioEngineering through grant R01 EB014346
+</p>
+<div class='vspace'></div><h3>ITK-SNAP 2.x Team (2004 - 2012)</h3>
+<p>Paul A. Yushkevich (University of Pennsylvania) - Lead Developer <br />Hui Zhang (University of Pennsylvania) - Developer  <br />Casey Goodlett (University of Utah) - Contributor  <br />Timothy Burke - Contributor  <br />Nicholas Tustison - Contributor  <br />Supported by the U.S. National Institute of Biomedical Imaging and BioEngineering and the NIH Blueprint for Neuroscience through grant R03 EB008200
+</p>
+<div class='vspace'></div><h3>SNAP/ITK Integration (2003-2004)</h3>
+<p>Paul A. Yushkevich (University of Pennsylvania) - Technical Director <br />Daniel S. Fritsch - Contract PI  <br />Guido Gerig (University of Utah) - Scientific Director  <br />Stephen R. Aylward (Kitware) - Consultant <br />Supported by the U.S. National Library of Medicine through PO 467-MZ-202446-1
+</p>
+<div class='vspace'></div><h3>Original SNAP/IRIS Team (199x - 2003)</h3>
+<p>Guido Gerig (University of Utah) - Scientific Director <br />Silvio Turello, Joachim Schlegel, Gabor Szekely (ETH Zurich) - Original AVS Module <br />Chris Wynn, Arun Neelamkavil, David Gregg, Eric Larsen, Sanjay Sthapit (UNC Chapel Hill) - IRIS 1999 Project <br />Sean Ho, Ashraf Farrag, Amy Henderson, Robin Munesato, Ming Yu (UNC Chapel Hill) - IRIS 2000 Project <br />Nathan Moon, Thorsten Scheuermann, Konstantin Bobkov, Nathan Talbert, Yongjik Kim (UNC Chapel Hill) - SnAP 2002 Proje [...]
+</p><h3>Special Thanks</h3>
+<p>Terry S. Yoo (NLM) <br />Zohara Cohen (NIBIB) <br />Luis Ibanez (Kitware) <br />Joshua Cates (University of Utah)  <br />James C. Gee (University of Pennsylvania)  <br />All who generously contribute to ITK, VTK, FLTK, and SNAP
+</p>
+</body>
+</html>
diff --git a/GUI/Qt/Resources/crosshair.gif b/GUI/Qt/Resources/crosshair.gif
new file mode 100644
index 0000000..d7e1b5d
Binary files /dev/null and b/GUI/Qt/Resources/crosshair.gif differ
diff --git a/GUI/Qt/Resources/crosshair3D.gif b/GUI/Qt/Resources/crosshair3D.gif
new file mode 100644
index 0000000..e5751a0
Binary files /dev/null and b/GUI/Qt/Resources/crosshair3D.gif differ
diff --git a/UserInterface/MainComponents/Artwork/crosshair3Dtiny.gif b/GUI/Qt/Resources/crosshair3Dtiny.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/crosshair3Dtiny.gif
rename to GUI/Qt/Resources/crosshair3Dtiny.gif
diff --git a/GUI/Qt/Resources/crosshair_cursor_bitmap.png b/GUI/Qt/Resources/crosshair_cursor_bitmap.png
new file mode 100644
index 0000000..4b69c29
Binary files /dev/null and b/GUI/Qt/Resources/crosshair_cursor_bitmap.png differ
diff --git a/GUI/Qt/Resources/crosshair_cursor_mask.png b/GUI/Qt/Resources/crosshair_cursor_mask.png
new file mode 100644
index 0000000..89fa501
Binary files /dev/null and b/GUI/Qt/Resources/crosshair_cursor_mask.png differ
diff --git a/GUI/Qt/Resources/delete_22.png b/GUI/Qt/Resources/delete_22.png
new file mode 100644
index 0000000..4ffcaed
Binary files /dev/null and b/GUI/Qt/Resources/delete_22.png differ
diff --git a/GUI/Qt/Resources/dl_3d.png b/GUI/Qt/Resources/dl_3d.png
new file mode 100644
index 0000000..8f80544
Binary files /dev/null and b/GUI/Qt/Resources/dl_3d.png differ
diff --git a/GUI/Qt/Resources/dl_axial.png b/GUI/Qt/Resources/dl_axial.png
new file mode 100644
index 0000000..3c910d7
Binary files /dev/null and b/GUI/Qt/Resources/dl_axial.png differ
diff --git a/GUI/Qt/Resources/dl_coronal.png b/GUI/Qt/Resources/dl_coronal.png
new file mode 100644
index 0000000..ae9757d
Binary files /dev/null and b/GUI/Qt/Resources/dl_coronal.png differ
diff --git a/GUI/Qt/Resources/dl_fourviews.png b/GUI/Qt/Resources/dl_fourviews.png
new file mode 100644
index 0000000..8a2930f
Binary files /dev/null and b/GUI/Qt/Resources/dl_fourviews.png differ
diff --git a/GUI/Qt/Resources/dl_sagittal.png b/GUI/Qt/Resources/dl_sagittal.png
new file mode 100644
index 0000000..6361237
Binary files /dev/null and b/GUI/Qt/Resources/dl_sagittal.png differ
diff --git a/GUI/Qt/Resources/dl_toolbox.png b/GUI/Qt/Resources/dl_toolbox.png
new file mode 100644
index 0000000..a6aca77
Binary files /dev/null and b/GUI/Qt/Resources/dl_toolbox.png differ
diff --git a/GUI/Qt/Resources/dlg_error_32.png b/GUI/Qt/Resources/dlg_error_32.png
new file mode 100644
index 0000000..1ef2b6f
Binary files /dev/null and b/GUI/Qt/Resources/dlg_error_32.png differ
diff --git a/GUI/Qt/Resources/dlg_warning_32.png b/GUI/Qt/Resources/dlg_warning_32.png
new file mode 100644
index 0000000..c506b52
Binary files /dev/null and b/GUI/Qt/Resources/dlg_warning_32.png differ
diff --git a/GUI/Qt/Resources/edgefunction.png b/GUI/Qt/Resources/edgefunction.png
new file mode 100644
index 0000000..3a1877c
Binary files /dev/null and b/GUI/Qt/Resources/edgefunction.png differ
diff --git a/GUI/Qt/Resources/expand_16.png b/GUI/Qt/Resources/expand_16.png
new file mode 100644
index 0000000..034513a
Binary files /dev/null and b/GUI/Qt/Resources/expand_16.png differ
diff --git a/GUI/Qt/Resources/fancyslider.css b/GUI/Qt/Resources/fancyslider.css
new file mode 100644
index 0000000..01ed53c
--- /dev/null
+++ b/GUI/Qt/Resources/fancyslider.css
@@ -0,0 +1,53 @@
+QSlider::groove:horizontal {
+border: 1px solid #bbb;
+background: white;
+height: 7px;
+border-radius: 4px;
+}
+
+QSlider::sub-page:horizontal {
+background: #gradient#;
+border: 1px solid #777;
+height: 7px;
+border-radius: 4px;
+}
+
+QSlider::add-page:horizontal {
+background: #fff;
+border: 1px solid #777;
+height: 7px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+    stop:0 #eee, stop:1 #ccc);
+border: 1px solid #777;
+width: 13px;
+margin-top: -2px;
+margin-bottom: -2px;
+border-radius: 4px;
+}
+
+QSlider::handle:horizontal:hover {
+background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
+    stop:0 #fff, stop:1 #ddd);
+border: 1px solid #444;
+border-radius: 4px;
+}
+
+QSlider::sub-page:horizontal:disabled {
+background: #bbb;
+border-color: #999;
+}
+
+QSlider::add-page:horizontal:disabled {
+background: #eee;
+border-color: #999;
+}
+
+QSlider::handle:horizontal:disabled {
+background: #eee;
+border: 1px solid #aaa;
+border-radius: 4px;
+}
diff --git a/GUI/Qt/Resources/fltkbutton.png b/GUI/Qt/Resources/fltkbutton.png
new file mode 100644
index 0000000..c53357a
Binary files /dev/null and b/GUI/Qt/Resources/fltkbutton.png differ
diff --git a/GUI/Qt/Resources/fltkbutton_pressed.png b/GUI/Qt/Resources/fltkbutton_pressed.png
new file mode 100644
index 0000000..98e1abc
Binary files /dev/null and b/GUI/Qt/Resources/fltkbutton_pressed.png differ
diff --git a/GUI/Qt/Resources/fltkpanel.png b/GUI/Qt/Resources/fltkpanel.png
new file mode 100644
index 0000000..9f51258
Binary files /dev/null and b/GUI/Qt/Resources/fltkpanel.png differ
diff --git a/UserInterface/MainComponents/Artwork/formula01.gif b/GUI/Qt/Resources/formula01.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/formula01.gif
rename to GUI/Qt/Resources/formula01.gif
diff --git a/UserInterface/MainComponents/Artwork/formula02.gif b/GUI/Qt/Resources/formula02.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/formula02.gif
rename to GUI/Qt/Resources/formula02.gif
diff --git a/UserInterface/MainComponents/Artwork/formula03.gif b/GUI/Qt/Resources/formula03.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/formula03.gif
rename to GUI/Qt/Resources/formula03.gif
diff --git a/GUI/Qt/Resources/icons8_close_16.png b/GUI/Qt/Resources/icons8_close_16.png
new file mode 100644
index 0000000..af6e5c1
Binary files /dev/null and b/GUI/Qt/Resources/icons8_close_16.png differ
diff --git a/GUI/Qt/Resources/icons8_down_18.png b/GUI/Qt/Resources/icons8_down_18.png
new file mode 100644
index 0000000..09c744e
Binary files /dev/null and b/GUI/Qt/Resources/icons8_down_18.png differ
diff --git a/GUI/Qt/Resources/icons8_fantasy_16.png b/GUI/Qt/Resources/icons8_fantasy_16.png
new file mode 100644
index 0000000..29fd59d
Binary files /dev/null and b/GUI/Qt/Resources/icons8_fantasy_16.png differ
diff --git a/GUI/Qt/Resources/icons8_invisible_16.png b/GUI/Qt/Resources/icons8_invisible_16.png
new file mode 100644
index 0000000..a8595a3
Binary files /dev/null and b/GUI/Qt/Resources/icons8_invisible_16.png differ
diff --git a/GUI/Qt/Resources/icons8_pin_16.png b/GUI/Qt/Resources/icons8_pin_16.png
new file mode 100644
index 0000000..4117463
Binary files /dev/null and b/GUI/Qt/Resources/icons8_pin_16.png differ
diff --git a/GUI/Qt/Resources/icons8_unpin_16.png b/GUI/Qt/Resources/icons8_unpin_16.png
new file mode 100644
index 0000000..3dc5ad2
Binary files /dev/null and b/GUI/Qt/Resources/icons8_unpin_16.png differ
diff --git a/GUI/Qt/Resources/icons8_up_18.png b/GUI/Qt/Resources/icons8_up_18.png
new file mode 100644
index 0000000..32cb120
Binary files /dev/null and b/GUI/Qt/Resources/icons8_up_18.png differ
diff --git a/GUI/Qt/Resources/icons8_visible_16.png b/GUI/Qt/Resources/icons8_visible_16.png
new file mode 100644
index 0000000..46d5695
Binary files /dev/null and b/GUI/Qt/Resources/icons8_visible_16.png differ
diff --git a/GUI/Qt/Resources/icons8_zoomin_16.png b/GUI/Qt/Resources/icons8_zoomin_16.png
new file mode 100644
index 0000000..8e4d606
Binary files /dev/null and b/GUI/Qt/Resources/icons8_zoomin_16.png differ
diff --git a/GUI/Qt/Resources/icons8_zoomout_16.png b/GUI/Qt/Resources/icons8_zoomout_16.png
new file mode 100644
index 0000000..109cb8f
Binary files /dev/null and b/GUI/Qt/Resources/icons8_zoomout_16.png differ
diff --git a/GUI/Qt/Resources/icontabwidget.css b/GUI/Qt/Resources/icontabwidget.css
new file mode 100644
index 0000000..9e6f9a8
--- /dev/null
+++ b/GUI/Qt/Resources/icontabwidget.css
@@ -0,0 +1,30 @@
+* {
+  icon-size: 28px;
+  text-align: center;
+}
+
+QTabBar {
+  left: 0px; right: 0px;
+  subcontrol-position: top left;
+  subcontrol-origin: margin;
+}
+
+QTabBar::tab {
+  min-width: 1ex;
+  border-bottom-color: gray;
+  border-top: 1px solid rgb(108, 108, 108);
+  border-bottom: 0px;
+  border-left: 1px solid rgb(201, 201, 201);
+  border-right: 1px solid rgb(201, 201, 201);
+  background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.0394089 rgba(245, 245, 245, 255), stop:0.487685 rgba(226, 226, 226, 255), stop:0.502463 rgba(215, 215, 215, 255), stop:1 rgba(245, 245, 245, 255));
+  width: 30px;
+}
+
+QTabBar::tab:hover, QTabBar::tab:selected {
+  background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.0394089 rgba(214, 228, 245, 255), stop:0.487685 rgba(193, 205, 221, 255), stop:0.502463 rgba(182, 193, 207, 255), stop:1 rgba(215, 228, 245, 255));
+}
+
+QTabWidget::pane {
+	border-top: 1px solid rgb(108, 108, 108);
+	border-bottom: 1px solid rgb(108, 108, 108);
+}
diff --git a/UserInterface/MainComponents/Artwork/itkLogoSmallTransparentBackground.gif b/GUI/Qt/Resources/itkLogoSmallTransparentBackground.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/itkLogoSmallTransparentBackground.gif
rename to GUI/Qt/Resources/itkLogoSmallTransparentBackground.gif
diff --git a/GUI/Qt/Resources/itksnap.css b/GUI/Qt/Resources/itksnap.css
new file mode 100644
index 0000000..b6ce270
--- /dev/null
+++ b/GUI/Qt/Resources/itksnap.css
@@ -0,0 +1,35 @@
+QMainWindow {
+  background-color: rgb(248,248,248);
+}
+/*
+QGroupBox {
+  border-image: url(:/root/fltkpanel.png) repeat;
+  border-top-width: 8px;
+  border-bottom-width: 8px;
+  border-left-width: 2px;
+  border-right-width: 2px;
+  background-origin: content;
+  padding-top: -3px;
+  padding-bottom: -3px;
+  padding-left: 3px;
+  padding-right: 3px;
+  margin-top: 2.5ex;
+  font-weight: bold;
+}
+*/
+QGroupBox {
+  background-origin: content;
+  margin-top: 2.5ex;
+  font-weight: bold;
+  font-size: 12px;
+  color: rgb(30,30,160);
+  background-color: rgb(237,237,237);
+  padding: 5px;
+  border-radius: 4px;
+  border: 1px solid rgb(130,130,130);
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+}
+
diff --git a/GUI/Qt/Resources/itksnap.qss b/GUI/Qt/Resources/itksnap.qss
new file mode 100644
index 0000000..f39fb7b
--- /dev/null
+++ b/GUI/Qt/Resources/itksnap.qss
@@ -0,0 +1,38 @@
+QToolButton
+{
+    border-image: url(:/root/fltkbutton.png) repeat;
+    border-top-width: 8px;
+    border-bottom-width: 8px;
+    border-left-width: 3px;
+    border-right-width: 3px;
+    background-origin: content;
+    padding-top: -8px;
+    padding-bottom: -8px;
+    padding-left: -3px;
+    padding-right: -3px;
+}
+
+QToolButton:pressed, QToolButton:checked
+{
+    border-image: url(:/root/fltkbutton_pressed.png) repeat;
+};
+
+QGroupBox {
+  border-image: url(:/root/fltkpanel.png) repeat;
+  border-top-width: 8px;
+  border-bottom-width: 8px;
+  border-left-width: 2px;
+  border-right-width: 2px;
+  background-origin: content;
+  padding-top: -3px;
+  padding-bottom: -3px;
+  padding-left: 3px;
+  padding-right: 3px;
+  margin-top: 2.5ex;
+  font-weight: bold;
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+};
+
diff --git a/GUI/Qt/Resources/layer_Inspector_16.png b/GUI/Qt/Resources/layer_Inspector_16.png
new file mode 100644
index 0000000..3dcb063
Binary files /dev/null and b/GUI/Qt/Resources/layer_Inspector_16.png differ
diff --git a/GUI/Qt/Resources/layer_invisible_16.png b/GUI/Qt/Resources/layer_invisible_16.png
new file mode 100644
index 0000000..c177f6d
Binary files /dev/null and b/GUI/Qt/Resources/layer_invisible_16.png differ
diff --git a/GUI/Qt/Resources/layer_visible_16.png b/GUI/Qt/Resources/layer_visible_16.png
new file mode 100644
index 0000000..d5ce135
Binary files /dev/null and b/GUI/Qt/Resources/layer_visible_16.png differ
diff --git a/GUI/Qt/Resources/layout_overlay_16.png b/GUI/Qt/Resources/layout_overlay_16.png
new file mode 100644
index 0000000..43c8e98
Binary files /dev/null and b/GUI/Qt/Resources/layout_overlay_16.png differ
diff --git a/GUI/Qt/Resources/layout_tile_16.png b/GUI/Qt/Resources/layout_tile_16.png
new file mode 100644
index 0000000..496c833
Binary files /dev/null and b/GUI/Qt/Resources/layout_tile_16.png differ
diff --git a/GUI/Qt/Resources/license.txt b/GUI/Qt/Resources/license.txt
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/GUI/Qt/Resources/license.txt
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/GUI/Qt/Resources/lock_blue_16.png b/GUI/Qt/Resources/lock_blue_16.png
new file mode 100644
index 0000000..7eb18e0
Binary files /dev/null and b/GUI/Qt/Resources/lock_blue_16.png differ
diff --git a/GUI/Qt/Resources/lock_gray_16.png b/GUI/Qt/Resources/lock_gray_16.png
new file mode 100644
index 0000000..2834bd3
Binary files /dev/null and b/GUI/Qt/Resources/lock_gray_16.png differ
diff --git a/UserInterface/MainComponents/Artwork/logo.gif b/GUI/Qt/Resources/logo.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/logo.gif
rename to GUI/Qt/Resources/logo.gif
diff --git a/UserInterface/MainComponents/Artwork/logo_new.gif b/GUI/Qt/Resources/logo_new.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/logo_new.gif
rename to GUI/Qt/Resources/logo_new.gif
diff --git a/GUI/Qt/Resources/logo_square.png b/GUI/Qt/Resources/logo_square.png
new file mode 100644
index 0000000..5a723d6
Binary files /dev/null and b/GUI/Qt/Resources/logo_square.png differ
diff --git a/GUI/Qt/Resources/logo_square_shadow.png b/GUI/Qt/Resources/logo_square_shadow.png
new file mode 100644
index 0000000..04c2da4
Binary files /dev/null and b/GUI/Qt/Resources/logo_square_shadow.png differ
diff --git a/GUI/Qt/Resources/mb_left.png b/GUI/Qt/Resources/mb_left.png
new file mode 100644
index 0000000..aa51160
Binary files /dev/null and b/GUI/Qt/Resources/mb_left.png differ
diff --git a/GUI/Qt/Resources/media-playback-pause-4.png b/GUI/Qt/Resources/media-playback-pause-4.png
new file mode 100644
index 0000000..6516654
Binary files /dev/null and b/GUI/Qt/Resources/media-playback-pause-4.png differ
diff --git a/GUI/Qt/Resources/media-playback-singlestep.png b/GUI/Qt/Resources/media-playback-singlestep.png
new file mode 100644
index 0000000..a5a9a48
Binary files /dev/null and b/GUI/Qt/Resources/media-playback-singlestep.png differ
diff --git a/GUI/Qt/Resources/media-playback-start-10x-4.png b/GUI/Qt/Resources/media-playback-start-10x-4.png
new file mode 100644
index 0000000..806dfc7
Binary files /dev/null and b/GUI/Qt/Resources/media-playback-start-10x-4.png differ
diff --git a/GUI/Qt/Resources/media-playback-start-1x-4.png b/GUI/Qt/Resources/media-playback-start-1x-4.png
new file mode 100644
index 0000000..f6cfdc6
Binary files /dev/null and b/GUI/Qt/Resources/media-playback-start-1x-4.png differ
diff --git a/GUI/Qt/Resources/media-playback-start-4.png b/GUI/Qt/Resources/media-playback-start-4.png
new file mode 100644
index 0000000..665f5e6
Binary files /dev/null and b/GUI/Qt/Resources/media-playback-start-4.png differ
diff --git a/GUI/Qt/Resources/media-playback-stop-4.png b/GUI/Qt/Resources/media-playback-stop-4.png
new file mode 100644
index 0000000..f3e8362
Binary files /dev/null and b/GUI/Qt/Resources/media-playback-stop-4.png differ
diff --git a/GUI/Qt/Resources/media-seek-backward-4.png b/GUI/Qt/Resources/media-seek-backward-4.png
new file mode 100644
index 0000000..0a5e19d
Binary files /dev/null and b/GUI/Qt/Resources/media-seek-backward-4.png differ
diff --git a/GUI/Qt/Resources/media-skip-forward-4.png b/GUI/Qt/Resources/media-skip-forward-4.png
new file mode 100644
index 0000000..8e4a932
Binary files /dev/null and b/GUI/Qt/Resources/media-skip-forward-4.png differ
diff --git a/GUI/Qt/Resources/menu-arrow.png b/GUI/Qt/Resources/menu-arrow.png
new file mode 100644
index 0000000..3c06ba7
Binary files /dev/null and b/GUI/Qt/Resources/menu-arrow.png differ
diff --git a/GUI/Qt/Resources/network-wireless.png b/GUI/Qt/Resources/network-wireless.png
new file mode 100644
index 0000000..1f3b6a1
Binary files /dev/null and b/GUI/Qt/Resources/network-wireless.png differ
diff --git a/GUI/Qt/Resources/open_22.png b/GUI/Qt/Resources/open_22.png
new file mode 100644
index 0000000..d6dea71
Binary files /dev/null and b/GUI/Qt/Resources/open_22.png differ
diff --git a/GUI/Qt/Resources/open_popup_16.png b/GUI/Qt/Resources/open_popup_16.png
new file mode 100644
index 0000000..ce7f1a4
Binary files /dev/null and b/GUI/Qt/Resources/open_popup_16.png differ
diff --git a/UserInterface/MainComponents/Artwork/outputintensity.gif b/GUI/Qt/Resources/outputintensity.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/outputintensity.gif
rename to GUI/Qt/Resources/outputintensity.gif
diff --git a/GUI/Qt/Resources/paintbrush.gif b/GUI/Qt/Resources/paintbrush.gif
new file mode 100644
index 0000000..fa9f57f
Binary files /dev/null and b/GUI/Qt/Resources/paintbrush.gif differ
diff --git a/GUI/Qt/Resources/poly.gif b/GUI/Qt/Resources/poly.gif
new file mode 100644
index 0000000..8622558
Binary files /dev/null and b/GUI/Qt/Resources/poly.gif differ
diff --git a/GUI/Qt/Resources/popup_clear_16.png b/GUI/Qt/Resources/popup_clear_16.png
new file mode 100644
index 0000000..db29272
Binary files /dev/null and b/GUI/Qt/Resources/popup_clear_16.png differ
diff --git a/GUI/Qt/Resources/popup_delete_16.png b/GUI/Qt/Resources/popup_delete_16.png
new file mode 100644
index 0000000..c7a62b0
Binary files /dev/null and b/GUI/Qt/Resources/popup_delete_16.png differ
diff --git a/GUI/Qt/Resources/popup_edit_16.png b/GUI/Qt/Resources/popup_edit_16.png
new file mode 100644
index 0000000..a92bc18
Binary files /dev/null and b/GUI/Qt/Resources/popup_edit_16.png differ
diff --git a/GUI/Qt/Resources/popup_ok_16.png b/GUI/Qt/Resources/popup_ok_16.png
new file mode 100644
index 0000000..eb4abc9
Binary files /dev/null and b/GUI/Qt/Resources/popup_ok_16.png differ
diff --git a/GUI/Qt/Resources/popup_paste_16.png b/GUI/Qt/Resources/popup_paste_16.png
new file mode 100644
index 0000000..d00e14c
Binary files /dev/null and b/GUI/Qt/Resources/popup_paste_16.png differ
diff --git a/GUI/Qt/Resources/popup_split_16.png b/GUI/Qt/Resources/popup_split_16.png
new file mode 100644
index 0000000..f42f7f8
Binary files /dev/null and b/GUI/Qt/Resources/popup_split_16.png differ
diff --git a/GUI/Qt/Resources/popup_undo_16.png b/GUI/Qt/Resources/popup_undo_16.png
new file mode 100644
index 0000000..516bdd8
Binary files /dev/null and b/GUI/Qt/Resources/popup_undo_16.png differ
diff --git a/UserInterface/MainComponents/Artwork/ra.gif b/GUI/Qt/Resources/ra.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/ra.gif
rename to GUI/Qt/Resources/ra.gif
diff --git a/UserInterface/MainComponents/Artwork/rb.gif b/GUI/Qt/Resources/rb.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/rb.gif
rename to GUI/Qt/Resources/rb.gif
diff --git a/UserInterface/MainComponents/Artwork/rc.gif b/GUI/Qt/Resources/rc.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/rc.gif
rename to GUI/Qt/Resources/rc.gif
diff --git a/GUI/Qt/Resources/redo_22.png b/GUI/Qt/Resources/redo_22.png
new file mode 100644
index 0000000..d79fdca
Binary files /dev/null and b/GUI/Qt/Resources/redo_22.png differ
diff --git a/GUI/Qt/Resources/revertaxis_16.png b/GUI/Qt/Resources/revertaxis_16.png
new file mode 100644
index 0000000..fbef1de
Binary files /dev/null and b/GUI/Qt/Resources/revertaxis_16.png differ
diff --git a/GUI/Qt/Resources/rotate3d.gif b/GUI/Qt/Resources/rotate3d.gif
new file mode 100644
index 0000000..2bed4f9
Binary files /dev/null and b/GUI/Qt/Resources/rotate3d.gif differ
diff --git a/UserInterface/MainComponents/Artwork/rotate3dTiny.gif b/GUI/Qt/Resources/rotate3dTiny.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/rotate3dTiny.gif
rename to GUI/Qt/Resources/rotate3dTiny.gif
diff --git a/GUI/Qt/Resources/save_22.png b/GUI/Qt/Resources/save_22.png
new file mode 100644
index 0000000..9420209
Binary files /dev/null and b/GUI/Qt/Resources/save_22.png differ
diff --git a/GUI/Qt/Resources/scalpel.gif b/GUI/Qt/Resources/scalpel.gif
new file mode 100644
index 0000000..5ac5632
Binary files /dev/null and b/GUI/Qt/Resources/scalpel.gif differ
diff --git a/UserInterface/MainComponents/Artwork/screencapture.gif b/GUI/Qt/Resources/screencapture.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/screencapture.gif
rename to GUI/Qt/Resources/screencapture.gif
diff --git a/UserInterface/MainComponents/Artwork/screencapture2.gif b/GUI/Qt/Resources/screencapture2.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/screencapture2.gif
rename to GUI/Qt/Resources/screencapture2.gif
diff --git a/GUI/Qt/Resources/snake.gif b/GUI/Qt/Resources/snake.gif
new file mode 100644
index 0000000..79e4c9c
Binary files /dev/null and b/GUI/Qt/Resources/snake.gif differ
diff --git a/GUI/Qt/Resources/snap_splash_172.png b/GUI/Qt/Resources/snap_splash_172.png
new file mode 100644
index 0000000..2698d41
Binary files /dev/null and b/GUI/Qt/Resources/snap_splash_172.png differ
diff --git a/GUI/Qt/Resources/snapres/EdgeForcesExample.png b/GUI/Qt/Resources/snapres/EdgeForcesExample.png
new file mode 100644
index 0000000..00c0899
Binary files /dev/null and b/GUI/Qt/Resources/snapres/EdgeForcesExample.png differ
diff --git a/GUI/Qt/Resources/snapres/RegionForcesExample.png b/GUI/Qt/Resources/snapres/RegionForcesExample.png
new file mode 100644
index 0000000..357e50e
Binary files /dev/null and b/GUI/Qt/Resources/snapres/RegionForcesExample.png differ
diff --git a/GUI/Qt/Resources/snapres/SnakeParameterPreviewCurve.txt b/GUI/Qt/Resources/snapres/SnakeParameterPreviewCurve.txt
new file mode 100644
index 0000000..2ee5976
--- /dev/null
+++ b/GUI/Qt/Resources/snapres/SnakeParameterPreviewCurve.txt
@@ -0,0 +1,12 @@
+Points.ArraySize = 11
+Points.Element[0]	=	0.2875	0.53125
+Points.Element[1]	=	0.36875	0.75
+Points.Element[2]	=	0.5375	0.7625
+Points.Element[3]	=	0.89375	0.84375
+Points.Element[4]	=	0.5375	0.525
+Points.Element[5]	=	0.6875	0.2125
+Points.Element[6]	=	0.45625	0.31875
+Points.Element[7]	=	0.1625	0.06875
+Points.Element[8]	=	0.38125	0.13125
+Points.Element[9]	=	0.10625	0.125
+Points.Element[10]	=	0.19375	0.36875
diff --git a/GUI/Qt/Resources/source/CVS/Entries b/GUI/Qt/Resources/source/CVS/Entries
new file mode 100644
index 0000000..1c0ae74
--- /dev/null
+++ b/GUI/Qt/Resources/source/CVS/Entries
@@ -0,0 +1,2 @@
+/snaplogo_gimp.xcf.gz/1.1/Sat Dec  2 04:22:26 2006/-kb/
+D
diff --git a/GUI/Qt/Resources/source/CVS/Repository b/GUI/Qt/Resources/source/CVS/Repository
new file mode 100644
index 0000000..3b17046
--- /dev/null
+++ b/GUI/Qt/Resources/source/CVS/Repository
@@ -0,0 +1 @@
+itksnap/UserInterface/MainComponents/Artwork/source
diff --git a/GUI/Qt/Resources/source/CVS/Root b/GUI/Qt/Resources/source/CVS/Root
new file mode 100644
index 0000000..afa7195
--- /dev/null
+++ b/GUI/Qt/Resources/source/CVS/Root
@@ -0,0 +1 @@
+:ext:pyushkevich at itk-snap.cvs.sourceforge.net:/cvsroot/itk-snap
diff --git a/UserInterface/MainComponents/Artwork/source/snaplogo_gimp.xcf.gz b/GUI/Qt/Resources/source/snaplogo_gimp.xcf.gz
similarity index 100%
rename from UserInterface/MainComponents/Artwork/source/snaplogo_gimp.xcf.gz
rename to GUI/Qt/Resources/source/snaplogo_gimp.xcf.gz
diff --git a/GUI/Qt/Resources/speed_bluegray.png b/GUI/Qt/Resources/speed_bluegray.png
new file mode 100644
index 0000000..7153517
Binary files /dev/null and b/GUI/Qt/Resources/speed_bluegray.png differ
diff --git a/GUI/Qt/Resources/speed_redoverlay.png b/GUI/Qt/Resources/speed_redoverlay.png
new file mode 100644
index 0000000..3366ff6
Binary files /dev/null and b/GUI/Qt/Resources/speed_redoverlay.png differ
diff --git a/GUI/Qt/Resources/spray.gif b/GUI/Qt/Resources/spray.gif
new file mode 100644
index 0000000..320b182
Binary files /dev/null and b/GUI/Qt/Resources/spray.gif differ
diff --git a/GUI/Qt/Resources/thresh_both.png b/GUI/Qt/Resources/thresh_both.png
new file mode 100644
index 0000000..424551d
Binary files /dev/null and b/GUI/Qt/Resources/thresh_both.png differ
diff --git a/GUI/Qt/Resources/thresh_lower.png b/GUI/Qt/Resources/thresh_lower.png
new file mode 100644
index 0000000..fe99901
Binary files /dev/null and b/GUI/Qt/Resources/thresh_lower.png differ
diff --git a/GUI/Qt/Resources/thresh_upper.png b/GUI/Qt/Resources/thresh_upper.png
new file mode 100644
index 0000000..14cf27f
Binary files /dev/null and b/GUI/Qt/Resources/thresh_upper.png differ
diff --git a/GUI/Qt/Resources/tools.png b/GUI/Qt/Resources/tools.png
new file mode 100644
index 0000000..5df0517
Binary files /dev/null and b/GUI/Qt/Resources/tools.png differ
diff --git a/GUI/Qt/Resources/triangle_small_down_16.png b/GUI/Qt/Resources/triangle_small_down_16.png
new file mode 100644
index 0000000..0c78bbd
Binary files /dev/null and b/GUI/Qt/Resources/triangle_small_down_16.png differ
diff --git a/GUI/Qt/Resources/triangle_small_right_16.png b/GUI/Qt/Resources/triangle_small_right_16.png
new file mode 100644
index 0000000..2fcf824
Binary files /dev/null and b/GUI/Qt/Resources/triangle_small_right_16.png differ
diff --git a/GUI/Qt/Resources/undo_22.png b/GUI/Qt/Resources/undo_22.png
new file mode 100644
index 0000000..abe1f2e
Binary files /dev/null and b/GUI/Qt/Resources/undo_22.png differ
diff --git a/GUI/Qt/Resources/view-refresh-4.png b/GUI/Qt/Resources/view-refresh-4.png
new file mode 100644
index 0000000..67698e3
Binary files /dev/null and b/GUI/Qt/Resources/view-refresh-4.png differ
diff --git a/GUI/Qt/Resources/zoom.gif b/GUI/Qt/Resources/zoom.gif
new file mode 100644
index 0000000..ae4de13
Binary files /dev/null and b/GUI/Qt/Resources/zoom.gif differ
diff --git a/UserInterface/MainComponents/Artwork/zoom3d.gif b/GUI/Qt/Resources/zoom3d.gif
similarity index 100%
rename from UserInterface/MainComponents/Artwork/zoom3d.gif
rename to GUI/Qt/Resources/zoom3d.gif
diff --git a/GUI/Qt/View/ColorMapBox.cxx b/GUI/Qt/View/ColorMapBox.cxx
new file mode 100644
index 0000000..26acd3d
--- /dev/null
+++ b/GUI/Qt/View/ColorMapBox.cxx
@@ -0,0 +1,66 @@
+#include "ColorMapBox.h"
+#include "ColorMapRenderer.h"
+#include "ColorMapModel.h"
+#include "ColorMapInspector.h"
+#include <QPalette>
+#include <QWidget>
+
+ColorMapBox::ColorMapBox(QWidget *parent)
+  : QtAbstractOpenGLBox(parent)
+{
+  m_Model = NULL;
+  m_Renderer = ColorMapRenderer::New();
+  m_Delegate = new ColorMapInteractionDelegate(this);
+
+  // attach delegate
+  AttachSingleDelegate(m_Delegate);
+}
+
+ColorMapBox::~ColorMapBox()
+{
+}
+
+void ColorMapBox::SetModel(ColorMapModel *model)
+{
+  m_Model = model;
+  m_Renderer->SetModel(model);
+  m_Delegate->SetModel(model);
+
+  connectITK(m_Model, ModelUpdateEvent());
+}
+
+void ColorMapBox::onModelUpdate(const EventBucket &bucket)
+{
+  this->update();
+}
+
+
+
+
+void ColorMapInteractionDelegate::mousePressEvent(QMouseEvent *ev)
+{
+  m_Model->ProcessMousePressEvent(m_XSpace);
+}
+
+void ColorMapInteractionDelegate::mouseReleaseEvent(QMouseEvent *)
+{
+  m_Model->ProcessMouseReleaseEvent(m_XSpace);
+}
+
+void ColorMapInteractionDelegate::mouseMoveEvent(QMouseEvent *)
+{
+  m_Model->ProcessMouseDragEvent(m_XSpace);
+}
+
+void ColorMapInteractionDelegate::mouseDoubleClickEvent(QMouseEvent *)
+{
+  m_InspectorWidget->PromptUserForColor();
+}
+
+ColorMapInteractionDelegate::ColorMapInteractionDelegate(QWidget *parent)
+  : QtInteractionDelegateWidget(parent)
+{
+  m_Model = NULL;
+}
+
+
diff --git a/GUI/Qt/View/ColorMapBox.h b/GUI/Qt/View/ColorMapBox.h
new file mode 100644
index 0000000..5c38635
--- /dev/null
+++ b/GUI/Qt/View/ColorMapBox.h
@@ -0,0 +1,73 @@
+#ifndef COLORMAPBOX_H
+#define COLORMAPBOX_H
+
+#include <QtAbstractOpenGLBox.h>
+#include <QtInteractionDelegateWidget.h>
+#include <SNAPEvents.h>
+#include <ColorMapRenderer.h>
+
+class ColorMapModel;
+class ColorMapInteractionDelegate;
+class ColorMapInspector;
+
+class ColorMapBox : public QtAbstractOpenGLBox
+{
+  Q_OBJECT
+
+  FIRES(ModelUpdateEvent)
+
+public:
+  explicit ColorMapBox(QWidget *parent = 0);
+  virtual ~ColorMapBox();
+
+  // Get the model in this widget
+  irisGetMacro(Model, ColorMapModel *)
+
+  // Get the renderer for this widget
+  irisGetMacro(Renderer, AbstractRenderer *)
+
+  // Get the interaction delegate for this widget
+  irisGetMacro(Delegate, ColorMapInteractionDelegate *)
+
+  // Set the model (state) for this widget
+  void SetModel(ColorMapModel *model);
+
+public slots:
+
+  void onModelUpdate(const EventBucket &bucket);
+
+private:
+
+  ColorMapModel *m_Model;
+  SmartPtr<ColorMapRenderer> m_Renderer;
+  ColorMapInteractionDelegate *m_Delegate;
+};
+
+
+class ColorMapInteractionDelegate : public QtInteractionDelegateWidget
+{
+  Q_OBJECT
+
+public:
+  explicit ColorMapInteractionDelegate(QWidget *parent = 0);
+
+  void mousePressEvent(QMouseEvent *);
+  void mouseReleaseEvent(QMouseEvent *);
+  void mouseMoveEvent(QMouseEvent *);
+  void mouseDoubleClickEvent(QMouseEvent *);
+
+  // Set the model (state) for this widget
+  irisGetSetMacro(Model, ColorMapModel *)
+
+  // Set the inspector widget
+  irisGetSetMacro(InspectorWidget, ColorMapInspector *)
+
+private:
+
+  ColorMapModel *m_Model;
+  ColorMapInspector *m_InspectorWidget;
+};
+
+
+
+#endif // COLORMAPBOX_H
diff --git a/GUI/Qt/View/CrosshairsInteractionMode.cxx b/GUI/Qt/View/CrosshairsInteractionMode.cxx
new file mode 100644
index 0000000..62af551
--- /dev/null
+++ b/GUI/Qt/View/CrosshairsInteractionMode.cxx
@@ -0,0 +1,284 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "CrosshairsInteractionMode.h"
+#include "GenericSliceView.h"
+#include "OrthogonalSliceCursorNavigationModel.h"
+#include "CrosshairsRenderer.h"
+#include <QPinchGesture>
+#include <QPanGesture>
+#include <QSwipeGesture>
+#include <QApplication>
+
+CrosshairsInteractionMode::CrosshairsInteractionMode(GenericSliceView *parent) :
+    SliceWindowInteractionDelegateWidget(parent)
+{
+  // Create the renderer
+  m_Renderer = CrosshairsRenderer::New();
+  m_Renderer->SetParentRenderer(
+        static_cast<GenericSliceRenderer *>(parent->GetRenderer()));
+
+
+  m_WheelEventTarget = NULL;
+  m_Model = NULL;
+
+  SetMouseButtonBehaviorToCrosshairsMode();
+  setAttribute(Qt::WA_AcceptTouchEvents, true);
+}
+
+CrosshairsInteractionMode::~CrosshairsInteractionMode()
+{
+
+}
+
+void CrosshairsInteractionMode
+::SetMouseButtonBehaviorToCrosshairsMode()
+{
+  m_BtnCursor = Qt::LeftButton;
+  m_BtnZoom = Qt::RightButton;
+  m_BtnPan = Qt::MiddleButton;
+}
+
+void CrosshairsInteractionMode
+::SetMouseButtonBehaviorToZoomPanMode()
+{
+  m_BtnCursor = Qt::MiddleButton;
+  m_BtnZoom = Qt::RightButton;
+  m_BtnPan = Qt::LeftButton;
+}
+
+void CrosshairsInteractionMode
+::SetModel(OrthogonalSliceCursorNavigationModel *model)
+{
+  m_Model = model;
+  m_Renderer->SetModel(model);
+  SetParentModel(model->GetParent());
+}
+
+void CrosshairsInteractionMode::mousePressEvent(QMouseEvent *ev)
+{
+  // Use model to envoke event
+  if(ev->button() == m_BtnCursor)
+    {
+    m_Model->UpdateCursor(Vector2f(m_XSpace[0], m_XSpace[1]));
+    }
+  else if(ev->button() == m_BtnZoom)
+    {
+    m_Model->BeginZoom();
+    }
+  else if(ev->button() == m_BtnPan)
+    {
+    m_Model->BeginPan();
+    }
+  // Eat this event
+  ev->accept();
+}
+
+void CrosshairsInteractionMode::mouseMoveEvent(QMouseEvent *ev)
+{
+  if(isDragging())
+    {
+    Vector3d dx = m_XSpace - m_LastPressXSpace;
+
+    if(m_LastPressButton == m_BtnCursor)
+      {
+      m_Model->UpdateCursor(Vector2f(m_XSpace[0], m_XSpace[1]));
+      }
+    else if(m_LastPressButton == m_BtnZoom)
+      {
+      double scaleFactor = pow(1.02, dx(1));
+      m_Model->ProcessZoomGesture(scaleFactor);
+      }
+    else if(m_LastPressButton == m_BtnPan)
+      {
+      m_Model->ProcessPanGesture(Vector2f(dx(0), dx(1)));
+      }
+
+    // Eat this event
+    ev->accept();
+    }
+  else
+    {
+    ev->ignore();
+    }
+}
+
+
+void CrosshairsInteractionMode::mouseReleaseEvent(QMouseEvent *ev)
+{
+
+  if(ev->button() == m_BtnCursor)
+    {
+    m_Model->UpdateCursor(Vector2f(m_XSpace[0], m_XSpace[1]));
+    }
+  else if(ev->button() == m_BtnZoom)
+    {
+    m_Model->EndZoom();
+    }
+  else if(ev->button() == m_BtnPan)
+    {
+    m_Model->EndPan();
+    }
+  // Eat this event
+  ev->accept();
+}
+
+bool CrosshairsInteractionMode::gestureEvent(QGestureEvent *ev)
+{
+  // Get the pinch gesture if there is one
+  if(QPinchGesture *pinch =
+      static_cast<QPinchGesture *>(ev->gesture(Qt::PinchGesture)))
+    {
+    if(pinch->state() == Qt::GestureStarted)
+      {
+      m_Model->BeginZoom();
+      }
+    else if(pinch->state() == Qt::GestureUpdated)
+      {
+      m_Model->ProcessZoomGesture(pinch->scaleFactor());
+      }
+    else if(pinch->state() == Qt::GestureFinished)
+      {
+      m_Model->ProcessZoomGesture(pinch->scaleFactor());
+      m_Model->EndZoom();
+      }
+    ev->accept();
+    return true;
+    }
+
+  /*
+
+  // Get the pan event
+  if(QPanGesture *pan =
+      static_cast<QPanGesture *>(ev->gesture(Qt::PanGesture)))
+    {
+    if(pan->state() == Qt::GestureStarted)
+      {
+      m_Model->BeginPan();
+      }
+    else if(pan->state() == Qt::GestureUpdated)
+      {
+      m_Model->ProcessPanGesture(Vector2f(pan->delta().x(), pan->delta().y()));
+      }
+    else if(pan->state() == Qt::GestureFinished)
+      {
+      m_Model->ProcessPanGesture(Vector2f(pan->delta().x(), pan->delta().y()));
+      m_Model->EndPan();
+      }
+    ev->accept();
+    return true;
+    }
+
+  // Get the swipe event
+  if(QSwipeGesture *swipe =
+      static_cast<QSwipeGesture *>(ev->gesture(Qt::SwipeGesture)))
+    {
+    if(swipe->verticalDirection() == QSwipeGesture::Down)
+      {
+      m_Model->ProcessScrollGesture(1);
+      }
+    else if(swipe->verticalDirection() == QSwipeGesture::Up)
+      {
+      m_Model->ProcessScrollGesture(-1);
+      }
+    ev->accept();
+    return true;
+    }
+  return false;
+
+  */
+  else return false;
+}
+
+void CrosshairsInteractionMode::keyPressEvent(QKeyEvent *ev)
+{
+  Vector3i dx(0,0,0);
+  switch(ev->key())
+    {
+    case Qt::Key_Up:       dx = Vector3i( 0, 1, 0); break;
+    case Qt::Key_Down:     dx = Vector3i( 0,-1, 0); break;
+    case Qt::Key_Left:     dx = Vector3i(-1, 0, 0); break;
+    case Qt::Key_Right:    dx = Vector3i( 1, 0, 0); break;
+    case Qt::Key_PageUp:   dx = Vector3i( 0, 0, 1); break;
+    case Qt::Key_PageDown: dx = Vector3i( 0, 0,-1); break;
+    default:
+      SliceWindowInteractionDelegateWidget::keyPressEvent(ev);
+      return;
+    }
+
+  if(ev->modifiers() & Qt::ShiftModifier)
+    dx *= 5;
+
+  m_Model->ProcessKeyNavigation(dx);
+  ev->accept();
+}
+
+void CrosshairsInteractionMode::enterEvent(QEvent *)
+{
+  // Respond to standard gestures
+  this->m_ParentView->grabGesture(Qt::PinchGesture);
+  // this->m_ParentView->grabGesture(Qt::PanGesture);
+  // this->m_ParentView->grabGesture(Qt::SwipeGesture);
+}
+
+void CrosshairsInteractionMode::leaveEvent(QEvent *)
+{
+  // Stop responding to gestures
+  // this->ungrabGesture(Qt::PinchGesture);
+}
+
+void CrosshairsInteractionMode::wheelEvent(QWheelEvent *event)
+{
+  // We want to scroll 1 line at a time!
+  int scrollLines = QApplication::wheelScrollLines();
+  QApplication::setWheelScrollLines(1);
+
+  if(m_WheelEventTarget)
+    {
+    QWheelEvent evnew(
+          event->pos(), event->globalPos(), event->delta(),
+          event->buttons(), event->modifiers(),
+          event->orientation());
+    QCoreApplication::sendEvent(m_WheelEventTarget, &evnew);
+    event->accept();
+    }
+
+  /*
+  int numDegrees = event->delta() / 8;
+  int numSteps = numDegrees / 15;
+  std::cout << "Wheel event: " << event->delta() << std::endl;
+
+  // Scroll
+  m_Model->ProcessScrollGesture(numSteps);
+  */
+
+  QApplication::setWheelScrollLines(scrollLines);
+}
+
+void CrosshairsInteractionMode::SetWheelEventTargetWidget(QWidget *w)
+{
+  m_WheelEventTarget = w;
+}
diff --git a/GUI/Qt/View/CrosshairsInteractionMode.h b/GUI/Qt/View/CrosshairsInteractionMode.h
new file mode 100644
index 0000000..7be68bf
--- /dev/null
+++ b/GUI/Qt/View/CrosshairsInteractionMode.h
@@ -0,0 +1,85 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef CROSSHAIRSINTERACTIONMODE_H
+#define CROSSHAIRSINTERACTIONMODE_H
+
+#include <SliceWindowInteractionDelegateWidget.h>
+#include <SNAPCommon.h>
+
+class GenericSliceModel;
+class OrthogonalSliceCursorNavigationModel;
+class GenericSliceView;
+class CrosshairsRenderer;
+
+class CrosshairsInteractionMode : public SliceWindowInteractionDelegateWidget
+{
+  Q_OBJECT
+
+public:
+  explicit CrosshairsInteractionMode(GenericSliceView *parent = NULL);
+  ~ CrosshairsInteractionMode();
+
+
+  irisGetMacro(Renderer, CrosshairsRenderer *)
+
+  void SetModel(OrthogonalSliceCursorNavigationModel *model);
+
+  void mousePressEvent(QMouseEvent *ev);
+  void mouseMoveEvent(QMouseEvent *);
+  void mouseReleaseEvent(QMouseEvent *);
+  void wheelEvent(QWheelEvent *);
+
+  void enterEvent(QEvent *);
+  void leaveEvent(QEvent *);
+
+  bool gestureEvent(QGestureEvent *);
+
+  // Handle keystrokes
+  void keyPressEvent(QKeyEvent *);
+
+  void SetMouseButtonBehaviorToCrosshairsMode();
+  void SetMouseButtonBehaviorToZoomPanMode();
+
+  // Set the widget to which the wheel events should be forwarded
+  void SetWheelEventTargetWidget(QWidget *w);
+
+signals:
+
+public slots:
+
+protected:
+  OrthogonalSliceCursorNavigationModel *m_Model;
+  SmartPtr<CrosshairsRenderer> m_Renderer;
+
+  // The behavior of buttons when envoking zoom/pan/cursor actions
+  Qt::MouseButton m_BtnCursor, m_BtnZoom, m_BtnPan;
+
+  // Widget to which wheel events are forwarded
+  QWidget *m_WheelEventTarget;
+};
+
+#endif // CROSSHAIRSINTERACTIONMODE_H
diff --git a/GUI/Qt/View/GenericSliceView.cxx b/GUI/Qt/View/GenericSliceView.cxx
new file mode 100644
index 0000000..34646c0
--- /dev/null
+++ b/GUI/Qt/View/GenericSliceView.cxx
@@ -0,0 +1,71 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "GenericSliceView.h"
+#include "CrosshairsInteractionMode.h"
+#include "LatentITKEventNotifier.h"
+#include "QtReporterDelegates.h"
+
+GenericSliceView::GenericSliceView(QWidget *parent) :
+  QtAbstractOpenGLBox(parent)
+{
+  m_Model = NULL;
+  m_Renderer = GenericSliceRenderer::New();
+
+  m_ViewportReporter = QtViewportReporter::New();
+  m_ViewportReporter->SetClientWidget(this);
+
+  // We need to grab keyboard focus
+  this->SetGrabFocusOnEntry(true);
+}
+
+void GenericSliceView::SetModel(GenericSliceModel *model)
+{
+  // Set the model
+  m_Model = model;
+
+  // Pass the viewport reporter to the model
+  m_Model->SetSizeReporter(m_ViewportReporter);
+
+  // Pass the model to the renderer
+  m_Renderer->SetModel(m_Model);
+
+  // Listen to the update events on the model. In response, simply repaint
+  connectITK(m_Model, ModelUpdateEvent());
+  connectITK(m_Model, SliceModelGeometryChangeEvent());
+  connectITK(m_Renderer, AppearanceUpdateEvent());
+}
+
+
+void GenericSliceView::onModelUpdate(const EventBucket &b)
+{
+  // Make sure the model is up to date
+  m_Model->Update();
+
+  // Ask this widget to repaint
+  this->update();
+}
+
diff --git a/GUI/Qt/View/GenericSliceView.h b/GUI/Qt/View/GenericSliceView.h
new file mode 100644
index 0000000..a12daf5
--- /dev/null
+++ b/GUI/Qt/View/GenericSliceView.h
@@ -0,0 +1,77 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef GENERICSLICEVIEW_H
+#define GENERICSLICEVIEW_H
+
+#include <QGLWidget>
+#include <SNAPCommon.h>
+#include <GenericSliceModel.h>
+#include <GenericSliceRenderer.h>
+#include <QtAbstractOpenGLBox.h>
+#include <EventBucket.h>
+#include "QtReporterDelegates.h"
+
+class CrosshairsInteractionMode;
+
+class GenericSliceView : public QtAbstractOpenGLBox
+{
+  Q_OBJECT
+
+public:
+  explicit GenericSliceView(QWidget *parent = 0);
+
+  irisGetMacro(Model, GenericSliceModel *)
+
+  // Set the model (state) for this widget
+  void SetModel(GenericSliceModel *model);
+
+  // Return the renderer
+  irisGetMacro(Renderer, AbstractRenderer *)
+
+  // Get the renderer overlays
+  GenericSliceRenderer::RendererDelegateList &GetRendererOverlays();
+
+public slots:
+
+  void onModelUpdate(const EventBucket &b);
+
+protected:
+
+  // Pointer to the model object for this class
+  GenericSliceModel *m_Model;
+
+  // A viewport reporter
+  SmartPtr<QtViewportReporter> m_ViewportReporter;
+
+  // OpenGL renderer (owned by the view)
+  SmartPtr<GenericSliceRenderer> m_Renderer;
+
+  // Whether next repaint requires a resize call (Qt bug?)
+  CrosshairsInteractionMode *m_Crosshairs;
+};
+
+#endif // GENERICSLICEVIEW_H
diff --git a/GUI/Qt/View/GenericView3D.cxx b/GUI/Qt/View/GenericView3D.cxx
new file mode 100644
index 0000000..c7aff4d
--- /dev/null
+++ b/GUI/Qt/View/GenericView3D.cxx
@@ -0,0 +1,258 @@
+#include "GenericView3D.h"
+#include "Generic3DModel.h"
+#include "Generic3DRenderer.h"
+#include "GlobalUIModel.h"
+#include "GlobalState.h"
+#include "vtkGenericRenderWindowInteractor.h"
+#include <QEvent>
+#include <QMouseEvent>
+#include <vtkInteractorStyle.h>
+#include <vtkInteractorStyleUser.h>
+#include <vtkInteractorStyleTrackballCamera.h>
+#include <vtkGenericOpenGLRenderWindow.h>
+#include <vtkCommand.h>
+#include <QtVTKInteractionDelegateWidget.h>
+#include <vtkPointPicker.h>
+#include <vtkRendererCollection.h>
+#include <vtkObjectFactory.h>
+#include <vtkInteractorStyleSwitch.h>
+#include "Window3DPicker.h"
+#include "IRISApplication.h"
+
+class CursorPlacementInteractorStyle : public vtkInteractorStyleTrackballCamera
+{
+public:
+  static CursorPlacementInteractorStyle* New();
+  vtkTypeRevisionMacro(CursorPlacementInteractorStyle, vtkInteractorStyleTrackballCamera)
+
+  irisGetSetMacro(Model, Generic3DModel *)
+
+  virtual void OnLeftButtonDown()
+  {
+    if(!m_Model->PickSegmentationVoxelUnderMouse(
+         this->Interactor->GetEventPosition()[0],
+         this->Interactor->GetEventPosition()[1]))
+      {
+      // Forward events
+      vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
+      }
+  }
+
+private:
+  Generic3DModel *m_Model;
+};
+
+class SpraycanInteractorStyle : public vtkInteractorStyleTrackballCamera
+{
+public:
+  static SpraycanInteractorStyle* New();
+  vtkTypeRevisionMacro(SpraycanInteractorStyle, vtkInteractorStyleTrackballCamera)
+
+  irisGetSetMacro(Model, Generic3DModel *)
+
+  virtual void OnLeftButtonDown()
+  {
+    // Spray a voxel
+    if(m_Model->SpraySegmentationVoxelUnderMouse(
+         this->Interactor->GetEventPosition()[0],
+         this->Interactor->GetEventPosition()[1]))
+      {
+      m_IsPainting = true;
+      }
+    else
+      {
+      // Forward events
+      vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
+      }
+  }
+
+  virtual void OnLeftButtonUp()
+  {
+    if(m_IsPainting)
+      m_IsPainting = false;
+    else
+      vtkInteractorStyleTrackballCamera::OnLeftButtonUp();
+  }
+
+  virtual void OnMouseMove()
+  {
+    if(m_IsPainting)
+      m_Model->SpraySegmentationVoxelUnderMouse(
+               this->Interactor->GetEventPosition()[0],
+               this->Interactor->GetEventPosition()[1]);
+    else
+      vtkInteractorStyleTrackballCamera::OnMouseMove();
+  }
+
+protected:
+
+  SpraycanInteractorStyle() : m_IsPainting(false), m_Model(NULL) {}
+  virtual ~SpraycanInteractorStyle() {}
+
+private:
+  Generic3DModel *m_Model;
+  bool m_IsPainting;
+};
+
+
+class ScalpelInteractorStyle : public vtkInteractorStyleTrackballCamera
+{
+public:
+  static ScalpelInteractorStyle* New();
+  vtkTypeRevisionMacro(ScalpelInteractorStyle, vtkInteractorStyleTrackballCamera)
+
+  irisGetSetMacro(Model, Generic3DModel *)
+
+  virtual void OnLeftButtonDown()
+  {
+    Vector2i xevent(this->Interactor->GetEventPosition());
+    switch(m_Model->GetScalpelStatus())
+      {
+      case Generic3DModel::SCALPEL_LINE_NULL:
+        // Holding and dragging the LMB acts as a trackball, only clicking
+        // the LMB causes drawing operations
+        m_ClickStart = xevent;
+        vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
+        // m_Model->SetScalpelStartPoint(xevent[0], xevent[1]);
+        break;
+      case Generic3DModel::SCALPEL_LINE_STARTED:
+        m_Model->SetScalpelEndPoint(xevent[0], xevent[1], true);
+        break;
+      case Generic3DModel::SCALPEL_LINE_COMPLETED:
+        vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
+        break;
+      }
+  }
+
+  virtual void OnMouseMove()
+  {
+    Vector2i xevent(this->Interactor->GetEventPosition());
+    switch(m_Model->GetScalpelStatus())
+      {
+      case Generic3DModel::SCALPEL_LINE_STARTED:
+        m_Model->SetScalpelEndPoint(xevent[0], xevent[1], false);
+        break;
+      default:
+        vtkInteractorStyleTrackballCamera::OnMouseMove();
+        break;
+      }
+ }
+
+  virtual void OnLeftButtonUp()
+  {
+    Vector2i xevent(this->Interactor->GetEventPosition());
+    Vector2i delta = xevent - m_ClickStart;
+
+    // Detect a click, which starts scalpel drawing
+    if(m_Model->GetScalpelStatus() == Generic3DModel::SCALPEL_LINE_NULL)
+      {
+      if(delta.squared_magnitude() < 4)
+        {
+        m_Model->SetScalpelStartPoint(xevent[0], xevent[1]);
+        }
+      }
+
+    vtkInteractorStyleTrackballCamera::OnLeftButtonUp();
+  }
+
+  virtual void OnEnter()
+  {
+    vtkInteractorStyleTrackballCamera::OnEnter();
+
+    // Record that we're inside
+    m_Inside = true;
+
+    // Record the end point
+    OnMouseMove();
+  }
+
+  virtual void OnLeave()
+  {
+    vtkInteractorStyleTrackballCamera::OnLeave();
+
+    // Record that we're inside
+    m_Inside = false;
+  }
+
+  irisGetMacro(Inside,bool)
+
+protected:
+
+  ScalpelInteractorStyle() : m_Model(NULL) {}
+  virtual ~ScalpelInteractorStyle() {}
+
+  Generic3DModel *m_Model;
+
+  Vector2i m_ClickStart;
+  bool m_Inside;
+};
+
+
+
+vtkCxxRevisionMacro(CursorPlacementInteractorStyle, "$Revision: 1.1 $")
+vtkStandardNewMacro(CursorPlacementInteractorStyle)
+
+vtkCxxRevisionMacro(SpraycanInteractorStyle, "$Revision: 1.1 $")
+vtkStandardNewMacro(SpraycanInteractorStyle)
+
+vtkCxxRevisionMacro(ScalpelInteractorStyle, "$Revision: 1.1 $")
+vtkStandardNewMacro(ScalpelInteractorStyle)
+
+
+
+GenericView3D::GenericView3D(QWidget *parent) :
+    QtVTKRenderWindowBox(parent)
+{
+  // Create the interactor styles for each mode
+  m_InteractionStyle[TRACKBALL_MODE]
+      = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
+
+  m_InteractionStyle[CROSSHAIRS_3D_MODE]
+      = vtkSmartPointer<CursorPlacementInteractorStyle>::New();
+
+  m_InteractionStyle[SCALPEL_MODE]
+      = vtkSmartPointer<ScalpelInteractorStyle>::New();
+
+  m_InteractionStyle[SPRAYPAINT_MODE]
+      = vtkSmartPointer<SpraycanInteractorStyle>::New();
+}
+
+GenericView3D::~GenericView3D()
+{
+}
+
+void GenericView3D::SetModel(Generic3DModel *model)
+{
+  m_Model = model;
+
+  // Assign the renderer
+  this->SetRenderer(m_Model->GetRenderer());
+
+  // Pass the model to the different interactors
+  CursorPlacementInteractorStyle::SafeDownCast(
+        m_InteractionStyle[CROSSHAIRS_3D_MODE])->SetModel(model);
+
+  SpraycanInteractorStyle::SafeDownCast(
+        m_InteractionStyle[SPRAYPAINT_MODE])->SetModel(model);
+
+  ScalpelInteractorStyle::SafeDownCast(
+        m_InteractionStyle[SCALPEL_MODE])->SetModel(model);
+
+  // Listen to toolbar changes
+  connectITK(m_Model->GetParentUI()->GetGlobalState()->GetToolbarMode3DModel(),
+             ValueChangedEvent(), SLOT(onToolbarModeChange()));
+
+  // Use the current toolbar settings
+  this->onToolbarModeChange();
+}
+
+void GenericView3D::onToolbarModeChange()
+{
+  int mode = (int) m_Model->GetParentUI()->GetGlobalState()->GetToolbarMode3D();
+
+  m_Model->GetRenderer()->GetRenderWindowInteractor()
+      ->SetInteractorStyle(m_InteractionStyle[mode]);
+
+  setMouseTracking(mode == SCALPEL_MODE);
+}
+
diff --git a/GUI/Qt/View/GenericView3D.h b/GUI/Qt/View/GenericView3D.h
new file mode 100644
index 0000000..da889fe
--- /dev/null
+++ b/GUI/Qt/View/GenericView3D.h
@@ -0,0 +1,42 @@
+#ifndef GENERICVIEW3D_H
+#define GENERICVIEW3D_H
+
+#include <QtVTKRenderWindowBox.h>
+#include <SNAPCommon.h>
+
+#include <vtkSmartPointer.h>
+
+class Generic3DModel;
+class vtkGenericRenderWindowInteractor;
+class vtkObject;
+class CursorPlacementInteractorStyle;
+class vtkInteractorStyle;
+
+class GenericView3D : public QtVTKRenderWindowBox
+{
+  Q_OBJECT
+
+public:
+  explicit GenericView3D(QWidget *parent = 0);
+  virtual ~GenericView3D();
+
+  void SetModel(Generic3DModel *model);
+
+signals:
+
+public slots:
+
+  void onToolbarModeChange();
+
+protected:
+
+  // The model in charge
+  Generic3DModel *m_Model;
+
+  // The interactor styles corresponding to each mode
+  vtkSmartPointer<vtkInteractorStyle> m_InteractionStyle[4];
+
+  vtkSmartPointer<CursorPlacementInteractorStyle> m_CursorPlacementStyle;
+};
+
+#endif // GENERICVIEW3D_H
diff --git a/GUI/Qt/View/InteractionMode.cxx b/GUI/Qt/View/InteractionMode.cxx
new file mode 100644
index 0000000..0eca444
--- /dev/null
+++ b/GUI/Qt/View/InteractionMode.cxx
@@ -0,0 +1,27 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "InteractionMode.h"
diff --git a/GUI/Qt/View/InteractionMode.h b/GUI/Qt/View/InteractionMode.h
new file mode 100644
index 0000000..622ce3a
--- /dev/null
+++ b/GUI/Qt/View/InteractionMode.h
@@ -0,0 +1,53 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef INTERACTIONMODE_H
+#define INTERACTIONMODE_H
+
+class QMouseEvent;
+class QWheelEvent;
+class QKeyEvent;
+class QFocusEvent;
+class QEvent;
+
+class InteractionMode
+{
+public:
+  virtual ~InteractionMode() {}
+  virtual void mousePressEvent(QMouseEvent *);
+  virtual void mouseReleaseEvent(QMouseEvent *);
+  virtual void mouseDoubleClickEvent(QMouseEvent *);
+  virtual void mouseMoveEvent(QMouseEvent *);
+  virtual void wheelEvent(QWheelEvent *);
+  virtual void keyPressEvent(QKeyEvent *);
+  virtual void keyReleaseEvent(QKeyEvent *);
+  virtual void focusInEvent(QFocusEvent *);
+  virtual void focusOutEvent(QFocusEvent *);
+  virtual void enterEvent(QEvent *);
+  virtual void leaveEvent(QEvent *);
+};
+
+#endif // INTERACTIONMODE_H
diff --git a/GUI/Qt/View/InteractionModeClient.cxx b/GUI/Qt/View/InteractionModeClient.cxx
new file mode 100644
index 0000000..4a5a77e
--- /dev/null
+++ b/GUI/Qt/View/InteractionModeClient.cxx
@@ -0,0 +1,94 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "InteractionModeClient.h"
+#include <algorithm>
+
+void
+InteractionModeClient
+::PushInteractionMode(InteractionMode *mode)
+{
+  m_Interactors.push_front(mode);
+}
+
+InteractionMode *
+InteractionModeClient
+::PopInteractionMode()
+{
+  InteractionMode *lastMode = m_Interactors.front();
+  m_Interactors.pop_front();
+  return lastMode;
+}
+
+void
+InteractionModeClient
+::ClearInteractionStack()
+{
+  m_Interactors.clear();
+}
+
+void InteractionModeClient
+::SetSingleInteractionMode(InteractionMode *mode)
+{
+  this->ClearInteractionStack();
+  this->PushInteractionMode(mode);
+}
+
+unsigned int
+InteractionModeClient
+::GetInteractionModeCount()
+{
+  return (unsigned int) m_Interactors.size();
+}
+
+InteractionMode *
+InteractionModeClient
+::GetTopInteractionMode()
+{
+  return m_Interactors.front();
+}
+
+bool
+InteractionModeClient
+::IsInteractionModeAdded(InteractionMode *target)
+{
+  return
+    std::find(m_Interactors.begin(), m_Interactors.end(), target) !=
+      m_Interactors.end();
+}
+/*
+void
+InteractionModeClient
+::FireInteractionDrawEvent()
+{
+  // Propagate the drawing event through the stack
+  typedef std::list<InteractionMode *>::iterator ModeIterator;
+  for (ModeIterator it = m_Interactors.begin(); it!=m_Interactors.end();it++)
+    {
+    InteractionMode *mode = *it;
+    mode->OnDraw();
+    }
+}*/
diff --git a/GUI/Qt/View/InteractionModeClient.h b/GUI/Qt/View/InteractionModeClient.h
new file mode 100644
index 0000000..c98e30b
--- /dev/null
+++ b/GUI/Qt/View/InteractionModeClient.h
@@ -0,0 +1,87 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef INTERACTIONMODECLIENT_H
+#define INTERACTIONMODECLIENT_H
+
+#include "InteractionMode.h"
+#include <list>
+
+/**
+ * \class InteractionModeClient
+ * \brief An abstract class that can pass on Qt events to
+ * interaction modes
+ */
+class InteractionModeClient
+{
+public:
+  /**
+   * Push an interaction mode onto the stack of modes.  Mode becomes first to
+   * receive events.  The events that it does not receive are passed on to the
+   * next mode on the stack.
+   */
+  void PushInteractionMode(InteractionMode *mode);
+
+  /**
+   * Pop the last interaction mode off the stack
+   */
+  InteractionMode *PopInteractionMode();
+
+  /**
+   * Get the top interaction mode on the stack
+   */
+  InteractionMode *GetTopInteractionMode();
+
+  /**
+   * See if the interaction mode is in the stack
+   */
+  bool IsInteractionModeAdded(InteractionMode *target);
+
+  /**
+   * Remove all interaction modes
+   */
+  void ClearInteractionStack();
+
+  /**
+   * Set the interaction stack to consist of just one interaction mode. This is
+   * equivalent to calling ClearInteractionStack() followed by PushInteractionMode()
+   */
+  void SetSingleInteractionMode(InteractionMode *mode);
+
+  /**
+   * Get the number of interaction modes on the stack
+   */
+  unsigned int GetInteractionModeCount();
+
+  // Virtual destructor
+  virtual ~InteractionModeClient() {}
+
+protected:
+
+  // The stack of interaction modes
+  std::list<InteractionMode *> m_Interactors;
+};
+#endif // INTERACTIONMODECLIENT_H
diff --git a/GUI/Qt/View/PaintbrushInteractionMode.cxx b/GUI/Qt/View/PaintbrushInteractionMode.cxx
new file mode 100644
index 0000000..da67fb0
--- /dev/null
+++ b/GUI/Qt/View/PaintbrushInteractionMode.cxx
@@ -0,0 +1,97 @@
+#include "PaintbrushInteractionMode.h"
+#include "PaintbrushRenderer.h"
+#include "GenericSliceView.h"
+#include "PaintbrushModel.h"
+#include "SliceViewPanel.h"
+
+PaintbrushInteractionMode::PaintbrushInteractionMode(GenericSliceView *parent)
+  : SliceWindowInteractionDelegateWidget(parent)
+{
+  m_Renderer = PaintbrushRenderer::New();
+  m_Renderer->SetParentRenderer(
+        static_cast<GenericSliceRenderer *>(parent->GetRenderer()));
+
+  m_Model = NULL;
+}
+
+PaintbrushInteractionMode::~PaintbrushInteractionMode()
+{
+}
+
+void
+PaintbrushInteractionMode
+::SetModel(PaintbrushModel *model)
+{
+  m_Model = model;
+  m_Renderer->SetModel(model);
+  SetParentModel(model->GetParent());
+}
+
+void PaintbrushInteractionMode::mousePressEvent(QMouseEvent *ev)
+{
+  bool isleft = (ev->button() == Qt::LeftButton);
+  bool isright = (ev->button() == Qt::RightButton);
+  if(isleft || isright)
+    {
+    if(m_Model->ProcessPushEvent(to_float(m_XSlice),isright))
+      ev->accept();
+    }
+}
+
+void PaintbrushInteractionMode::mouseMoveEvent(QMouseEvent *ev)
+{
+  ev->ignore();
+
+  if(isDragging())
+    {
+    if(m_Model->ProcessDragEvent(
+         to_float(m_XSlice), to_float(m_LastPressXSlice),
+         GetNumberOfPixelsMoved(ev), false))
+      {
+      ev->accept();
+      }
+    }
+  else
+    {
+    if(m_Model->ProcessMouseMoveEvent(to_float(m_XSlice)))
+      ev->accept();
+    }
+}
+
+void PaintbrushInteractionMode::mouseReleaseEvent(QMouseEvent *ev)
+{
+  if(m_Model->ProcessDragEvent(
+       to_float(m_XSlice), to_float(m_LastPressXSlice),
+       GetNumberOfPixelsMoved(ev), true))
+    {
+    ev->accept();
+    }
+}
+
+void PaintbrushInteractionMode::enterEvent(QEvent *)
+{
+  // TODO: this is hideous!
+  SliceViewPanel *panel = dynamic_cast<SliceViewPanel *>(m_ParentView->parent());
+  panel->SetMouseMotionTracking(true);
+}
+
+void PaintbrushInteractionMode::leaveEvent(QEvent *)
+{
+  SliceViewPanel *panel = dynamic_cast<SliceViewPanel *>(m_ParentView->parent());
+  panel->SetMouseMotionTracking(false);
+
+  // This fixes a crash when you press quit in paintbrush mode
+  if(panel->isVisible())
+    m_Model->ProcessMouseLeaveEvent();
+}
+
+void PaintbrushInteractionMode::keyPressEvent(QKeyEvent *ev)
+{
+  if(ev->key() == Qt::Key_Space)
+    m_Model->AcceptAtCursor();
+}
+
+
+void PaintbrushInteractionMode::onModelUpdate(const EventBucket &bucket)
+{
+}
diff --git a/GUI/Qt/View/PaintbrushInteractionMode.h b/GUI/Qt/View/PaintbrushInteractionMode.h
new file mode 100644
index 0000000..04a9d7d
--- /dev/null
+++ b/GUI/Qt/View/PaintbrushInteractionMode.h
@@ -0,0 +1,45 @@
+#ifndef PAINTBRUSHINTERACTIONMODE_H
+#define PAINTBRUSHINTERACTIONMODE_H
+
+#include <SliceWindowInteractionDelegateWidget.h>
+#include <SNAPCommon.h>
+
+class GenericSliceModel;
+class GenericSliceView;
+class PaintbrushModel;
+class PaintbrushRenderer;
+
+class PaintbrushInteractionMode : public SliceWindowInteractionDelegateWidget
+{
+  Q_OBJECT
+
+public:
+  PaintbrushInteractionMode(GenericSliceView *parent = 0);
+  ~PaintbrushInteractionMode();
+
+  irisGetMacro(Model, PaintbrushModel *)
+  void SetModel(PaintbrushModel *m_Model);
+
+  irisGetMacro(Renderer, PaintbrushRenderer *)
+
+
+  void mousePressEvent(QMouseEvent *ev);
+  void mouseMoveEvent(QMouseEvent *ev);
+  void mouseReleaseEvent(QMouseEvent *ev);
+
+  void enterEvent(QEvent *);
+  void leaveEvent(QEvent *);
+
+  void keyPressEvent(QKeyEvent *ev);
+
+public slots:
+
+  void onModelUpdate(const EventBucket &bucket);
+
+protected:
+
+  PaintbrushModel *m_Model;
+  SmartPtr<PaintbrushRenderer> m_Renderer;
+};
+
+#endif // PAINTBRUSHINTERACTIONMODE_H
diff --git a/GUI/Qt/View/PolygonDrawingInteractionMode.cxx b/GUI/Qt/View/PolygonDrawingInteractionMode.cxx
new file mode 100644
index 0000000..201f368
--- /dev/null
+++ b/GUI/Qt/View/PolygonDrawingInteractionMode.cxx
@@ -0,0 +1,220 @@
+#include "PolygonDrawingInteractionMode.h"
+#include "PolygonDrawingRenderer.h"
+#include "PolygonDrawingModel.h"
+#include "QtAbstractOpenGLBox.h"
+#include "QtWarningDialog.h"
+#include "QtWidgetActivator.h"
+#include "IRISApplication.h"
+#include "GlobalState.h"
+#include "GenericSliceView.h"
+
+#include <QMenu>
+
+QAction *setupAction(PolygonDrawingInteractionMode *w, QMenu *menu,
+                     QString icon, QString sshort, QString slong,
+                     const char *slotname,
+                     PolygonDrawingUIState flag1,
+                     PolygonDrawingUIState flag2)
+{
+  QAction *action = new QAction(w);
+  action->setText(slong);
+  action->setIconText(sshort);
+  if(icon.length())
+    action->setIcon(QIcon(QString(":/root/%1.png").arg(icon)));
+
+  // activateOnAllFlags(action, w->GetModel(), flag1, flag2);
+
+  menu->addAction(action);
+
+  // connect(action, SIGNAL(triggered()), w, slotname);
+
+  return action;
+}
+
+
+PolygonDrawingInteractionMode
+::PolygonDrawingInteractionMode(GenericSliceView *parent) :
+    SliceWindowInteractionDelegateWidget(parent)
+{
+  m_Renderer = PolygonDrawingRenderer::New();
+  m_Renderer->SetParentRenderer(
+        static_cast<GenericSliceRenderer *>(parent->GetRenderer()));
+  m_Model = NULL;
+}
+
+PolygonDrawingInteractionMode
+::~PolygonDrawingInteractionMode()
+{
+
+}
+
+void
+PolygonDrawingInteractionMode
+::SetModel(PolygonDrawingModel *model)
+{
+  m_Model = model;
+  m_Renderer->SetModel(model);
+  SetParentModel(model->GetParent());
+
+  // Listen to events in the model (update buttons)
+  connectITK(m_Model, StateMachineChangeEvent());
+}
+
+void PolygonDrawingInteractionMode::onModelUpdate(const EventBucket &bucket)
+{
+  update();
+}
+
+void PolygonDrawingInteractionMode::mousePressEvent(QMouseEvent *ev)
+{
+  // Call the model's code
+  if(ev->button() == Qt::LeftButton)
+    {
+    if(m_Model->ProcessPushEvent(m_XSlice(0), m_XSlice(1),
+                                 ev->modifiers().testFlag(Qt::ShiftModifier)))
+      {
+      ev->accept();
+      }
+    }
+}
+
+void PolygonDrawingInteractionMode::mouseMoveEvent(QMouseEvent *ev)
+{
+  ev->ignore();
+  if(m_LeftDown)
+    {
+    if(m_Model->ProcessDragEvent(m_XSlice(0), m_XSlice(1)))
+      {
+      ev->accept();
+      }
+    }
+  else if (!isDragging())
+    {
+    if(m_Model->ProcessMouseMoveEvent(m_XSlice(0), m_XSlice(1)))
+      {
+      ev->accept();
+      m_ParentView->update();
+      }
+    }
+}
+
+void PolygonDrawingInteractionMode::mouseReleaseEvent(QMouseEvent *ev)
+{
+  if(ev->button() == Qt::LeftButton)
+    {
+    if(m_Model->ProcessReleaseEvent(m_XSlice(0), m_XSlice(1)))
+      {
+      ev->accept();
+      }
+    }
+}
+
+void PolygonDrawingInteractionMode
+::contextMenuEvent(QContextMenuEvent *ev)
+{
+  // We bring up the context menu on the right click only if the option
+  // is enabled. But we always bring it up if there are modifiers
+  if(m_ParentModel->GetDriver()->GetGlobalState()->GetPolygonDrawingContextMenu()
+     || ev->modifiers().testFlag(Qt::ControlModifier)
+     || ev->modifiers().testFlag(Qt::MetaModifier))
+    {
+    emit contextMenuRequested();
+    }
+}
+
+/* ==============================
+   SLOTS
+   ============================== */
+
+void PolygonDrawingInteractionMode::onPastePolygon()
+{
+  m_Model->PastePolygon();
+}
+
+
+void PolygonDrawingInteractionMode::onAcceptPolygon()
+{
+  // Make current GL context current before running any GL operations
+  QtAbstractOpenGLBox *parent = this->GetParentGLWidget();
+  parent->makeCurrent();
+
+  // This is hacky, but we need the viewport in the parent GL widget to be
+  // set to the entire window. This is needed because the rendering of the
+  // slice view may set up multiple viewports, and for polygon rasterization
+  // we only need one.
+  glViewport(0, 0, parent->width(), parent->height());
+
+  // Create a warning list
+  std::vector<IRISWarning> warnings;
+
+  // Call accept polygon code
+  m_Model->AcceptPolygon(warnings);
+
+  // Display the warnings
+  if(warnings.size())
+    {
+    QtWarningDialog::show(warnings);
+    }
+}
+
+
+void PolygonDrawingInteractionMode::onSplitSelected()
+{
+  m_Model->Insert();
+}
+
+
+void PolygonDrawingInteractionMode::onDeleteSelected()
+{
+  m_Model->Delete();
+}
+
+
+void PolygonDrawingInteractionMode::onClearPolygon()
+{
+  m_Model->Reset();
+}
+
+
+void PolygonDrawingInteractionMode::onCloseLoopAndEdit()
+{
+  m_Model->ClosePolygon();
+}
+
+
+void PolygonDrawingInteractionMode::onCloseLoopAndAccept()
+{
+  onCloseLoopAndEdit();
+  onAcceptPolygon();
+}
+
+
+void PolygonDrawingInteractionMode::onUndoLastPoint()
+{
+  m_Model->DropLastPoint();
+}
+
+
+void PolygonDrawingInteractionMode::onCancelDrawing()
+{
+  m_Model->Reset();
+}
+
+#include <SliceViewPanel.h>
+
+void PolygonDrawingInteractionMode::enterEvent(QEvent *)
+{
+  // TODO: this is hideous!
+  SliceViewPanel *panel = dynamic_cast<SliceViewPanel *>(m_ParentView->parent());
+  panel->SetMouseMotionTracking(true);
+}
+
+void PolygonDrawingInteractionMode::leaveEvent(QEvent *)
+{
+  SliceViewPanel *panel = dynamic_cast<SliceViewPanel *>(m_ParentView->parent());
+  panel->SetMouseMotionTracking(false);
+}
+
+
+
+
diff --git a/GUI/Qt/View/PolygonDrawingInteractionMode.h b/GUI/Qt/View/PolygonDrawingInteractionMode.h
new file mode 100644
index 0000000..2ef842d
--- /dev/null
+++ b/GUI/Qt/View/PolygonDrawingInteractionMode.h
@@ -0,0 +1,63 @@
+#ifndef POLYGONDRAWINGINTERACTIONMODE_H
+#define POLYGONDRAWINGINTERACTIONMODE_H
+
+#include <SliceWindowInteractionDelegateWidget.h>
+#include <SNAPCommon.h>
+
+class GenericSliceModel;
+class GenericSliceView;
+class PolygonDrawingModel;
+class PolygonDrawingRenderer;
+
+class QMenu;
+class QAction;
+
+class PolygonDrawingInteractionMode : public SliceWindowInteractionDelegateWidget
+{
+  Q_OBJECT
+
+public:
+  explicit PolygonDrawingInteractionMode(GenericSliceView *parent = 0);
+  ~PolygonDrawingInteractionMode();
+
+  irisGetMacro(Model, PolygonDrawingModel *)
+  void SetModel(PolygonDrawingModel *m_Model);
+
+  irisGetMacro(Renderer, PolygonDrawingRenderer *)
+
+
+  void mousePressEvent(QMouseEvent *ev);
+  void mouseMoveEvent(QMouseEvent *ev);
+  void mouseReleaseEvent(QMouseEvent *ev);
+  void enterEvent(QEvent *);
+  void leaveEvent(QEvent *);
+
+  void contextMenuEvent(QContextMenuEvent *);
+
+signals:
+
+  void contextMenuRequested();
+
+public slots:
+
+  void onPastePolygon();
+  void onAcceptPolygon();
+  void onSplitSelected();
+  void onDeleteSelected();
+  void onClearPolygon();
+  void onCloseLoopAndEdit();
+  void onCloseLoopAndAccept();
+  void onUndoLastPoint();
+  void onCancelDrawing();
+
+  void onModelUpdate(const EventBucket &bucket);
+
+
+protected:
+
+  PolygonDrawingModel *m_Model;
+  SmartPtr<PolygonDrawingRenderer> m_Renderer;
+
+};
+
+#endif // POLYGONDRAWINGINTERACTIONMODE_H
diff --git a/GUI/Qt/View/QtAbstractOpenGLBox.cxx b/GUI/Qt/View/QtAbstractOpenGLBox.cxx
new file mode 100644
index 0000000..730cd59
--- /dev/null
+++ b/GUI/Qt/View/QtAbstractOpenGLBox.cxx
@@ -0,0 +1,157 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "QtAbstractOpenGLBox.h"
+#include <QMouseEvent>
+#include <QStackedLayout>
+#include <QWindow>
+#include <QtInteractionDelegateWidget.h>
+#include "LatentITKEventNotifier.h"
+#include "SNAPOpenGL.h"
+#include <AbstractRenderer.h>
+#include "SNAPQtCommon.h"
+
+#include <vtkSmartPointer.h>
+#include <vtkImageData.h>
+
+#include "GLToPNG.h"
+
+QtAbstractOpenGLBox::QtAbstractOpenGLBox(QWidget *parent) :
+    QGLWidget(parent)
+{
+  m_NeedResizeOnNextRepaint = false;
+  m_GrabFocusOnEntry = false;
+}
+
+void QtAbstractOpenGLBox::AttachSingleDelegate(QtInteractionDelegateWidget *delegate)
+{
+  // Install the delegate
+  // QStackedLayout *l = new QStackedLayout();
+  // l->addWidget(delegate);
+  // this->setLayout(l);
+
+  // Delegate handles all of our events
+  this->installEventFilter(delegate);
+}
+
+bool QtAbstractOpenGLBox::SaveScreenshot(std::string filename)
+{
+  m_ScreenshotRequest = from_utf8(filename);
+  this->repaint();
+  return true;
+}
+
+
+void
+QtAbstractOpenGLBox
+::connectITK(itk::Object *src, const itk::EventObject &ev, const char *slot)
+{
+  LatentITKEventNotifier::connect(src, ev, this, slot);
+}
+
+void QtAbstractOpenGLBox::paintGL()
+{
+  // Update the renderer. This will cause the renderer to update itself
+  // based on any events that it has received upstream.
+  GetRenderer()->Update();
+
+  // Get width and height in pixels
+  int wp = (int) this->size().width() * this->windowHandle()->devicePixelRatio();
+  int hp = (int) this->size().height() * this->windowHandle()->devicePixelRatio();
+
+  // Qt bug workaround
+  if(m_NeedResizeOnNextRepaint)
+    {
+    GetRenderer()->resizeGL(wp, hp);
+    m_NeedResizeOnNextRepaint = false;
+    }
+
+  // Do the actual painting
+  GetRenderer()->paintGL();
+
+  // If screenshot set, handle it
+  if(m_ScreenshotRequest.length())
+    {
+    try
+      {
+      vtkSmartPointer<vtkImageData> image = GLToVTKImageData(
+            (unsigned int) GL_RGB, 0, 0, wp, hp);
+      std::string fn = to_utf8(m_ScreenshotRequest);
+      VTKImageDataToPNG(image, fn.c_str());
+      }
+    catch(...)
+      {
+      // TODO: should we notify user of failures?
+      }
+    m_ScreenshotRequest = QString();
+    }
+}
+
+void QtAbstractOpenGLBox::resizeGL(int w, int h)
+{
+  GetRenderer()->Update();
+  GetRenderer()->resizeGL(w, h);
+}
+
+void QtAbstractOpenGLBox::initializeGL()
+{
+  GetRenderer()->Update();
+  GetRenderer()->initializeGL();
+}
+
+void QtAbstractOpenGLBox::resizeEvent(QResizeEvent *)
+{
+  // This is a workaround for a Qt bug. It didn't take long to find bugs
+  // in Qt. How sad.
+  m_NeedResizeOnNextRepaint = true;
+
+  // Set geometry of all child widgets (which are interactors)
+  QList<QWidget *> kids = this->findChildren<QWidget *>();
+  for(int i = 0; i < kids.size(); i++)
+    kids.at(i)->setGeometry(this->geometry());
+}
+
+
+void QtAbstractOpenGLBox::enterEvent(QEvent *)
+{
+  if(m_GrabFocusOnEntry)
+    this->setFocus();
+}
+
+void QtAbstractOpenGLBox::leaveEvent(QEvent *)
+{
+  if(m_GrabFocusOnEntry)
+    this->clearFocus();
+}
+
+
+
+
+
+
+
+
+
diff --git a/GUI/Qt/View/QtAbstractOpenGLBox.h b/GUI/Qt/View/QtAbstractOpenGLBox.h
new file mode 100644
index 0000000..223ba5a
--- /dev/null
+++ b/GUI/Qt/View/QtAbstractOpenGLBox.h
@@ -0,0 +1,107 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTABSTRACTOPENGLBOX_H
+#define QTABSTRACTOPENGLBOX_H
+
+#include <QGLWidget>
+#include <SNAPCommon.h>
+#include <SNAPEvents.h>
+
+class QMouseEvent;
+class EventBucket;
+class QtInteractionDelegateWidget;
+class AbstractRenderer;
+
+namespace itk { class Object; }
+
+class QtAbstractOpenGLBox : public QGLWidget
+{
+  Q_OBJECT
+
+public:
+  explicit QtAbstractOpenGLBox(QWidget *parent = 0);
+
+  // Whether to grab keyboard focus when the mouse enters this widget
+  irisGetSetMacro(GrabFocusOnEntry, bool)
+
+  /**
+    Use this function when the GL widget is only associated with a single
+    interaction mode.
+    */
+  void AttachSingleDelegate(QtInteractionDelegateWidget *delegate);
+
+  /**
+    The child class must override this method to return its pointer to the
+    renderer object. Every instance of this object must have a renderer.
+    */
+  virtual AbstractRenderer* GetRenderer() const = 0;
+
+  /**
+   Take a screenshot, save to a PNG file
+   */
+  virtual bool SaveScreenshot(std::string filename);
+
+public slots:
+
+  // Default slot for model updates
+  virtual void onModelUpdate(const EventBucket &bucket) {}
+
+protected:
+
+  /** Register to receive ITK events from object src. Events will be cached in
+    an event bucket and delivered once execution returns to the UI loop */
+  void connectITK(itk::Object *src, const itk::EventObject &ev,
+                  const char *slot = SLOT(onModelUpdate(const EventBucket &)));
+
+  // OpenGL painter methods
+  virtual void paintGL();
+  virtual void resizeGL(int w, int h);
+  virtual void initializeGL();
+
+  // Resize event
+  virtual void resizeEvent(QResizeEvent *);
+  virtual void enterEvent(QEvent *);
+  virtual void leaveEvent(QEvent *);
+
+  // Whether we need to call GL resize next time a paint command occurs
+  bool m_NeedResizeOnNextRepaint;
+
+  // Whether this widget grabs keyboard focus when the mouse enters it
+  bool m_GrabFocusOnEntry;
+
+  // Whether a screenshot has been requested (non-empty string)
+  QString m_ScreenshotRequest;
+
+signals:
+
+public slots:
+
+};
+
+
+
+#endif // QTABSTRACTOPENGLBOX_H
diff --git a/GUI/Qt/View/QtInteractionDelegateWidget.cxx b/GUI/Qt/View/QtInteractionDelegateWidget.cxx
new file mode 100644
index 0000000..588f5c3
--- /dev/null
+++ b/GUI/Qt/View/QtInteractionDelegateWidget.cxx
@@ -0,0 +1,163 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "QtInteractionDelegateWidget.h"
+#include <QtAbstractOpenGLBox.h>
+#include <QMouseEvent>
+#include <QGestureEvent>
+#include "GenericSliceModel.h"
+#include "SNAPOpenGL.h"
+
+QtInteractionDelegateWidget::QtInteractionDelegateWidget(QWidget *parent) :
+  SNAPComponent(parent)
+{
+  m_LeftDown = false;
+  m_MiddleDown = false;
+  m_RightDown = false;
+  m_Filtering = false;
+
+  // The widget is hidden
+  this->hide();
+}
+
+bool QtInteractionDelegateWidget::event(QEvent *ev)
+{
+  // If the event was sent to the widget itself, ignore it. The delegate
+  // only should receive events through the sender
+  if(!m_Filtering)
+    return false;
+
+  // Generate data from this event
+  preprocessEvent(ev);
+
+  // Deal with gesture events
+  if(ev->type() == QEvent::Gesture)
+    return gestureEvent(static_cast<QGestureEvent*>(ev));
+  else return QWidget::event(ev);
+}
+
+QtAbstractOpenGLBox * QtInteractionDelegateWidget::GetParentGLWidget() const
+{
+  // Search up until a parent widget is found
+  for(QObject *p = parent(); p != NULL; p = p->parent())
+    {
+    QtAbstractOpenGLBox *pgl = dynamic_cast<QtAbstractOpenGLBox *>(p);
+    if(pgl)
+      return pgl;
+    }
+
+  return NULL;
+}
+
+bool QtInteractionDelegateWidget::eventFilter(QObject *obj, QEvent *ev)
+{
+  ev->setAccepted(false);
+  m_Filtering = true;
+  this->event(ev);
+  m_Filtering = false;
+
+  if(ev->isAccepted())
+    return true;
+  else return QWidget::eventFilter(obj, ev);
+}
+
+void QtInteractionDelegateWidget::preprocessEvent(QEvent *ev)
+{
+  // Deal with mouse events
+  if(ev->type() == QEvent::MouseButtonPress ||
+     ev->type() == QEvent::MouseButtonRelease ||
+     ev->type() == QEvent::MouseMove ||
+     ev->type() == QEvent::MouseButtonDblClick)
+    {
+    // Compute the spatial location of the event
+    QMouseEvent *emouse = static_cast<QMouseEvent *>(ev);
+    m_XSpace = this->GetEventWorldCoordinates(emouse, true);
+
+    // If a mouse press, back up this info for drag tracking
+    if(ev->type() == QEvent::MouseButtonPress)
+      {
+      m_LastPressPos = emouse->pos();
+      m_LastPressGlobalPos = emouse->globalPos();
+      m_LastPressButton = emouse->button();
+      m_LastPressXSpace = m_XSpace;
+
+      // Store what buttons are up or down
+      if(emouse->button() == Qt::LeftButton)
+        m_LeftDown = true;
+      if(emouse->button() == Qt::RightButton)
+        m_RightDown = true;
+      if(emouse->button() == Qt::MiddleButton)
+        m_MiddleDown = true;
+      }
+    else if(ev->type() == QEvent::MouseButtonRelease)
+      {
+      // Store what buttons are up or down
+      if(emouse->button() == Qt::LeftButton)
+        m_LeftDown = false;
+      if(emouse->button() == Qt::RightButton)
+        m_RightDown = false;
+      if(emouse->button() == Qt::MiddleButton)
+        m_MiddleDown = false;
+      }
+    }
+}
+
+Vector3d
+QtInteractionDelegateWidget
+::GetEventWorldCoordinates(QMouseEvent *ev, bool flipY)
+{
+  // Make the parent window the current context
+  QtAbstractOpenGLBox *parent = this->GetParentGLWidget();
+  parent->makeCurrent();
+
+  // Convert the event coordinates into the model view coordinates
+  double modelMatrix[16], projMatrix[16];
+  GLint viewport[4];
+  glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
+  glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
+  glGetIntegerv(GL_VIEWPORT,viewport);
+
+  // For retina displays, these are the 'logical' coordinates of the event
+  int lx = ev->x();
+  int ly = (flipY) ? parent->height() - 1 - ev->y() : ev->y();
+
+  // Scale to actual pixels for the unproject call
+  double px = lx * parent->window()->devicePixelRatio();
+  double py = ly * parent->window()->devicePixelRatio();
+
+  // Unproject to get the coordinate of the event
+  Vector3d xProjection;
+  gluUnProject(px, py, 0,
+               modelMatrix,projMatrix,viewport,
+               &xProjection[0], &xProjection[1], &xProjection[2]);
+  return xProjection;
+}
+
+double QtInteractionDelegateWidget::GetNumberOfPixelsMoved(QMouseEvent *ev)
+{
+  QPoint delta = ev->pos() - m_LastPressPos;
+  return std::sqrt((double)(delta.x() * delta.x() + delta.y() * delta.y()));
+}
diff --git a/GUI/Qt/View/QtInteractionDelegateWidget.h b/GUI/Qt/View/QtInteractionDelegateWidget.h
new file mode 100644
index 0000000..0123b10
--- /dev/null
+++ b/GUI/Qt/View/QtInteractionDelegateWidget.h
@@ -0,0 +1,96 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTINTERACTIONDELEGATEWIDGET_H
+#define QTINTERACTIONDELEGATEWIDGET_H
+
+#include <QWidget>
+#include <SNAPCommon.h>
+#include <QMouseEvent>
+#include <SNAPComponent.h>
+
+class QtAbstractOpenGLBox;
+class QGestureEvent;
+class GenericSliceModel;
+
+class QtInteractionDelegateWidget : public SNAPComponent
+{
+  Q_OBJECT
+
+public:
+  explicit QtInteractionDelegateWidget(QWidget *parent = 0);
+
+signals:
+
+public slots:
+
+protected:
+
+  // Event handler
+  virtual bool event(QEvent *);
+
+  // Handler for event filtering
+  virtual bool eventFilter(QObject *, QEvent *ev);
+
+  // Children may override this method to provide additional event processing,
+  // but should call QtInteractionDelegateWidget::preprocessEvent in there.
+  virtual void preprocessEvent(QEvent *);
+
+  // Get the world coordinates of the Qt event. The default implementation uses
+  // the current GL viewport, projection and model matrices of the parent GL
+  // widget.
+  virtual Vector3d GetEventWorldCoordinates(QMouseEvent *ev, bool flipY);
+
+  // Gesture event handler
+  virtual bool gestureEvent(QGestureEvent *ev)
+    { return false; }
+
+  virtual bool isDragging()
+    { return m_LeftDown || m_RightDown || m_MiddleDown; }
+
+  // Return the number of pixels moved since last press
+  double GetNumberOfPixelsMoved(QMouseEvent *ev);
+
+  // Get a pointer to the parent GL widget
+  QtAbstractOpenGLBox *GetParentGLWidget() const;
+
+  // Information about the mouse press event
+  QPoint m_LastPressPos, m_LastPressGlobalPos;
+  Qt::MouseButton m_LastPressButton;
+
+  // Spatial coordinates of the last press event, current event
+  Vector3d m_LastPressXSpace, m_XSpace;
+
+  // Whether we are between a press and a release for a particular button
+  bool m_LeftDown, m_RightDown, m_MiddleDown;
+
+  // Whether we are currently filtering an event from another widget
+  bool m_Filtering;
+
+
+};
+
+#endif // QTINTERACTIONDELEGATEWIDGET_H
diff --git a/GUI/Qt/View/QtSimpleOpenGLBox.cxx b/GUI/Qt/View/QtSimpleOpenGLBox.cxx
new file mode 100644
index 0000000..23a42b0
--- /dev/null
+++ b/GUI/Qt/View/QtSimpleOpenGLBox.cxx
@@ -0,0 +1,27 @@
+#include "QtSimpleOpenGLBox.h"
+#include "AbstractRenderer.h"
+
+QtSimpleOpenGLBox::QtSimpleOpenGLBox(QWidget *parent)
+  : QtAbstractOpenGLBox(parent)
+{
+  m_Renderer = NULL;
+}
+
+void QtSimpleOpenGLBox::onModelUpdate(const EventBucket &bucket)
+{
+  if(this->isVisible())
+    {
+    // TODO: this seems redundant, Update is already called in the paint method
+    // of the renderer, and update() just causes paint to be called.
+    if(m_Renderer)
+      m_Renderer->Update();
+
+    this->update();
+    }
+}
+
+void QtSimpleOpenGLBox::SetRenderer(AbstractRenderer *renderer)
+{
+  m_Renderer = renderer;
+  connectITK(m_Renderer, ModelUpdateEvent());
+}
diff --git a/GUI/Qt/View/QtSimpleOpenGLBox.h b/GUI/Qt/View/QtSimpleOpenGLBox.h
new file mode 100644
index 0000000..d5ea252
--- /dev/null
+++ b/GUI/Qt/View/QtSimpleOpenGLBox.h
@@ -0,0 +1,38 @@
+#ifndef QTSIMPLEOPENGLBOX_H
+#define QTSIMPLEOPENGLBOX_H
+
+#include <QtAbstractOpenGLBox.h>
+
+/**
+  This is an actual implementation of a SNAPQGLWidget that can be inserted
+  into a widget without having to create a separate custom widget. The user
+  must supply a renderer, which in turn must fire ModelUpdateEvent() to force
+  this widget to redraw.
+
+  TODO: add interaction support
+  */
+class QtSimpleOpenGLBox : public QtAbstractOpenGLBox
+{
+  Q_OBJECT
+
+public:
+
+  explicit QtSimpleOpenGLBox(QWidget *parent = 0);
+
+  // Set the renderer in this widget
+  void SetRenderer(AbstractRenderer *renderer);
+
+  // Get the renderer for this widget
+  irisGetMacro(Renderer, AbstractRenderer *)
+
+public slots:
+
+  virtual void onModelUpdate(const EventBucket &bucket);
+
+protected:
+
+  AbstractRenderer *m_Renderer;
+
+};
+
+#endif // QTSIMPLEOPENGLBOX_H
diff --git a/GUI/Qt/View/QtVTKInteractionDelegateWidget.cxx b/GUI/Qt/View/QtVTKInteractionDelegateWidget.cxx
new file mode 100644
index 0000000..a70b7a7
--- /dev/null
+++ b/GUI/Qt/View/QtVTKInteractionDelegateWidget.cxx
@@ -0,0 +1,80 @@
+#include "QtVTKInteractionDelegateWidget.h"
+#include "vtkRenderWindowInteractor.h"
+#include "QtAbstractOpenGLBox.h"
+#include <QApplication>
+#include <QWindow>
+
+QtVTKInteractionDelegateWidget::QtVTKInteractionDelegateWidget(QWidget *parent) :
+    QtInteractionDelegateWidget(parent)
+{
+}
+
+void QtVTKInteractionDelegateWidget::SetVTKEventState(QMouseEvent *ev)
+{
+  Qt::KeyboardModifiers km = QApplication::keyboardModifiers();
+
+  // Account for Retina displays
+  int x = ev->pos().x() * this->windowHandle()->devicePixelRatio();
+  int y = ev->pos().y() * this->windowHandle()->devicePixelRatio();
+
+  m_VTKInteractor->SetEventInformationFlipY(
+        x, y, 
+        km.testFlag(Qt::ControlModifier),
+        km.testFlag(Qt::ShiftModifier));
+}
+
+void QtVTKInteractionDelegateWidget::mousePressEvent(QMouseEvent *ev)
+{
+  // Set the position information
+  SetVTKEventState(ev);
+
+  // Fire appropriate event
+  if(ev->button() == Qt::LeftButton)
+    m_VTKInteractor->LeftButtonPressEvent();
+  else if(ev->button() == Qt::RightButton)
+    m_VTKInteractor->RightButtonPressEvent();
+  else if(ev->button() == Qt::MiddleButton)
+    m_VTKInteractor->MiddleButtonPressEvent();
+
+  // TODO: why do we need to force this?
+  this->GetParentGLWidget()->update();
+}
+
+void QtVTKInteractionDelegateWidget::mouseReleaseEvent(QMouseEvent *ev)
+{
+  // Set the position information
+  SetVTKEventState(ev);
+
+  // Fire appropriate event
+  if(ev->button() == Qt::LeftButton)
+    m_VTKInteractor->LeftButtonReleaseEvent();
+  else if(ev->button() == Qt::RightButton)
+    m_VTKInteractor->RightButtonReleaseEvent();
+  else if(ev->button() == Qt::MiddleButton)
+    m_VTKInteractor->MiddleButtonReleaseEvent();
+
+  // TODO: why do we need to force this?
+  this->GetParentGLWidget()->update();
+}
+
+void QtVTKInteractionDelegateWidget::mouseMoveEvent(QMouseEvent *ev)
+{
+  // Set the position information
+  SetVTKEventState(ev);
+  m_VTKInteractor->MouseMoveEvent();
+
+  // TODO: why do we need to force this?
+  this->GetParentGLWidget()->update();
+}
+
+void QtVTKInteractionDelegateWidget::SetVTKInteractor(vtkRenderWindowInteractor *iren)
+{
+  m_VTKInteractor = iren;
+}
+
+vtkRenderWindowInteractor * QtVTKInteractionDelegateWidget::GetVTKInteractor() const
+{
+  return m_VTKInteractor;
+}
+
+
diff --git a/GUI/Qt/View/QtVTKInteractionDelegateWidget.h b/GUI/Qt/View/QtVTKInteractionDelegateWidget.h
new file mode 100644
index 0000000..b739f5d
--- /dev/null
+++ b/GUI/Qt/View/QtVTKInteractionDelegateWidget.h
@@ -0,0 +1,39 @@
+#ifndef QTVTKINTERACTIONDELEGATEWIDGET_H
+#define QTVTKINTERACTIONDELEGATEWIDGET_H
+
+#include "QtInteractionDelegateWidget.h"
+#include "vtkSmartPointer.h"
+
+class vtkRenderWindowInteractor;
+
+/**
+  This interaction delegate simply passes selected events from Qt to
+  events in the vtkRenderWindowInteractor class.
+  */
+class QtVTKInteractionDelegateWidget : public QtInteractionDelegateWidget
+{
+  Q_OBJECT
+public:
+  explicit QtVTKInteractionDelegateWidget(QWidget *parent = 0);
+
+  void mousePressEvent(QMouseEvent *);
+  void mouseReleaseEvent(QMouseEvent *);
+  void mouseMoveEvent(QMouseEvent *);
+
+  void SetVTKInteractor(vtkRenderWindowInteractor *iren);
+  vtkRenderWindowInteractor *GetVTKInteractor() const;
+
+signals:
+
+public slots:
+
+
+protected:
+
+  void SetVTKEventState(QMouseEvent *ev);
+
+  // The vtkRenderWindowInteractor that receives our events
+  vtkSmartPointer<vtkRenderWindowInteractor> m_VTKInteractor;
+};
+
+#endif // QTVTKINTERACTIONDELEGATEWIDGET_H
diff --git a/GUI/Qt/View/QtVTKRenderWindowBox.cxx b/GUI/Qt/View/QtVTKRenderWindowBox.cxx
new file mode 100644
index 0000000..b5d792a
--- /dev/null
+++ b/GUI/Qt/View/QtVTKRenderWindowBox.cxx
@@ -0,0 +1,54 @@
+#include "QtVTKRenderWindowBox.h"
+#include "AbstractVTKRenderer.h"
+#include "QtVTKInteractionDelegateWidget.h"
+#include "vtkRenderWindow.h"
+#include "vtkCommand.h"
+
+QtVTKRenderWindowBox::QtVTKRenderWindowBox(QWidget *parent) :
+  QtSimpleOpenGLBox(parent)
+{
+  m_InteractionDelegate = new QtVTKInteractionDelegateWidget(this);
+  this->AttachSingleDelegate(m_InteractionDelegate);
+}
+
+void QtVTKRenderWindowBox::SetRenderer(AbstractRenderer *renderer)
+{
+  // Cast to the VTK type
+  AbstractVTKRenderer *renvtk = dynamic_cast<AbstractVTKRenderer *>(renderer);
+  if(renvtk)
+    {
+    // Hook up the interaction delegate
+    m_InteractionDelegate->SetVTKInteractor(renvtk->GetRenderWindowInteractor());
+    }
+
+  // Hook up context-related events (is this needed?)
+  renvtk->GetRenderWindow()->AddObserver(
+        vtkCommand::WindowMakeCurrentEvent,
+        this, &QtVTKRenderWindowBox::RendererCallback);
+
+  renvtk->GetRenderWindow()->AddObserver(
+        vtkCommand::WindowIsCurrentEvent,
+        this, &QtVTKRenderWindowBox::RendererCallback);
+
+  // Call parent method
+  QtSimpleOpenGLBox::SetRenderer(renderer);
+}
+
+void
+QtVTKRenderWindowBox
+::RendererCallback(
+    vtkObject *src, unsigned long event, void *data)
+{
+  if(event == vtkCommand::WindowMakeCurrentEvent)
+    {
+    this->makeCurrent();
+    }
+  else if(event == vtkCommand::WindowIsCurrentEvent)
+    {
+    bool *result = static_cast<bool *>(data);
+    *result = QGLContext::currentContext() == this->context();
+    }
+}
+
+
+
diff --git a/GUI/Qt/View/QtVTKRenderWindowBox.h b/GUI/Qt/View/QtVTKRenderWindowBox.h
new file mode 100644
index 0000000..4f92514
--- /dev/null
+++ b/GUI/Qt/View/QtVTKRenderWindowBox.h
@@ -0,0 +1,35 @@
+#ifndef QTVTKRENDERWINDOWBOX_H
+#define QTVTKRENDERWINDOWBOX_H
+
+#include <QtSimpleOpenGLBox.h>
+
+class AbstractVTKRenderer;
+class QtVTKInteractionDelegateWidget;
+class vtkObject;
+
+
+/**
+ * This is a qt widget that interfaces with an AbstractVTKRenderer.
+ * The widget includes a delegate for passing events to the interactor
+ * stored in the AbstractVTKRenderer.
+ */
+class QtVTKRenderWindowBox : public QtSimpleOpenGLBox
+{
+  Q_OBJECT
+
+public:
+  explicit QtVTKRenderWindowBox(QWidget *parent = 0);
+
+  virtual void SetRenderer(AbstractRenderer *renderer);
+  
+signals:
+  
+protected:
+
+  QtVTKInteractionDelegateWidget *m_InteractionDelegate;
+
+  void RendererCallback(vtkObject *src, unsigned long event, void *data);
+
+};
+
+#endif // QTVTKRENDERWINDOWBOX_H
diff --git a/GUI/Qt/View/SliceWindowInteractionDelegateWidget.cxx b/GUI/Qt/View/SliceWindowInteractionDelegateWidget.cxx
new file mode 100644
index 0000000..21df2fa
--- /dev/null
+++ b/GUI/Qt/View/SliceWindowInteractionDelegateWidget.cxx
@@ -0,0 +1,105 @@
+#include "SliceWindowInteractionDelegateWidget.h"
+#include "GenericSliceModel.h"
+#include "GenericSliceView.h"
+#include "GlobalUIModel.h"
+#include "DisplayLayoutModel.h"
+
+SliceWindowInteractionDelegateWidget
+::SliceWindowInteractionDelegateWidget(GenericSliceView *parent)
+  : QtInteractionDelegateWidget(parent)
+{
+  m_ParentModel = NULL;
+  m_ParentView = parent;
+  m_LastPressLayoutCell.fill(0);
+}
+
+void SliceWindowInteractionDelegateWidget::preprocessEvent(QEvent *ev)
+{
+  // Do the parent's processing
+  QtInteractionDelegateWidget::preprocessEvent(ev);
+
+  // Don't do nothing if slice not initialized
+  if(!m_ParentModel || !m_ParentModel->IsSliceInitialized())
+    return;
+
+  // Deal with mouse events
+  if(ev->type() == QEvent::MouseButtonPress ||
+     ev->type() == QEvent::MouseButtonRelease ||
+     ev->type() == QEvent::MouseMove ||
+     ev->type() == QEvent::MouseButtonDblClick)
+    {
+    // Compute the spatial location of the event
+    m_XSlice = to_double(m_ParentModel->MapWindowToSlice(
+                           to_float(Vector2d(m_XSpace.extract(2)))));
+
+    // If a mouse press, back up this info for drag tracking
+    if(ev->type() == QEvent::MouseButtonPress)
+      {
+      m_LastPressXSlice = m_XSlice;
+      }
+    }
+}
+
+#include <QDebug>
+#include <QWindow>
+
+Vector3d
+SliceWindowInteractionDelegateWidget
+::GetEventWorldCoordinates(QMouseEvent *ev, bool flipY)
+{
+  // Make the parent window the current context
+  QtAbstractOpenGLBox *parent = this->GetParentGLWidget();
+  parent->makeCurrent();
+
+  // Get the x,y coordinates of the event in actual pixels (retina)
+  int xpix = (int) ev->x() * parent->windowHandle()->devicePixelRatio();
+  int ypix = (int) ev->y() * parent->windowHandle()->devicePixelRatio();
+  int hpix = (int) parent->height() * parent->windowHandle()->devicePixelRatio();
+  int x = xpix;
+  int y = (flipY) ? hpix - 1 - ypix : ypix;
+
+  // Get the cell size and the number of cells
+  Vector2ui sz = m_ParentModel->GetSize();
+  DisplayLayoutModel *dlm = m_ParentModel->GetParentUI()->GetDisplayLayoutModel();
+  Vector2ui cells = dlm->GetSliceViewLayerTilingModel()->GetValue();
+  int nrows = cells[0], ncols = cells[1];
+  int icol, irow;
+
+  // Determine which layout cell generated the event, unless we are dragging
+  // in which case we want to use the last cell
+  if(!this->isDragging())
+    {
+    // Which cell did the event fall in?
+    icol = xpix / sz[0];
+    irow = ypix / sz[1];
+
+    // Ensure the column and row are valid, otherwise default to the first cell
+    if(icol < 0 || icol >= ncols || irow < 0 || irow > nrows)
+      {
+      icol = 0;
+      irow = 0;
+      }
+
+    // Store this for the next time
+    m_LastPressLayoutCell = Vector2ui(irow, icol);
+    }
+  else
+    {
+    irow = m_LastPressLayoutCell[0];
+    icol = m_LastPressLayoutCell[1];
+    }
+
+  // Convert the event coordinates into the model view coordinates
+  double modelMatrix[16], projMatrix[16];
+  GLint viewport[] = { icol * sz[0], (nrows - 1 - irow) * sz[1], sz[0], sz[1] };
+  glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
+  glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
+
+  // Unproject to get the coordinate of the event
+  Vector3d xProjection;
+  gluUnProject(x, y, 0,
+               modelMatrix,projMatrix,viewport,
+               &xProjection[0], &xProjection[1], &xProjection[2]);
+
+  return xProjection;
+}
diff --git a/GUI/Qt/View/SliceWindowInteractionDelegateWidget.h b/GUI/Qt/View/SliceWindowInteractionDelegateWidget.h
new file mode 100644
index 0000000..55887ae
--- /dev/null
+++ b/GUI/Qt/View/SliceWindowInteractionDelegateWidget.h
@@ -0,0 +1,39 @@
+#ifndef SLICEWINDOWINTERACTIONDELEGATEWIDGET_H
+#define SLICEWINDOWINTERACTIONDELEGATEWIDGET_H
+
+#include <QtInteractionDelegateWidget.h>
+
+class GenericSliceView;
+
+class SliceWindowInteractionDelegateWidget : public QtInteractionDelegateWidget
+{
+  Q_OBJECT
+
+public:
+  explicit SliceWindowInteractionDelegateWidget(GenericSliceView *parent = 0);
+
+  irisSetMacro(ParentModel, GenericSliceModel *)
+
+protected:
+
+  // We override this method from parent class in order to handle the fact
+  // that a slice view may have multiple cells and thus multiple viewports
+  virtual Vector3d GetEventWorldCoordinates(QMouseEvent *ev, bool flipY);
+
+  // Slice coordinates of the event
+  Vector3d m_LastPressXSlice, m_XSlice;
+
+  // The cell in which the last press was generated
+  Vector2ui m_LastPressLayoutCell;
+
+  // Parent model
+  GenericSliceModel *m_ParentModel;
+
+  // Parent widget
+  GenericSliceView *m_ParentView;
+
+  void preprocessEvent(QEvent *ev);
+
+};
+
+#endif // SLICEWINDOWINTERACTIONDELEGATEWIDGET_H
diff --git a/GUI/Qt/View/SnakeROIInteractionMode.cxx b/GUI/Qt/View/SnakeROIInteractionMode.cxx
new file mode 100644
index 0000000..b669477
--- /dev/null
+++ b/GUI/Qt/View/SnakeROIInteractionMode.cxx
@@ -0,0 +1,85 @@
+#include "SnakeROIInteractionMode.h"
+#include "GenericSliceView.h"
+#include "SnakeROIModel.h"
+#include "SnakeROIRenderer.h"
+
+SnakeROIInteractionMode::SnakeROIInteractionMode(GenericSliceView *parent)
+  : SliceWindowInteractionDelegateWidget(parent)
+{
+  // Create the renderer
+  m_Renderer = SnakeROIRenderer::New();
+  m_Renderer->SetParentRenderer(
+        static_cast<GenericSliceRenderer *>(parent->GetRenderer()));
+}
+
+SnakeROIInteractionMode::~SnakeROIInteractionMode()
+{
+
+}
+
+void SnakeROIInteractionMode::SetModel(SnakeROIModel *model)
+{
+  m_Model = model;
+  m_Renderer->SetModel(model);
+  SetParentModel(model->GetParent());
+}
+
+void SnakeROIInteractionMode::mousePressEvent(QMouseEvent *ev)
+{
+  if(ev->button() == Qt::LeftButton)
+    if(m_Model->ProcessPushEvent(m_XSlice[0], m_XSlice[1]))
+      ev->accept();
+}
+
+void SnakeROIInteractionMode::mouseMoveEvent(QMouseEvent *ev)
+{
+  ev->ignore();
+  if(m_LeftDown)
+    {
+    if(m_Model->ProcessDragEvent(
+         m_XSlice[0], m_XSlice[1],
+         m_LastPressXSlice[0], m_LastPressXSlice[1], false))
+      {
+      ev->accept();
+      }
+    }
+  else if(!isDragging())
+    {
+    if(m_Model->ProcessMoveEvent(m_XSlice[0], m_XSlice[1]))
+      {
+      ev->accept();
+      }
+    }
+}
+
+void SnakeROIInteractionMode::mouseReleaseEvent(QMouseEvent *ev)
+{
+  if(m_Model->ProcessDragEvent(
+       m_XSlice[0], m_XSlice[1],
+       m_LastPressXSlice[0], m_LastPressXSlice[1], true))
+    ev->accept();
+}
+
+#include <SliceViewPanel.h>
+
+void SnakeROIInteractionMode::enterEvent(QEvent *)
+{
+  m_Model->ProcessEnterEvent();
+
+  // TODO: this is hideous!
+  SliceViewPanel *panel = dynamic_cast<SliceViewPanel *>(m_ParentView->parent());
+  panel->SetMouseMotionTracking(true);
+}
+
+void SnakeROIInteractionMode::leaveEvent(QEvent *)
+{
+  if(!this->isDragging())
+    m_Model->ProcessLeaveEvent();
+
+  SliceViewPanel *panel = dynamic_cast<SliceViewPanel *>(m_ParentView->parent());
+  panel->SetMouseMotionTracking(false);
+}
+
+
+
+
diff --git a/GUI/Qt/View/SnakeROIInteractionMode.h b/GUI/Qt/View/SnakeROIInteractionMode.h
new file mode 100644
index 0000000..d1c8df6
--- /dev/null
+++ b/GUI/Qt/View/SnakeROIInteractionMode.h
@@ -0,0 +1,37 @@
+#ifndef SNAKEROIINTERACTIONMODE_H
+#define SNAKEROIINTERACTIONMODE_H
+
+#include <SliceWindowInteractionDelegateWidget.h>
+#include <SNAPCommon.h>
+
+class GenericSliceModel;
+class GenericSliceView;
+class SnakeROIRenderer;
+class SnakeROIModel;
+
+class SnakeROIInteractionMode : public SliceWindowInteractionDelegateWidget
+{
+  Q_OBJECT
+
+public:
+  explicit SnakeROIInteractionMode(GenericSliceView *parent = NULL);
+  ~SnakeROIInteractionMode();
+
+  irisGetMacro(Renderer, SnakeROIRenderer *)
+
+  void SetModel(SnakeROIModel *model);
+
+  void mousePressEvent(QMouseEvent *ev);
+  void mouseMoveEvent(QMouseEvent *);
+  void mouseReleaseEvent(QMouseEvent *);
+  void enterEvent(QEvent *);
+  void leaveEvent(QEvent *);
+
+protected:
+
+  SmartPtr<SnakeROIRenderer> m_Renderer;
+
+  SnakeROIModel *m_Model;
+};
+
+#endif // SNAKEROIINTERACTIONMODE_H
diff --git a/GUI/Qt/View/ThumbnailInteractionMode.cxx b/GUI/Qt/View/ThumbnailInteractionMode.cxx
new file mode 100644
index 0000000..21e493e
--- /dev/null
+++ b/GUI/Qt/View/ThumbnailInteractionMode.cxx
@@ -0,0 +1,90 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "OrthogonalSliceCursorNavigationModel.h"
+#include "ThumbnailInteractionMode.h"
+#include <QMouseEvent>
+
+ThumbnailInteractionMode::ThumbnailInteractionMode(GenericSliceView *parent) :
+    SliceWindowInteractionDelegateWidget(parent)
+{
+
+}
+
+void ThumbnailInteractionMode
+::SetModel(OrthogonalSliceCursorNavigationModel *model)
+{
+  m_Model = model;
+  m_PanFlag = false;
+  this->SetParentModel(model->GetParent());
+}
+
+
+void ThumbnailInteractionMode::mousePressEvent(QMouseEvent *ev)
+{
+  // Press position in screen pixels
+  Vector2i x(ev->pos().x(), this->height() - ev->pos().y());
+
+  // Only react to left mouse button presses
+  if(ev->button() == Qt::LeftButton && m_Model->CheckThumbnail(x))
+    {
+    m_PanFlag = true;
+    m_Model->BeginPan();
+    ev->accept();
+    }
+}
+
+void ThumbnailInteractionMode::mouseMoveEvent(QMouseEvent *ev)
+{
+  // Press position in screen pixels
+  Vector2i x(ev->pos().x(), this->height() - ev->pos().y());
+
+  ev->ignore();
+  if(m_PanFlag)
+    {
+    Vector2i dx(ev->pos().x() - m_LastPressPos.x(),
+                - (ev->pos().y() - m_LastPressPos.y()));
+    m_Model->ProcessThumbnailPanGesture(-dx);
+    ev->accept();
+    }
+  else if(!isDragging() && m_Model->CheckThumbnail(x))
+    {
+    // When the view is responding to hover events, we want to consume
+    // mouse hovering that occurs over the thumbnail. Otherwise the user
+    // would not see the effect of the hovering
+    ev->accept();
+    }
+}
+
+void ThumbnailInteractionMode::mouseReleaseEvent(QMouseEvent *ev)
+{
+  this->mouseMoveEvent(ev);
+  if(m_PanFlag)
+    m_Model->EndPan();
+  m_PanFlag = false;
+}
+
+
diff --git a/GUI/Qt/View/ThumbnailInteractionMode.h b/GUI/Qt/View/ThumbnailInteractionMode.h
new file mode 100644
index 0000000..ee298cf
--- /dev/null
+++ b/GUI/Qt/View/ThumbnailInteractionMode.h
@@ -0,0 +1,54 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef THUMBNAILINTERACTIONMODE_H
+#define THUMBNAILINTERACTIONMODE_H
+
+#include <SliceWindowInteractionDelegateWidget.h>
+
+class OrthogonalSliceCursorNavigationModel;
+
+class ThumbnailInteractionMode : public SliceWindowInteractionDelegateWidget
+{
+  Q_OBJECT
+
+public:
+  explicit ThumbnailInteractionMode(GenericSliceView *parent = 0);
+
+  void SetModel(OrthogonalSliceCursorNavigationModel *model);
+
+  void mousePressEvent(QMouseEvent *ev);
+  void mouseMoveEvent(QMouseEvent *);
+  void mouseReleaseEvent(QMouseEvent *);
+
+private:
+
+  OrthogonalSliceCursorNavigationModel *m_Model;
+
+  bool m_PanFlag;
+};
+
+#endif // THUMBNAILINTERACTIONMODE_H
diff --git a/GUI/Qt/Windows/.DS_Store b/GUI/Qt/Windows/.DS_Store
new file mode 100644
index 0000000..0e8b0cf
Binary files /dev/null and b/GUI/Qt/Windows/.DS_Store differ
diff --git a/GUI/Qt/Windows/AboutDialog.cxx b/GUI/Qt/Windows/AboutDialog.cxx
new file mode 100644
index 0000000..21deac0
--- /dev/null
+++ b/GUI/Qt/Windows/AboutDialog.cxx
@@ -0,0 +1,29 @@
+#include "AboutDialog.h"
+#include "ui_AboutDialog.h"
+#include "QFile"
+#include "SNAPCommon.h"
+
+AboutDialog::AboutDialog(QWidget *parent) :
+  QDialog(parent),
+  ui(new Ui::AboutDialog)
+{
+  ui->setupUi(this);
+
+  // Load the credits file
+  QFile fCredits(":root/credits.html");
+  if(fCredits.open(QFile::ReadOnly))
+    ui->outCredits->setHtml(QString(fCredits.readAll()));
+
+  // Load the contents into the browser
+  QFile fLicense(":/root/license.txt");
+  if(fLicense.open(QFile::ReadOnly))
+    ui->outLicense->setPlainText(QString(fLicense.readAll()));
+
+  // Load the build information
+  ui->outBuild->setPlainText(QString::fromUtf8(SNAPBuildInfo));
+}
+
+AboutDialog::~AboutDialog()
+{
+  delete ui;
+}
diff --git a/GUI/Qt/Windows/AboutDialog.h b/GUI/Qt/Windows/AboutDialog.h
new file mode 100644
index 0000000..3c35bd9
--- /dev/null
+++ b/GUI/Qt/Windows/AboutDialog.h
@@ -0,0 +1,23 @@
+#ifndef ABOUTDIALOG_H
+#define ABOUTDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class AboutDialog;
+}
+
+class AboutDialog : public QDialog
+{
+  Q_OBJECT
+  
+public:
+  explicit AboutDialog(QWidget *parent = 0);
+
+  ~AboutDialog();
+  
+private:
+  Ui::AboutDialog *ui;
+};
+
+#endif // ABOUTDIALOG_H
diff --git a/GUI/Qt/Windows/AboutDialog.ui b/GUI/Qt/Windows/AboutDialog.ui
new file mode 100644
index 0000000..cc49381
--- /dev/null
+++ b/GUI/Qt/Windows/AboutDialog.ui
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AboutDialog</class>
+ <widget class="QDialog" name="AboutDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>640</width>
+    <height>480</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>About ITK-SNAP</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout" rowstretch="0,1,0" columnstretch="0,1">
+   <item row="1" column="0" colspan="2">
+    <widget class="QTabWidget" name="tabWidget">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="tab">
+      <attribute name="title">
+       <string>Developers</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout">
+       <property name="leftMargin">
+        <number>8</number>
+       </property>
+       <property name="topMargin">
+        <number>4</number>
+       </property>
+       <property name="rightMargin">
+        <number>8</number>
+       </property>
+       <property name="bottomMargin">
+        <number>8</number>
+       </property>
+       <item>
+        <widget class="QTextBrowser" name="outCredits">
+         <property name="html">
+          <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; text-decoration: underline;">ITK-SNAP 3.x Team (2011 - Present)</span></p>
+<p style=" margin-top:6px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Paul A. Yushkevich (University of Pennsylvania) - PI and Lead Developer <br />Guido Gerig (University of Utah) - Co-PI <br />Octavian Soldea (University of Pennsylvania) - Developer <br />Yang Gao (University of Utah) - Developer <br />Supported by the U.S. National Institute of Biomedical Imaging and BioEngineering through grant  [...]
+<p style=" margin-top:14px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; text-decoration: underline;">ITK-SNAP 2.x Team (2004 - 2012)</span></p>
+<p style=" margin-top:6px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Paul A. Yushkevich (University of Pennsylvania) - Lead Developer <br />Hui Zhang (University of Pennsylvania) - Developer <br />Casey Goodlett (University of Utah) - Contributor <br />Timothy Burke - Contributor <br />Nicholas Tustison - Contributor <br />Supported by the U.S. National Institute of Biomedical Imaging and Bio [...]
+<p style=" margin-top:14px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; text-decoration: underline;">SNAP/ITK Integration (2003-2004)</span></p>
+<p style=" margin-top:6px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Paul A. Yushkevich (University of Pennsylvania) - Technical Director <br />Daniel S. Fritsch - Contract PI <br />Guido Gerig (University of Utah) - Scientific Director <br />Stephen R. Aylward (Kitware) - Consultant <br />Supported by the U.S. National Library of Medicine through PO 467-MZ-202446-1 </p>
+<p style=" margin-top:14px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; text-decoration: underline;">Original SNAP/IRIS Team (199x - 2003)</span></p>
+<p style=" margin-top:6px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Guido Gerig (University of Utah) - Scientific Director <br />Silvio Turello, Joachim Schlegel, Gabor Szekely (ETH Zurich) - Original AVS Module <br />Chris Wynn, Arun Neelamkavil, David Gregg, Eric Larsen, Sanjay Sthapit (UNC Chapel Hill) - IRIS 1999 Project <br />Sean Ho, Ashraf Farrag, Amy Henderson, Robin Munesato, Ming Yu (UNC Chape [...]
+<p style=" margin-top:14px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; text-decoration: underline;">Special Thanks</span></p>
+<p style=" margin-top:6px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Terry S. Yoo (NLM) <br />Zohara Cohen (NIBIB) <br />Luis Ibanez (Kitware) <br />Joshua Cates (University of Utah) <br />James C. Gee (University of Pennsylvania) <br />All who generously contribute to ITK, VTK, FLTK, and SNAP </p></body></html></string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tab_2">
+      <attribute name="title">
+       <string>License</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_2">
+       <property name="leftMargin">
+        <number>8</number>
+       </property>
+       <property name="topMargin">
+        <number>4</number>
+       </property>
+       <property name="rightMargin">
+        <number>8</number>
+       </property>
+       <property name="bottomMargin">
+        <number>8</number>
+       </property>
+       <item>
+        <widget class="QTextBrowser" name="outLicense"/>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tab_3">
+      <attribute name="title">
+       <string>Components</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_3">
+       <property name="leftMargin">
+        <number>8</number>
+       </property>
+       <property name="topMargin">
+        <number>4</number>
+       </property>
+       <property name="rightMargin">
+        <number>8</number>
+       </property>
+       <property name="bottomMargin">
+        <number>8</number>
+       </property>
+       <item>
+        <widget class="QTextBrowser" name="outComponents">
+         <property name="html">
+          <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; text-decoration: underline;">Toolbar Icons</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ITK-SNAP uses icons from the following free collections under the Creative Commons Attribution License:</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">OpenIcon: <a href="http://openiconlibrary.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://openiconlibrary.sourceforge.net/</span></a> </p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VisualPharm: <a href="http://icons8.com"><span style=" text-decoration: underline; color:#0000ff;">http://icons8.com</span></a></p></body></html></string>
+         </property>
+         <property name="openExternalLinks">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tab_4">
+      <attribute name="title">
+       <string>Build</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_4">
+       <property name="leftMargin">
+        <number>8</number>
+       </property>
+       <property name="topMargin">
+        <number>4</number>
+       </property>
+       <property name="rightMargin">
+        <number>8</number>
+       </property>
+       <property name="bottomMargin">
+        <number>8</number>
+       </property>
+       <item>
+        <widget class="QTextBrowser" name="outBuild">
+         <property name="styleSheet">
+          <string notr="true">font: 12px "Courier";</string>
+         </property>
+         <property name="html">
+          <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Courier'; font-size:12px; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">Build date: %BUILD_DATE%</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">Git commit: %GIT_COMMIT%</span></p></body></html></string>
+         </property>
+         <property name="openExternalLinks">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="SplashPanel" name="widget" native="true"/>
+   </item>
+   <item row="0" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string/>
+     </property>
+     <property name="pixmap">
+      <pixmap resource="../Resources/SNAPResources.qrc">:/root/logo_new.gif</pixmap>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="2">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+     <property name="centerButtons">
+      <bool>false</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>SplashPanel</class>
+   <extends>QWidget</extends>
+   <header>SplashPanel.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>AboutDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>AboutDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/GUI/Qt/Windows/DropActionDialog.cxx b/GUI/Qt/Windows/DropActionDialog.cxx
new file mode 100644
index 0000000..b4710c3
--- /dev/null
+++ b/GUI/Qt/Windows/DropActionDialog.cxx
@@ -0,0 +1,107 @@
+#include "DropActionDialog.h"
+#include "ui_DropActionDialog.h"
+#include "QtStyles.h"
+#include "GlobalUIModel.h"
+#include "ImageIODelegates.h"
+#include "SystemInterface.h"
+#include "QtWarningDialog.h"
+#include "QtCursorOverride.h"
+#include <QMessageBox>
+#include "SNAPQtCommon.h"
+#include "MainImageWindow.h"
+#include "SaveModifiedLayersDialog.h"
+#include "IRISImageData.h"
+
+DropActionDialog::DropActionDialog(QWidget *parent) :
+  QDialog(parent),
+  ui(new Ui::DropActionDialog)
+{
+  ui->setupUi(this);
+
+  // Start from scratch
+  ApplyCSS(this, ":/root/itksnap.css");
+
+}
+
+DropActionDialog::~DropActionDialog()
+{
+  delete ui;
+}
+
+void DropActionDialog::SetDroppedFilename(QString name)
+{
+  ui->outFilename->setText(name);
+}
+
+void DropActionDialog::SetModel(GlobalUIModel *model)
+{
+  m_Model = model;
+}
+
+void DropActionDialog::on_btnLoadMain_clicked()
+{
+  // Prompt for unsaved changes before replacing the main image
+  if(!SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model))
+    return;
+
+  SmartPtr<LoadMainImageDelegate> del = LoadMainImageDelegate::New();
+  del->Initialize(m_Model->GetDriver());
+  this->LoadCommon(del);
+}
+
+void DropActionDialog::on_btnLoadSegmentation_clicked()
+{
+  // Prompt for unsaved changes before replacing the segmentation
+  if(!SaveModifiedLayersDialog::PromptForUnsavedSegmentationChanges(m_Model))
+    return;
+
+  SmartPtr<LoadSegmentationImageDelegate> del = LoadSegmentationImageDelegate::New();
+  del->Initialize(m_Model->GetDriver());
+  this->LoadCommon(del);
+}
+
+void DropActionDialog::on_btnLoadOverlay_clicked()
+{
+  SmartPtr<LoadOverlayImageDelegate > del = LoadOverlayImageDelegate ::New();
+  del->Initialize(m_Model->GetDriver());
+  this->LoadCommon(del);
+}
+
+void DropActionDialog::on_btnLoadNew_clicked()
+{
+  std::list<std::string> args;
+  args.push_back(to_utf8(ui->outFilename->text()));
+  try
+    {
+    m_Model->GetSystemInterface()->LaunchChildSNAPSimple(args);
+    this->accept();
+    }
+  catch(exception &exc)
+    {
+    QMessageBox b(this);
+    b.setText(QString("Failed to launch new ITK-SNAP instance"));
+    b.setDetailedText(exc.what());
+    b.setIcon(QMessageBox::Critical);
+    b.exec();
+    }
+}
+
+void DropActionDialog::LoadCommon(AbstractLoadImageDelegate *delegate)
+{
+  std::string file = to_utf8(ui->outFilename->text());
+  QtCursorOverride c(Qt::WaitCursor);
+  try
+    {
+    IRISWarningList warnings;
+    m_Model->GetDriver()->LoadImageViaDelegate(file.c_str(), delegate, warnings);
+    this->accept();
+    }
+  catch(exception &exc)
+    {
+    QMessageBox b(this);
+    b.setText(QString("Failed to load image %1").arg(ui->outFilename->text()));
+    b.setDetailedText(exc.what());
+    b.setIcon(QMessageBox::Critical);
+    b.exec();
+  }
+}
diff --git a/GUI/Qt/Windows/DropActionDialog.h b/GUI/Qt/Windows/DropActionDialog.h
new file mode 100644
index 0000000..3bb0ffd
--- /dev/null
+++ b/GUI/Qt/Windows/DropActionDialog.h
@@ -0,0 +1,49 @@
+#ifndef DROPACTIONDIALOG_H
+#define DROPACTIONDIALOG_H
+
+#include <QDialog>
+
+class GlobalUIModel;
+class AbstractLoadImageDelegate;
+
+namespace Ui {
+class DropActionDialog;
+}
+
+
+
+/**
+ * This dialog is shown when the user drops an image onto the SNAP window.
+ * This dialog is so simple that we don't couple it with its own model, and
+ * allow it to hold its data (the dropped filename) in the widgets.
+ */
+class DropActionDialog : public QDialog
+{
+  Q_OBJECT
+  
+public:
+  explicit DropActionDialog(QWidget *parent = 0);
+  ~DropActionDialog();
+
+  void SetDroppedFilename(QString name);
+
+  void SetModel(GlobalUIModel *model);
+  
+private slots:
+  void on_btnLoadMain_clicked();
+
+  void on_btnLoadSegmentation_clicked();
+
+  void on_btnLoadOverlay_clicked();
+
+  void on_btnLoadNew_clicked();
+
+
+private:
+  Ui::DropActionDialog *ui;
+  GlobalUIModel *m_Model;
+
+  void LoadCommon(AbstractLoadImageDelegate *delegate);
+};
+
+#endif // DROPACTIONDIALOG_H
diff --git a/GUI/Qt/Windows/DropActionDialog.ui b/GUI/Qt/Windows/DropActionDialog.ui
new file mode 100644
index 0000000..80b97e5
--- /dev/null
+++ b/GUI/Qt/Windows/DropActionDialog.ui
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DropActionDialog</class>
+ <widget class="QDialog" name="DropActionDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>622</width>
+    <height>319</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Open Document - ITK-SNAP</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>8</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="outFilename">
+     <property name="maximumSize">
+      <size>
+       <width>598</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">font-weight: bold;</string>
+     </property>
+     <property name="text">
+      <string>TextLabel</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line">
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_2">
+     <property name="text">
+      <string>What should ITK-SNAP do with this image?</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Fixed</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>10</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Open it in the current window</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <item>
+       <widget class="QPushButton" name="btnLoadMain">
+        <property name="minimumSize">
+         <size>
+          <width>192</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>192</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Load as Main Image</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnLoadSegmentation">
+        <property name="minimumSize">
+         <size>
+          <width>192</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>192</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Load as Segmentation</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnLoadOverlay">
+        <property name="minimumSize">
+         <size>
+          <width>192</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>192</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Load as Overlay</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_3">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Fixed</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>10</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="title">
+      <string>Open it in a new ITK-SNAP window</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_3">
+      <item>
+       <widget class="QPushButton" name="btnLoadNew">
+        <property name="minimumSize">
+         <size>
+          <width>192</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>192</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Open in New ITK-SNAP</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <spacer name="horizontalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pushButton_5">
+        <property name="text">
+         <string>Cancel</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pushButton_5</sender>
+   <signal>clicked()</signal>
+   <receiver>DropActionDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>557</x>
+     <y>282</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>614</x>
+     <y>232</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/GUI/Qt/Windows/ImageIODialog.cxx b/GUI/Qt/Windows/ImageIODialog.cxx
new file mode 100644
index 0000000..17df54b
--- /dev/null
+++ b/GUI/Qt/Windows/ImageIODialog.cxx
@@ -0,0 +1,14 @@
+#include "ImageIODialog.h"
+#include "ui_ImageIODialog.h"
+
+ImageIODialog::ImageIODialog(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::ImageIODialog)
+{
+    ui->setupUi(this);
+}
+
+ImageIODialog::~ImageIODialog()
+{
+    delete ui;
+}
diff --git a/GUI/Qt/Windows/ImageIODialog.h b/GUI/Qt/Windows/ImageIODialog.h
new file mode 100644
index 0000000..c5be8e4
--- /dev/null
+++ b/GUI/Qt/Windows/ImageIODialog.h
@@ -0,0 +1,22 @@
+#ifndef IMAGEIODIALOG_H
+#define IMAGEIODIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+    class ImageIODialog;
+}
+
+class ImageIODialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit ImageIODialog(QWidget *parent = 0);
+    ~ImageIODialog();
+
+private:
+    Ui::ImageIODialog *ui;
+};
+
+#endif // IMAGEIODIALOG_H
diff --git a/GUI/Qt/Windows/ImageIODialog.ui b/GUI/Qt/Windows/ImageIODialog.ui
new file mode 100644
index 0000000..60924a8
--- /dev/null
+++ b/GUI/Qt/Windows/ImageIODialog.ui
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ImageIODialog</class>
+ <widget class="QDialog" name="ImageIODialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <widget class="QDialogButtonBox" name="buttonBox">
+   <property name="geometry">
+    <rect>
+     <x>30</x>
+     <y>240</y>
+     <width>341</width>
+     <height>32</height>
+    </rect>
+   </property>
+   <property name="orientation">
+    <enum>Qt::Horizontal</enum>
+   </property>
+   <property name="standardButtons">
+    <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+   </property>
+  </widget>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>ImageIODialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>ImageIODialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/GUI/Qt/Windows/ImageIOWizard.cxx b/GUI/Qt/Windows/ImageIOWizard.cxx
new file mode 100644
index 0000000..5a2f609
--- /dev/null
+++ b/GUI/Qt/Windows/ImageIOWizard.cxx
@@ -0,0 +1,758 @@
+#include "ImageIOWizard.h"
+
+#include <QLabel>
+#include <QLineEdit>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QPushButton>
+#include <QComboBox>
+#include <QFileDialog>
+#include <QCompleter>
+#include <QFileSystemModel>
+#include <QStandardItemModel>
+#include <QFileInfo>
+#include <QMenu>
+#include <QTreeWidget>
+#include <QMessageBox>
+#include <QTableWidget>
+#include <QApplication>
+#include <QHeaderView>
+#include <QGridLayout>
+#include <QSpinBox>
+
+#include <QtCursorOverride.h>
+
+#include "IRISException.h"
+#include "ImageIOWizardModel.h"
+#include "MetaDataAccess.h"
+#include "SNAPQtCommon.h"
+#include "FileChooserPanelWithHistory.h"
+
+namespace imageiowiz {
+
+const QString AbstractPage::m_HtmlTemplate =
+    "<tr><td width=40><img src=\":/root/%1.png\" /></td>"
+    "<td><p>%2</p></td></tr>";
+
+AbstractPage::AbstractPage(QWidget *parent)
+  : QWizardPage(parent)
+{
+  this->m_Model = NULL;
+
+  m_OutMessage = new QLabel(this);
+  m_OutMessage->setWordWrap(true);
+}
+
+bool
+AbstractPage::ErrorMessage(const IRISException &exc)
+{
+  QString text = QString::fromUtf8(exc.what());
+  QString head = text.section(".",0,0);
+  QString tail = text.section(".", 1);
+
+  QString html = QString("<table>%1</table>").arg(
+        QString(m_HtmlTemplate).arg(
+          "dlg_error_32", QString("<b>%1.</b> %2").arg(head, tail)));
+
+  m_OutMessage->setText(html);
+  return false;
+}
+
+void
+AbstractPage::WarningMessage(const IRISWarningList &wl)
+{
+  if(wl.size())
+    {
+    QString html;
+    for(size_t i = 0; i < wl.size(); i++)
+      {
+      QString text = QString::fromUtf8(wl[i].what());
+      QString head = text.section(".",0,0);
+      QString tail = text.section(".", 1);
+      html += QString(m_HtmlTemplate).arg(
+            "dlg_warning_32", QString("<b>%1.</b> %2").arg(head, tail));
+      }
+    html = QString("<table>%1</table>").arg(html);
+    m_OutMessage->setText(html);
+    }
+}
+
+bool
+AbstractPage::ErrorMessage(const char *subject, const char *detail)
+{
+  QString html = QString(
+        "<html><body><ul>"
+        "<li><b>%1</b>%2</li>"
+        "</ul></body></html>").arg(QString::fromUtf8(subject),
+                                   QString::fromUtf8(detail));
+
+  m_OutMessage->setText(html);
+
+  return false;
+}
+
+bool
+AbstractPage::ConditionalError(bool rc, const char *subject, const char *detail)
+{
+  if(!rc)
+    {
+    return ErrorMessage(subject, detail);
+    }
+  return true;
+}
+
+
+
+SelectFilePage::SelectFilePage(QWidget *parent)
+  : AbstractPage(parent)
+{
+  // setTitle("Select 3D Image to Load");
+
+  // Lay out the page
+  QVBoxLayout *lo = new QVBoxLayout(this);
+
+  // File input
+  m_FilePanel = new FileChooserPanelWithHistory(this);
+  lo->addWidget(m_FilePanel);
+  lo->addSpacing(15);
+
+  // The output message
+  lo->addStretch(1);
+  lo->addWidget(m_OutMessage);
+
+  // Register the fields
+  this->registerField("Filename*", m_FilePanel, "absoluteFilename", SIGNAL(absoluteFilenameChanged(QString)));
+  this->registerField("Format*", m_FilePanel, "activeFormat", SIGNAL(activeFormatChanged(QString)));
+
+  // Connect slots
+  QMetaObject::connectSlotsByName(this);
+
+  connect(m_FilePanel, SIGNAL(absoluteFilenameChanged(QString)), this, SLOT(onFilenameChanged(QString)));
+
+  QWizard *wiz = dynamic_cast<QWizard *>(parent);
+  connect(wiz, SIGNAL(accepted()), m_FilePanel, SLOT(onFilenameAccept()));
+}
+
+/*
+class QtRegistryTableModel : public QAbstractTableModel
+{
+  Q_OBJECT
+
+public:
+
+  typedef std::vector<Registry> RegistryArray;
+
+  explicit QtRegistryTableModel(QObject *parent, const RegistryArray &reg);
+
+  int rowCount(const QModelIndex &parent) const;
+  int columnCount(const QModelIndex &parent) const;
+  QVariant data(const QModelIndex &index, int role) const;
+
+protected:
+
+  RegistryArray &m_Array;
+};
+*/
+
+
+void SelectFilePage::initializePage()
+{
+  assert(m_Model);
+
+  // Reset the model
+  m_Model->Reset();
+
+  // Set title
+  if(m_Model->IsLoadMode())
+    setTitle(QString("Open %1").arg(m_Model->GetDisplayName().c_str()));
+  else
+    setTitle(QString("Save %1").arg(m_Model->GetDisplayName().c_str()));
+
+  // Create a filter for the filename panel
+  std::string filter = m_Model->GetFilter("%s (%s)", "*.%s", " ", ";;");
+
+  // Determine the active format to use
+  QString activeFormat;
+  if(m_Model->IsSaveMode())
+    activeFormat = from_utf8(m_Model->GetDefaultFormatForSave());
+  if(m_Model->GetSelectedFormat() < GuidedNativeImageIO::FORMAT_COUNT)
+    activeFormat = from_utf8(m_Model->GetFileFormatName(m_Model->GetSelectedFormat()));
+
+  // Initialize the file panel
+  if(m_Model->IsLoadMode())
+    {
+    m_FilePanel->initializeForOpenFile(
+          m_Model->GetParent(),
+          "Image Filename:",
+          from_utf8(m_Model->GetHistoryName()),
+          from_utf8(filter),
+          from_utf8(m_Model->GetSuggestedFilename()),
+          activeFormat);
+    }
+  else
+    {
+    m_FilePanel->initializeForSaveFile(
+          m_Model->GetParent(),
+          "Image Filename:",
+          from_utf8(m_Model->GetHistoryName()),
+          from_utf8(filter),
+          false,
+          from_utf8(m_Model->GetSuggestedFilename()),
+          activeFormat);
+    }
+
+  // Provide a callback for determining format from filename
+  m_FilePanel->setCustomFormatOracle(this, "customFormatOracle");
+}
+
+
+
+
+bool SelectFilePage::validatePage()
+{
+  // Clear error state
+  m_OutMessage->clear();
+
+  // Get the selected format
+  QString format = m_FilePanel->activeFormat();
+  ImageIOWizardModel::FileFormat fmt = m_Model->GetFileFormatByName(to_utf8(format));
+
+  // If can't handle the format, return false
+  if(!m_Model->CanHandleFileFormat(fmt))
+    {
+    return ErrorMessage("File format is not supported for this operation");
+    }
+
+  // If format is RAW, continue to next page
+  if(fmt == GuidedNativeImageIO::FORMAT_RAW)
+    return true;
+
+  // If format is DICOM, process the DICOM directory
+  if(fmt == GuidedNativeImageIO::FORMAT_DICOM_DIR)
+    {
+    // Change cursor until this object moves out of scope
+    QtCursorOverride curse(Qt::WaitCursor);
+    try
+      {
+      m_Model->ProcessDicomDirectory(to_utf8(m_FilePanel->absoluteFilename()));
+      return true;
+      }
+    catch(IRISException &exc)
+      {
+      return ErrorMessage(exc);
+      }
+    }
+
+  // Save or load the image
+  try
+    {
+    QtCursorOverride curse(Qt::WaitCursor);
+    m_Model->SetSelectedFormat(fmt);
+    if(m_Model->IsLoadMode())
+      {
+      m_Model->LoadImage(to_utf8(m_FilePanel->absoluteFilename()));
+      }
+    else
+      {
+      m_Model->SaveImage(to_utf8(m_FilePanel->absoluteFilename()));
+      }
+    }
+  catch(IRISException &exc)
+    {
+    return ErrorMessage(exc);
+    }
+
+  return true;
+}
+
+int SelectFilePage::nextId() const
+{
+  if(m_Model->IsSaveMode())
+    return -1;
+
+  // Get the selected format
+  QString format = m_FilePanel->activeFormat();
+  ImageIOWizardModel::FileFormat fmt = m_Model->GetFileFormatByName(to_utf8(format));
+
+  // Depending on the format, return the next page
+  if(fmt == GuidedNativeImageIO::FORMAT_RAW)
+    return ImageIOWizard::Page_Raw;
+  else if(fmt == GuidedNativeImageIO::FORMAT_DICOM_DIR)
+    return ImageIOWizard::Page_DICOM;
+  else
+    return ImageIOWizard::Page_Summary;
+}
+
+void SelectFilePage::onFilenameChanged(QString absoluteFilename)
+{
+  bool file_exists = false;
+
+  // The file format for the checkbox
+  /*
+  GuidedNativeImageIO::FileFormat fmt =
+      m_Model->GuessFileFormat(to_utf8(absoluteFilename), file_exists);
+
+  if(fmt != GuidedNativeImageIO::FORMAT_COUNT)
+    m_FilePanel->setActiveFormat(m_InFormat->currentText());
+    */
+
+  // Is it a directory?
+  if(QFileInfo(absoluteFilename).isDir())
+    return;
+/*
+  // Add some messages to help the user
+  if(fmt == GuidedNativeImageIO::FORMAT_COUNT)
+    {
+    if(!m_FilePanel->errorText().length())
+      m_FilePanel->setErrorText("The format can not be determined from the file name.");
+    }
+  else if(!m_Model->CanHandleFileFormat(fmt))
+    {
+    if(!m_FilePanel->errorText().length())
+      m_FilePanel->setErrorText("The format is not supported for this operation.");
+    }*/
+
+  emit completeChanged();
+}
+
+QString SelectFilePage::customFormatOracle(QString filename)
+{
+  // Guess the file format using history information
+  bool file_exists;
+  GuidedNativeImageIO::FileFormat fmt =
+      m_Model->GuessFileFormat(to_utf8(filename), file_exists);
+
+  // Return the stinr
+  if(fmt != GuidedNativeImageIO::FORMAT_COUNT)
+    return from_utf8(m_Model->GetFileFormatName(fmt));
+
+  // Return empty string - we failed
+  return QString();
+}
+
+
+SummaryPage::SummaryPage(QWidget *parent) :
+  AbstractPage(parent)
+{
+  // Set up the UI
+  m_Tree = new QTreeWidget();
+  m_Tree->setColumnCount(2);
+
+  QStringList header;
+  header << "Property" << "Value";
+  m_Tree->setHeaderLabels(header);
+
+  m_Tree->setAlternatingRowColors(true);
+
+  QVBoxLayout *lo = new QVBoxLayout(this);
+  lo->addWidget(m_Tree);
+
+  // Set up the warnings
+  lo->addWidget(m_OutMessage);
+}
+
+
+
+void SummaryPage::AddItem(
+    QTreeWidgetItem *parent,
+    const char *key,
+    ImageIOWizardModel::SummaryItem si)
+{
+  QTreeWidgetItem *item = new QTreeWidgetItem(parent);
+  item->setText(0, key);
+  item->setText(1, from_utf8(m_Model->GetSummaryItem(si)));
+}
+
+void SummaryPage::AddItem(
+    QTreeWidget *parent,
+    const char *key,
+    ImageIOWizardModel::SummaryItem si)
+{
+  QTreeWidgetItem *item = new QTreeWidgetItem(parent);
+  item->setText(0, key);
+  item->setText(1, from_utf8(m_Model->GetSummaryItem(si)));
+}
+
+
+
+
+void SummaryPage::initializePage()
+{
+  // Set the title
+  this->setTitle("Image Summary");
+
+  // Fill the tree widget
+  m_Tree->clear();
+
+  // Add all the top level items
+  AddItem(m_Tree, "File name", ImageIOWizardModel::SI_FILENAME);
+  AddItem(m_Tree, "Dimensions", ImageIOWizardModel::SI_DIMS);
+  AddItem(m_Tree, "Voxel spacing", ImageIOWizardModel::SI_SPACING);
+  AddItem(m_Tree, "Origin", ImageIOWizardModel::SI_ORIGIN);
+  AddItem(m_Tree, "Orientation", ImageIOWizardModel::SI_ORIENT);
+  AddItem(m_Tree, "Byte order", ImageIOWizardModel::SI_ENDIAN);
+  AddItem(m_Tree, "Components/Voxel", ImageIOWizardModel::SI_COMPONENTS);
+  AddItem(m_Tree, "Data type", ImageIOWizardModel::SI_DATATYPE);
+  AddItem(m_Tree, "File size", ImageIOWizardModel::SI_FILESIZE);
+
+  // Create metadata item
+  QTreeWidgetItem *meta = new QTreeWidgetItem(m_Tree);
+  meta->setText(0, "Metadata");
+
+  // Add all metadata items
+  MetaDataAccess mda(m_Model->GetGuidedIO()->GetNativeImage());
+  std::vector<std::string> keys = mda.GetKeysAsArray();
+  for(size_t i = 0; i < keys.size(); i++)
+    {
+    QTreeWidgetItem *item = new QTreeWidgetItem(meta);
+    item->setText(0, mda.MapKeyToDICOM(keys[i]).c_str());
+    item->setText(1, mda.GetValueAsString(keys[i]).c_str());
+    }
+
+  m_Tree->resizeColumnToContents(0);
+  m_Tree->resizeColumnToContents(1);
+
+  // Show the warning messages generated so far
+  WarningMessage(m_Model->GetWarnings());
+}
+
+bool SummaryPage::validatePage()
+{
+  m_Model->Finalize();
+  return true;
+}
+
+
+DICOMPage::DICOMPage(QWidget *parent)
+  : AbstractPage(parent)
+{
+  // Set up a table widget
+  m_Table = new QTableWidget();
+  QVBoxLayout *lo = new QVBoxLayout(this);
+  lo->addWidget(m_Table);
+  lo->addWidget(m_OutMessage);
+
+  m_Table->setSelectionBehavior(QAbstractItemView::SelectRows);
+  m_Table->setSelectionMode(QAbstractItemView::SingleSelection);
+  m_Table->setAlternatingRowColors(true);
+  m_Table->setEditTriggers(QAbstractItemView::NoEditTriggers);
+  m_Table->verticalHeader()->hide();
+
+  connect(m_Table->selectionModel(),
+          SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+          SIGNAL(completeChanged()));
+}
+
+void DICOMPage::initializePage()
+{
+  // Set the title, subtitle
+  setTitle("Select DICOM series to open");
+
+  // Populate the DICOM page
+  const std::vector<Registry> &reg = m_Model->GetDicomContents();
+
+  m_Table->setRowCount(reg.size());
+  m_Table->setColumnCount(4);
+  m_Table->setHorizontalHeaderItem(0, new QTableWidgetItem("Series Number"));
+  m_Table->setHorizontalHeaderItem(1, new QTableWidgetItem("Description"));
+  m_Table->setHorizontalHeaderItem(2, new QTableWidgetItem("Dimensions"));
+  m_Table->setHorizontalHeaderItem(3, new QTableWidgetItem("Number of Images"));
+
+  for(size_t i = 0; i < reg.size(); i++)
+    {
+    Registry r = reg[i];
+    m_Table->setItem(i, 0, new QTableWidgetItem(r["SeriesNumber"][""]));
+    m_Table->setItem(i, 1, new QTableWidgetItem(r["SeriesDescription"][""]));
+    m_Table->setItem(i, 2, new QTableWidgetItem(r["Dimensions"][""]));
+    m_Table->setItem(i, 3, new QTableWidgetItem(r["NumberOfImages"][""]));
+    }
+
+  m_Table->resizeColumnsToContents();
+  m_Table->resizeRowsToContents();
+
+  // If only one sequence selected, pick it
+  if(reg.size() == 1)
+    {
+    m_Table->selectRow(0);
+    }
+
+  // Choose the sequence previously loaded
+  // TODO:
+
+  /*
+  // See if one of the sequences in the registry matches
+  StringType last = m_Registry["DICOM.SequenceId"]["NULL"];
+  const Fl_Menu_Item *lastpos = m_InDICOMPageSequenceId->find_item(last.c_str());
+  if(lastpos)
+    m_InDICOMPageSequenceId->value(lastpos);
+  else
+    m_InDICOMPageSequenceId->value(0);
+  */
+}
+
+bool DICOMPage::validatePage()
+{
+  // Clear error state
+  m_OutMessage->clear();
+
+  // Add registry entries for the selected DICOM series
+  int row = m_Table->selectionModel()->selectedRows().front().row();
+
+  try
+    {
+    QtCursorOverride curse(Qt::WaitCursor);
+    m_Model->LoadDicomSeries(to_utf8(this->field("Filename").toString()), row);
+    }
+  catch(IRISException &exc)
+    {
+    return ErrorMessage(exc);
+    }
+
+  return true;
+}
+
+int DICOMPage::nextId() const
+{
+  return ImageIOWizard::Page_Summary;
+}
+
+bool DICOMPage::isComplete() const
+{
+  return m_Table->selectionModel()->selectedRows().size() == 1;
+}
+
+
+RawPage::RawPage(QWidget *parent)
+  : AbstractPage(parent)
+{
+  // Create a new layout
+  QGridLayout *lo = new QGridLayout(this);
+
+  // Create the header input
+  m_HeaderSize = new QSpinBox();
+  lo->addWidget(new QLabel("Header size:"), 0, 0, 1, 2);
+  lo->addWidget(m_HeaderSize, 0, 2, 1, 1);
+  lo->addWidget(new QLabel("bytes"), 0, 3, 1, 4);
+
+  m_HeaderSize->setToolTip(
+        "Specify the number of bytes at the beginning of the image that "
+        "should be skipped before reading the image data.");
+
+  connect(m_HeaderSize, SIGNAL(valueChanged(int)), SLOT(onHeaderSizeChange()));
+
+  // Create the dimensions input
+  for(size_t i = 0; i < 3; i++)
+    {
+    m_Dims[i] = new QSpinBox();
+    connect(m_Dims[i], SIGNAL(valueChanged(int)), SLOT(onHeaderSizeChange()));
+    }
+
+  lo->addWidget(new QLabel("Image dimensions:"), 1, 0, 1, 1);
+  lo->addWidget(new QLabel("x:"), 1, 1, 1, 1);
+  lo->addWidget(m_Dims[0], 1, 2, 1, 1);
+  lo->addWidget(new QLabel("y:"), 1, 3, 1, 1);
+  lo->addWidget(m_Dims[1], 1, 4, 1, 1);
+  lo->addWidget(new QLabel("z:"), 1, 5, 1, 1);
+  lo->addWidget(m_Dims[2], 1, 6, 1, 1);
+
+  // Voxel representation
+  /*
+  PIXELTYPE_UCHAR=0, PIXELTYPE_CHAR, PIXELTYPE_USHORT, PIXELTYPE_SHORT,
+  PIXELTYPE_UINT, PIXELTYPE_INT, PIXELTYPE_FLOAT, PIXELTYPE_DOUBLE,
+  PIXELTYPE_COUNT};
+  */
+
+  m_InFormat = new QComboBox();
+  m_InFormat->addItem("8 bit unsigned integer (uchar)");
+  m_InFormat->addItem("8 bit signed integer (char)");
+  m_InFormat->addItem("16 bit unsigned integer (ushort)");
+  m_InFormat->addItem("16 bit signed integer (short)");
+  m_InFormat->addItem("32 bit unsigned integer (uint)");
+  m_InFormat->addItem("32 bit signed integer (int)");
+  m_InFormat->addItem("32 bit floating point (float)");
+  m_InFormat->addItem("64 bit floating point (double)");
+
+  connect(m_InFormat, SIGNAL(currentIndexChanged(int)), SLOT(onHeaderSizeChange()));
+
+  lo->addWidget(new QLabel("Voxel type:"), 2, 0, 1, 2);
+  lo->addWidget(m_InFormat, 2, 2, 1, 5);
+
+  // Endianness
+  m_InEndian = new QComboBox();
+  m_InEndian->addItem("Big Endian (PowerPC, SPARC)");
+  m_InEndian->addItem("Little Endian (x86, x86_64)");
+
+  lo->addWidget(new QLabel("Byte alignment:"), 3, 0, 1, 2);
+  lo->addWidget(m_InEndian, 3, 2, 1, 5);
+
+  // Add some space
+  lo->setRowMinimumHeight(4,16);
+
+  // File sizes
+  m_OutImpliedSize = new QSpinBox();
+  m_OutImpliedSize->setReadOnly(true);
+  m_OutImpliedSize->setButtonSymbols(QAbstractSpinBox::NoButtons);
+  m_OutImpliedSize->setRange(0, 0x7fffffff);
+  lo->addWidget(new QLabel("Implied file size:"), 5, 0, 1, 2);
+  lo->addWidget(m_OutImpliedSize, 5, 2, 1, 1);
+
+  m_OutActualSize = new QSpinBox();
+  m_OutActualSize->setReadOnly(true);
+  m_OutActualSize->setButtonSymbols(QAbstractSpinBox::NoButtons);
+  m_OutActualSize->setRange(0, 0x7fffffff);
+  lo->addWidget(new QLabel("Actual file size:"), 6, 0, 1, 2);
+  lo->addWidget(m_OutActualSize, 6, 2, 1, 1);
+
+  QLabel *lbrace = new QLabel("}");
+  lbrace->setStyleSheet("font-size: 30px");
+  lo->addWidget(lbrace, 5, 3, 2, 1);
+  lo->addWidget(new QLabel("should be equal"), 5, 4, 2, 2);
+
+  lo->addWidget(m_OutMessage, 7, 0, 1, 7);
+
+  // The output label
+  lo->setColumnMinimumWidth(0, 140);
+
+  // Initialize this field
+  m_FileSize = 0;
+}
+
+void RawPage::onHeaderSizeChange()
+{
+  // Check the size of the file
+  const int nbytes[] = { 1, 1, 2, 2, 4, 4, 4 };
+  unsigned long myfs =
+      m_HeaderSize->value() +
+      m_Dims[0]->value() * m_Dims[1]->value() * m_Dims[2]->value() *
+      nbytes[m_InFormat->currentIndex()];
+
+  m_OutImpliedSize->setValue(myfs);
+
+  emit completeChanged();
+}
+
+bool RawPage::isComplete() const
+{
+  // Check if required fields are filled
+  if(!AbstractPage::isComplete())
+    return false;
+
+  // Check if the sizes match
+  return(m_OutImpliedSize->value() == m_OutActualSize->value());
+}
+
+void RawPage::initializePage()
+{
+  setTitle("Image Header Specification:");
+
+  // Get the hints (from previous experience with this file)
+  Registry hint = m_Model->GetHints();
+
+  // Get the size of the image in bytes
+  m_FileSize = m_Model->GetFileSizeInBytes(to_utf8(field("Filename").toString()));
+  m_OutActualSize->setValue(m_FileSize);
+
+  // Assign to the widgets
+  m_HeaderSize->setValue(hint["Raw.HeaderSize"][0]);
+  m_HeaderSize->setRange(0, m_FileSize);
+
+  // Set the dimensions
+  Vector3i dims = hint["Raw.Dimensions"][Vector3i(0)];
+  for(size_t i = 0; i < 3; i++)
+    {
+    m_Dims[i]->setValue(dims[i]);
+    m_Dims[i]->setRange(1, m_FileSize);
+    }
+
+  // Set the data type (default to uchar)
+  int ipt = (int) (GuidedNativeImageIO::GetPixelType(
+        hint, GuidedNativeImageIO::PIXELTYPE_UCHAR) -
+                   GuidedNativeImageIO::PIXELTYPE_UCHAR);
+  m_InFormat->setCurrentIndex(ipt);
+
+  // Set the endian (default to LE)
+  int ien = hint["Raw.BigEndian"][false] ? 0 : 1;
+  m_InEndian->setCurrentIndex(ien);
+}
+
+int RawPage::nextId() const
+{
+  return ImageIOWizard::Page_Summary;
+}
+
+bool RawPage::validatePage()
+{
+  // Clear error state
+  m_OutMessage->clear();
+
+  // Get the hints (from previous experience with this file)
+  Registry &hint = m_Model->GetHints();
+
+  // Set up the registry with the specified values
+  hint["Raw.HeaderSize"] << (unsigned int) m_HeaderSize->value();
+
+  // Set the dimensions
+  hint["Raw.Dimensions"] << Vector3i(
+    m_Dims[0]->value(), m_Dims[1]->value(), m_Dims[2]->value());
+
+  // Set the endianness
+  hint["Raw.BigEndian"] << ( m_InEndian->currentIndex() == 0 );
+
+  // Set the pixel type
+  int iPixType = m_InFormat->currentIndex();
+  GuidedNativeImageIO::RawPixelType pixtype = (iPixType < 0)
+    ? GuidedNativeImageIO::PIXELTYPE_COUNT
+    : (GuidedNativeImageIO::RawPixelType) iPixType;
+  GuidedNativeImageIO::SetPixelType(hint, pixtype);
+
+  // Try loading the image
+  QtCursorOverride curse(Qt::WaitCursor);
+  try
+    {
+    m_Model->SetSelectedFormat(GuidedNativeImageIO::FORMAT_RAW);
+    m_Model->LoadImage(to_utf8(field("Filename").toString()));
+    }
+  catch(IRISException &exc)
+    {
+    return ErrorMessage(exc);
+    }
+  return true;
+}
+
+
+} // namespace
+
+using namespace imageiowiz;
+
+ImageIOWizard::ImageIOWizard(QWidget *parent) :
+    QWizard(parent)
+{
+  // Give ourselves a name
+  this->setObjectName("wizImageIO");
+
+  // Add pages to the wizard
+  setPage(Page_File, new SelectFilePage(this));
+  setPage(Page_Summary, new SummaryPage(this));
+  setPage(Page_DICOM, new DICOMPage(this));
+  setPage(Page_Raw, new RawPage(this));
+
+}
+
+void ImageIOWizard::SetModel(ImageIOWizardModel *model)
+{
+  // Store the model
+  this->m_Model = model;
+
+  // Assign the model to all pages
+  QList<int> ids = pageIds();
+  for(QList<int>::iterator it=ids.begin();it!=ids.end();it++)
+    static_cast<AbstractPage *>(this->page(*it))->SetModel(model);
+
+  // Set the title
+  if(model->IsLoadMode())
+    this->setWindowTitle("Open Image - ITK-SNAP");
+  else
+    this->setWindowTitle("Save Image - ITK-SNAP");
+}
+
+
diff --git a/GUI/Qt/Windows/ImageIOWizard.h b/GUI/Qt/Windows/ImageIOWizard.h
new file mode 100644
index 0000000..c0c63f1
--- /dev/null
+++ b/GUI/Qt/Windows/ImageIOWizard.h
@@ -0,0 +1,178 @@
+#ifndef IMAGEIOWIZARD_H
+#define IMAGEIOWIZARD_H
+
+#include <QDebug>
+
+#include <QWizard>
+#include "SNAPCommon.h"
+#include "ImageIOWizardModel.h"
+
+class QLineEdit;
+class QPushButton;
+class QComboBox;
+class QLabel;
+class QFileDialog;
+class QStandardItemModel;
+class QMenu;
+class QTreeWidget;
+class QTreeWidgetItem;
+class QTableWidget;
+class QSpinBox;
+class FileChooserPanelWithHistory;
+
+// Helper classes in their own namespace, so I can use simple class names
+namespace imageiowiz
+{
+
+/*
+ * TODO/NOTE:
+ *
+ * This was one of the first elements ported to Qt. For that reason, it does
+ * not follow the same design patterns as the newer Qt code. Namely, it does
+ * not make use of .ui files (all the Qt elements are coded in C++ directly)
+ * and it does not use model couplings in the way that newer code does.
+ *
+ * Eventually, this code should be brought in line with the newer code.
+ */
+
+class AbstractPage : public QWizardPage
+{
+  Q_OBJECT
+
+public:
+  explicit AbstractPage(QWidget *parent = 0);
+
+  irisSetMacro(Model, ImageIOWizardModel *)
+  irisGetMacro(Model, ImageIOWizardModel *)
+
+protected:
+
+  bool ErrorMessage(const char *subject, const char *detail = NULL);
+  bool ConditionalError(bool rc, const char *subject, const char *detail);
+  bool ErrorMessage(const IRISException &exc);
+  void WarningMessage(const IRISWarningList &wl);
+  ImageIOWizardModel *m_Model;
+
+  // A qlabel for displaying error/warning messages. The children are
+  // responsible for placing this control on their layouts
+  QLabel *m_OutMessage;
+
+  static const QString m_HtmlTemplate;
+};
+
+class SelectFilePage : public AbstractPage
+{
+  Q_OBJECT
+
+public:
+  explicit SelectFilePage(QWidget *parent = 0);
+
+  int nextId() const;
+  void initializePage();
+  bool validatePage();
+  // bool isComplete() const;
+
+public slots:
+
+  void onFilenameChanged(QString absoluteFilename);
+
+  QString customFormatOracle(QString filename);
+
+private:
+  FileChooserPanelWithHistory *m_FilePanel;
+};
+
+class SummaryPage : public AbstractPage
+{
+  Q_OBJECT
+
+public:
+  explicit SummaryPage(QWidget *parent = 0);
+
+  int nextId() const { return -1; }
+  void initializePage();
+
+  bool validatePage();
+
+
+private:
+  // Helper for building the tree
+  void AddItem(QTreeWidgetItem *parent, const char *key, ImageIOWizardModel::SummaryItem si);
+  void AddItem(QTreeWidget *parent, const char *key, ImageIOWizardModel::SummaryItem si);
+
+  QTreeWidget *m_Tree;
+  QLabel *m_Warnings;
+};
+
+
+class DICOMPage : public AbstractPage
+{
+  Q_OBJECT
+
+public:
+
+  explicit DICOMPage(QWidget *parent = 0);
+  int nextId() const;
+  void initializePage();
+  bool validatePage();
+
+  bool isComplete() const;
+private:
+
+  QTableWidget *m_Table;
+};
+
+class RawPage : public AbstractPage
+{
+  Q_OBJECT
+
+public:
+
+  explicit RawPage(QWidget *parent = 0);
+  int nextId() const;
+  void initializePage();
+  bool validatePage();
+  virtual bool isComplete() const;
+
+public slots:
+  void onHeaderSizeChange();
+
+private:
+  QSpinBox *m_Dims[3], *m_HeaderSize;
+  QComboBox *m_InFormat, *m_InEndian;
+  QSpinBox *m_OutImpliedSize, *m_OutActualSize;
+  unsigned long m_FileSize;
+};
+
+} // end namespace
+
+
+
+
+class ImageIOWizard : public QWizard
+{
+  Q_OBJECT
+
+
+
+
+public:
+
+  enum { Page_File, Page_Raw, Page_DICOM, Page_Summary };
+
+  explicit ImageIOWizard(QWidget *parent = 0);
+
+  void SetModel(ImageIOWizardModel *model);
+
+signals:
+
+public slots:
+
+protected:
+
+
+  // The model
+  ImageIOWizardModel *m_Model;
+};
+
+#endif // IMAGEIOWIZARD_H
diff --git a/GUI/Qt/Windows/ImageIOWizardSummaryPage.ui b/GUI/Qt/Windows/ImageIOWizardSummaryPage.ui
new file mode 100644
index 0000000..1b83f3e
--- /dev/null
+++ b/GUI/Qt/Windows/ImageIOWizardSummaryPage.ui
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Form</class>
+ <widget class="QWidget" name="Form">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>439</width>
+    <height>366</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/LabelEditorDialog.cxx b/GUI/Qt/Windows/LabelEditorDialog.cxx
new file mode 100644
index 0000000..fa9d0a9
--- /dev/null
+++ b/GUI/Qt/Windows/LabelEditorDialog.cxx
@@ -0,0 +1,198 @@
+#include "LabelEditorDialog.h"
+#include "ui_LabelEditorDialog.h"
+#include <LabelEditorModel.h>
+
+#include <QAbstractTableModel>
+
+#include <QtComboBoxCoupling.h>
+#include <QtLineEditCoupling.h>
+#include <QtListWidgetCoupling.h>
+#include <QtSliderCoupling.h>
+#include <QtSpinBoxCoupling.h>
+#include <QtDoubleSpinBoxCoupling.h>
+#include <QtWidgetArrayCoupling.h>
+#include <QtCheckBoxCoupling.h>
+#include <QtAbstractButtonCoupling.h>
+#include <QtColorWheelCoupling.h>
+#include <SNAPQtCommon.h>
+#include <QtWidgetActivator.h>
+#include <ColorWheel.h>
+#include <QMenu>
+
+#include <QSortFilterProxyModel>
+#include <QStandardItemModel>
+#include <QtAbstractItemViewCoupling.h>
+
+LabelEditorDialog::LabelEditorDialog(QWidget *parent) :
+  QDialog(parent),
+  ui(new Ui::LabelEditorDialog)
+{
+  ui->setupUi(this);
+
+  ui->inColorWheel->setWheelWidth(15);
+
+  // Add some actions to the action button
+  QMenu *menu = new QMenu();
+  ui->btnActions->setMenu(menu);
+  menu->addAction(FindUpstreamAction(this, "actionLoadLabels"));
+  menu->addAction(FindUpstreamAction(this, "actionSaveLabels"));
+  menu->addSeparator();
+  menu->addAction(ui->actionResetLabels);
+
+  // Set up a filter model for the label list view
+  m_LabelListFilterModel = new QSortFilterProxyModel(this);
+  m_LabelListFilterModel->setSourceModel(new QStandardItemModel(this));
+  m_LabelListFilterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+  m_LabelListFilterModel->setFilterKeyColumn(-1);
+  ui->lvLabels->setModel(m_LabelListFilterModel);
+}
+
+LabelEditorDialog::~LabelEditorDialog()
+{
+  delete ui;
+}
+
+#include <QSortFilterProxyModel>
+
+void LabelEditorDialog::SetModel(LabelEditorModel *model)
+{
+  // Store the model
+  m_Model = model;
+
+  // Couple widgets to the model
+  makeCoupling((QAbstractItemView *) (ui->lvLabels), m_Model->GetCurrentLabelModel());
+
+  // Coupling for the description of the current label. Override the default
+  // signal for this widget.
+  makeCoupling(ui->inLabelDescription,
+               m_Model->GetCurrentLabelDescriptionModel());
+
+  // Coupling for the ID of the current label
+  makeCoupling(ui->inLabelId,
+               m_Model->GetCurrentLabelIdModel());
+
+  // Opacity (there are two controls)
+  makeCoupling(ui->inLabelOpacitySlider,
+               m_Model->GetCurrentLabelOpacityModel());
+
+  makeCoupling(ui->inLabelOpacitySpinner,
+               m_Model->GetCurrentLabelOpacityModel());
+
+  // Visibility checkboxes
+  makeArrayCoupling(ui->inVisibleAll, ui->inVisible3D,
+                    m_Model->GetCurrentLabelHiddenStateModel());
+
+  // Color button
+  makeCoupling(ui->btnLabelColor, m_Model->GetCurrentLabelColorModel());
+
+  // Color wheel
+  makeCoupling(ui->inColorWheel, m_Model->GetCurrentLabelColorModel());
+
+  // RGB sliders
+  makeArrayCoupling(ui->inRed, ui->inGreen, ui->inBlue,
+                    m_Model->GetCurrentLabelColorModel());
+
+  // Set as foreground/background buttons
+  makeArrayCoupling((QAbstractButton *)ui->btnForeground,
+                    (QAbstractButton *) ui->btnBackground,
+                    m_Model->GetIsForegroundBackgroundModel());
+
+  // Set up activations
+  activateOnFlag(ui->grpSelectedLabel, m_Model,
+                 LabelEditorModel::UIF_EDITABLE_LABEL_SELECTED);
+  activateOnFlag(ui->btnDuplicate, m_Model,
+                 LabelEditorModel::UIF_EDITABLE_LABEL_SELECTED);
+  activateOnFlag(ui->btnDelete, m_Model,
+                 LabelEditorModel::UIF_EDITABLE_LABEL_SELECTED);
+}
+
+void LabelEditorDialog::on_btnClose_clicked()
+{
+  this->close();
+}
+
+#include <QMessageBox>
+
+void LabelEditorDialog::on_btnNew_clicked()
+{
+  // Create a new label in the first slot after the currently selected
+  if(!m_Model->MakeNewLabel(false))
+    {
+    QMessageBox::information(
+          this,
+          "ITK-SNAP: Label Insertion Failed",
+          "There is no room to add a new label. Delete some existing labels.");
+    }
+}
+
+void LabelEditorDialog::on_btnDuplicate_clicked()
+{
+  // Create a new label in the first slot after the currently selected
+  if(!m_Model->MakeNewLabel(true))
+    {
+    QMessageBox::information(
+          this,
+          "ITK-SNAP: Label Insertion Failed",
+          "There is no room to add a new label. Delete some existing labels.");
+    }
+}
+
+void LabelEditorDialog::on_btnDelete_clicked()
+{
+  // Check if the deletion is going to affect the segmentation
+  if(m_Model->IsLabelDeletionDestructive())
+    {
+    QMessageBox mb(this);
+    QString text = QString(
+          "Label %1 is used in the current segmentation. If you delete this "
+          "label, the voxels that currently are assigned label %1 will be "
+          "assigned the clear label (label 0). Are you sure you want to "
+          "delete label %1?").arg(m_Model->GetCurrentLabelModel()->GetValue());
+    mb.setText(text);
+    mb.addButton("Delete Label", QMessageBox::ActionRole);
+    QPushButton *bCancel = mb.addButton(QMessageBox::Cancel);
+    mb.exec();
+
+    if(mb.clickedButton() == bCancel)
+      return;
+    }
+
+  // Delete the label
+  m_Model->DeleteCurrentLabel();
+}
+
+void LabelEditorDialog::on_inLabelId_editingFinished()
+{
+  // Check if the new value is available
+  LabelType newid = (LabelType) ui->inLabelId->value();
+  LabelType curid = m_Model->GetCurrentLabelIdModel()->GetValue();
+
+  // If the value is the same as the current, just ignore
+  if(newid == curid)
+    return;
+
+  // Try to reassign the label
+  if(!m_Model->ReassignLabelId(ui->inLabelId->value()))
+    {
+    // Complain
+    QMessageBox::information(
+          this,
+          "ITK-SNAP: Label Id Change Failed",
+          QString("Can not change the numerical value to %1 "
+                  "because a label with that value already exists. "
+                  "Delete label %1 first.").arg(ui->inLabelId->value()));
+
+    // Set the value to the current value
+    ui->inLabelId->setValue(curid);
+    }
+}
+
+void LabelEditorDialog::on_actionResetLabels_triggered()
+{
+  m_Model->ResetLabels();
+}
+
+void LabelEditorDialog::on_inLabelFilter_textChanged(const QString &arg1)
+{
+  m_LabelListFilterModel->setFilterFixedString(arg1);
+}
diff --git a/GUI/Qt/Windows/LabelEditorDialog.h b/GUI/Qt/Windows/LabelEditorDialog.h
new file mode 100644
index 0000000..4685422
--- /dev/null
+++ b/GUI/Qt/Windows/LabelEditorDialog.h
@@ -0,0 +1,48 @@
+#ifndef LABELEDITORDIALOG_H
+#define LABELEDITORDIALOG_H
+
+#include <QDialog>
+
+class LabelEditorModel;
+class QStandardItemModel;
+class QSortFilterProxyModel;
+
+namespace Ui {
+    class LabelEditorDialog;
+}
+
+class LabelEditorDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+  explicit LabelEditorDialog(QWidget *parent = 0);
+  ~LabelEditorDialog();
+
+  void SetModel(LabelEditorModel *model);
+
+private slots:
+  void on_btnClose_clicked();
+
+  void on_btnNew_clicked();
+
+  void on_btnDuplicate_clicked();
+
+  void on_btnDelete_clicked();
+
+  void on_inLabelId_editingFinished();
+
+  void on_actionResetLabels_triggered();
+
+  void on_inLabelFilter_textChanged(const QString &arg1);
+
+private:
+  Ui::LabelEditorDialog *ui;
+
+  LabelEditorModel *m_Model;
+
+  // The Qt model tied to the QListView
+  QSortFilterProxyModel *m_LabelListFilterModel;
+};
+
+#endif // LABELEDITORDIALOG_H
diff --git a/GUI/Qt/Windows/LabelEditorDialog.ui b/GUI/Qt/Windows/LabelEditorDialog.ui
new file mode 100644
index 0000000..14712dd
--- /dev/null
+++ b/GUI/Qt/Windows/LabelEditorDialog.ui
@@ -0,0 +1,780 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LabelEditorDialog</class>
+ <widget class="QDialog" name="LabelEditorDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>548</width>
+    <height>537</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Segmentation Label Editor - ITK-SNAP</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QGroupBox {
+  background-origin: content;
+  margin-top: 15px;
+  font-weight: bold;
+  font-size: 12px;
+  color: rgb(30,30,160);
+  background-color: rgb(237,237,237);
+  padding: 5px;
+  border-radius: 4px;
+  border: 1px solid rgb(130,130,130);
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+}</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <property name="leftMargin">
+    <number>6</number>
+   </property>
+   <property name="topMargin">
+    <number>24</number>
+   </property>
+   <property name="rightMargin">
+    <number>6</number>
+   </property>
+   <property name="bottomMargin">
+    <number>6</number>
+   </property>
+   <property name="horizontalSpacing">
+    <number>8</number>
+   </property>
+   <property name="verticalSpacing">
+    <number>16</number>
+   </property>
+   <item row="1" column="0" colspan="3">
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="spacing">
+       <number>8</number>
+      </property>
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QPushButton" name="btnNew">
+        <property name="text">
+         <string>New</string>
+        </property>
+        <property name="autoDefault">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnDuplicate">
+        <property name="text">
+         <string>Duplicate</string>
+        </property>
+        <property name="autoDefault">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnDelete">
+        <property name="text">
+         <string>Delete</string>
+        </property>
+        <property name="autoDefault">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnActions">
+        <property name="text">
+         <string>Actions...</string>
+        </property>
+        <property name="autoDefault">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnClose">
+        <property name="text">
+         <string>Close</string>
+        </property>
+        <property name="autoDefault">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="0" column="2">
+    <widget class="QGroupBox" name="grpSelectedLabel">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="title">
+      <string>Selected Label</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>4</number>
+      </property>
+      <property name="leftMargin">
+       <number>6</number>
+      </property>
+      <property name="topMargin">
+       <number>6</number>
+      </property>
+      <property name="rightMargin">
+       <number>6</number>
+      </property>
+      <property name="bottomMargin">
+       <number>6</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>Description:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="inLabelDescription"/>
+      </item>
+      <item>
+       <spacer name="verticalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>10</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_2" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QLabel" name="label_2">
+           <property name="text">
+            <string>Color:</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_2">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_6" native="true">
+        <property name="minimumSize">
+         <size>
+          <width>0</width>
+          <height>100</height>
+         </size>
+        </property>
+        <layout class="QGridLayout" name="gridLayout_3" columnstretch="0,1,0,0,0">
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <property name="spacing">
+          <number>4</number>
+         </property>
+         <item row="3" column="2" colspan="2">
+          <widget class="QColorButtonWidget" name="btnLabelColor" native="true">
+           <property name="minimumSize">
+            <size>
+             <width>60</width>
+             <height>20</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="3" colspan="2">
+          <widget class="QSpinBox" name="inRed">
+           <property name="maximumSize">
+            <size>
+             <width>56</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="maximum">
+            <number>255</number>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="2">
+          <widget class="QLabel" name="label_8">
+           <property name="text">
+            <string>B:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="2">
+          <widget class="QLabel" name="label_6">
+           <property name="text">
+            <string>R:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="3">
+          <widget class="QSpinBox" name="inBlue">
+           <property name="maximumSize">
+            <size>
+             <width>56</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="maximum">
+            <number>255</number>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="0" rowspan="5">
+          <widget class="ColorWheel" name="inColorWheel" native="true">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>120</width>
+             <height>120</height>
+            </size>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>120</width>
+             <height>120</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="2">
+          <widget class="QLabel" name="label_7">
+           <property name="text">
+            <string>G:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="3" colspan="2">
+          <widget class="QSpinBox" name="inGreen">
+           <property name="maximumSize">
+            <size>
+             <width>56</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="maximum">
+            <number>255</number>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <spacer name="horizontalSpacer_4">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeType">
+            <enum>QSizePolicy::Fixed</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>5</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <spacer name="verticalSpacer_3">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>10</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Opacity:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_3" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout_3">
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QSpinBox" name="inLabelOpacitySpinner">
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="maximum">
+            <number>255</number>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QSlider" name="inLabelOpacitySlider">
+           <property name="maximum">
+            <number>255</number>
+           </property>
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <spacer name="verticalSpacer_4">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>10</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QGroupBox" name="groupBox">
+        <property name="styleSheet">
+         <string notr="true">QGroupBox {
+  background-origin: content;
+  margin-top: 15px;
+  font-weight: normal;
+  color: black;
+  background-color: rgb(237,237,237);
+  padding: 5px;
+  border-radius: 0px;
+  border-top: 1px solid rgb(130,130,130);
+  border-left: none;
+  border-right:none;
+  border-bottom:none;
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+}</string>
+        </property>
+        <property name="title">
+         <string>Visibility:</string>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_3">
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QCheckBox" name="inVisible3D">
+           <property name="toolTip">
+            <string>When selected, the label is not rendered in the 3D view</string>
+           </property>
+           <property name="text">
+            <string>Hide label in 3D window</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="inVisibleAll">
+           <property name="toolTip">
+            <string>When selected, the label is not visible in any views.</string>
+           </property>
+           <property name="text">
+            <string>Hide label in all windows</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <spacer name="verticalSpacer_6">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>10</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QGroupBox" name="groupBox_2">
+        <property name="styleSheet">
+         <string notr="true">QGroupBox {
+  background-origin: content;
+  margin-top: 15px;
+  font-weight: normal;
+  color: black;
+  background-color: rgb(237,237,237);
+  padding: 5px;
+  border-radius: 0px;
+  border-top: 1px solid rgb(130,130,130);
+  border-left: none;
+  border-right:none;
+  border-bottom:none;
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+}</string>
+        </property>
+        <property name="title">
+         <string>Advanced Options:</string>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_6">
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QWidget" name="widget_4" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout_4">
+            <property name="leftMargin">
+             <number>0</number>
+            </property>
+            <property name="topMargin">
+             <number>0</number>
+            </property>
+            <property name="rightMargin">
+             <number>0</number>
+            </property>
+            <property name="bottomMargin">
+             <number>0</number>
+            </property>
+            <item>
+             <spacer name="horizontalSpacer_3">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QLabel" name="label_4">
+              <property name="text">
+               <string>Numeric value:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QSpinBox" name="inLabelId">
+              <property name="minimumSize">
+               <size>
+                <width>64</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string>The value that this label has in the segmentation image. If you change this value, voxels that have this value in the segmentation image will be changed to the new value.</string>
+              </property>
+              <property name="readOnly">
+               <bool>false</bool>
+              </property>
+              <property name="buttonSymbols">
+               <enum>QAbstractSpinBox::NoButtons</enum>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <spacer name="verticalSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>5</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QGroupBox" name="groupBox_3">
+     <property name="title">
+      <string>Available Labels:</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout">
+      <property name="leftMargin">
+       <number>6</number>
+      </property>
+      <property name="topMargin">
+       <number>6</number>
+      </property>
+      <property name="rightMargin">
+       <number>6</number>
+      </property>
+      <property name="bottomMargin">
+       <number>6</number>
+      </property>
+      <item>
+       <widget class="QTableView" name="lvLabels">
+        <property name="editTriggers">
+         <set>QAbstractItemView::NoEditTriggers</set>
+        </property>
+        <property name="dragDropMode">
+         <enum>QAbstractItemView::NoDragDrop</enum>
+        </property>
+        <property name="selectionMode">
+         <enum>QAbstractItemView::SingleSelection</enum>
+        </property>
+        <property name="selectionBehavior">
+         <enum>QAbstractItemView::SelectRows</enum>
+        </property>
+        <attribute name="horizontalHeaderVisible">
+         <bool>false</bool>
+        </attribute>
+        <attribute name="horizontalHeaderDefaultSectionSize">
+         <number>50</number>
+        </attribute>
+        <attribute name="horizontalHeaderStretchLastSection">
+         <bool>true</bool>
+        </attribute>
+        <attribute name="verticalHeaderVisible">
+         <bool>false</bool>
+        </attribute>
+        <attribute name="verticalHeaderDefaultSectionSize">
+         <number>22</number>
+        </attribute>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_5" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout_5">
+         <property name="spacing">
+          <number>4</number>
+         </property>
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QLabel" name="label_5">
+           <property name="text">
+            <string>Filter:</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLineEdit" name="inLabelFilter"/>
+         </item>
+         <item>
+          <widget class="QToolButton" name="btnForeground">
+           <property name="toolTip">
+            <string>Press to set the selected label as the foreground label</string>
+           </property>
+           <property name="text">
+            <string>F</string>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QToolButton" name="btnBackground">
+           <property name="toolTip">
+            <string>Press to set the selected label as the background label</string>
+           </property>
+           <property name="text">
+            <string>B</string>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+  <action name="actionResetLabels">
+   <property name="text">
+    <string>Reset Label Descriptions</string>
+   </property>
+   <property name="toolTip">
+    <string>Restores label descriptions to the default values.</string>
+   </property>
+  </action>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QColorButtonWidget</class>
+   <extends>QWidget</extends>
+   <header>QColorButtonWidget.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>ColorWheel</class>
+   <extends>QWidget</extends>
+   <header>ColorWheel.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>lvLabels</tabstop>
+  <tabstop>inLabelFilter</tabstop>
+  <tabstop>btnForeground</tabstop>
+  <tabstop>btnBackground</tabstop>
+  <tabstop>inLabelDescription</tabstop>
+  <tabstop>inRed</tabstop>
+  <tabstop>inGreen</tabstop>
+  <tabstop>inBlue</tabstop>
+  <tabstop>inLabelOpacitySpinner</tabstop>
+  <tabstop>inLabelOpacitySlider</tabstop>
+  <tabstop>inVisible3D</tabstop>
+  <tabstop>inVisibleAll</tabstop>
+  <tabstop>inLabelId</tabstop>
+  <tabstop>btnNew</tabstop>
+  <tabstop>btnDuplicate</tabstop>
+  <tabstop>btnDelete</tabstop>
+  <tabstop>btnActions</tabstop>
+  <tabstop>btnClose</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/LabelSelectionPopup.cxx b/GUI/Qt/Windows/LabelSelectionPopup.cxx
new file mode 100644
index 0000000..6e78af9
--- /dev/null
+++ b/GUI/Qt/Windows/LabelSelectionPopup.cxx
@@ -0,0 +1,114 @@
+#include "LabelSelectionPopup.h"
+#include "ui_LabelSelectionPopup.h"
+
+#include "GlobalUIModel.h"
+#include <QToolBar>
+#include <QStatusBar>
+#include <SNAPQtCommon.h>
+#include "IRISApplication.h"
+#include "ColorLabelTable.h"
+#include "GlobalState.h"
+#include "QtComboBoxCoupling.h"
+#include <QMenu>
+#include <QValidator>
+
+LabelSelectionPopup::LabelSelectionPopup(QWidget *parent) :
+  SNAPComponent(parent),
+  ui(new Ui::LabelSelectionPopup)
+{
+  ui->setupUi(this);
+
+  m_ToolBarFore = new QToolBar(this);
+  m_ToolBarFore->setIconSize(QSize(16,16));
+  ui->tbForeground->layout()->addWidget(m_ToolBarFore);
+
+  m_ToolBarBack = new QToolBar(this);
+  m_ToolBarBack->setIconSize(QSize(16,16));
+  ui->tbBackground->layout()->addWidget(m_ToolBarBack);
+
+  this->setWindowFlags(Qt::Popup);
+
+  connect(m_ToolBarFore, SIGNAL(actionTriggered(QAction*)),
+          SLOT(onForegroundToolbarAction(QAction*)));
+  connect(m_ToolBarBack, SIGNAL(actionTriggered(QAction*)),
+          SLOT(onBackgroundToolbarAction(QAction*)));
+  connect(ui->inBackground, SIGNAL(currentIndexChanged(int)), SLOT(close()));
+  connect(ui->inForeground, SIGNAL(currentIndexChanged(int)), SLOT(close()));
+}
+
+LabelSelectionPopup::~LabelSelectionPopup()
+{
+  delete ui;
+}
+
+void LabelSelectionPopup::SetModel(GlobalUIModel *model)
+{
+  m_Model = model;
+
+  makeCoupling(ui->inForeground, m_Model->GetGlobalState()->GetDrawingColorLabelModel());
+  makeCoupling(ui->inBackground, m_Model->GetGlobalState()->GetDrawOverFilterModel());
+
+  connectITK(m_Model->GetGlobalState()->GetDrawingColorLabelModel(), ValueChangedEvent());
+  connectITK(m_Model->GetGlobalState()->GetDrawOverFilterModel(), ValueChangedEvent());
+  connectITK(m_Model->GetGlobalState()->GetDrawingColorLabelModel(), DomainChangedEvent());
+  connectITK(m_Model->GetGlobalState()->GetDrawOverFilterModel(), DomainChangedEvent());
+
+  this->UpdateContents();
+}
+
+void LabelSelectionPopup::onModelUpdate(const EventBucket &bucket)
+{
+  this->UpdateContents();
+}
+
+void LabelSelectionPopup::onForegroundToolbarAction(QAction *action)
+{
+  int cl = action->data().toInt();
+  m_Model->GetGlobalState()->SetDrawingColorLabel((LabelType) cl);
+  this->close();
+}
+
+void LabelSelectionPopup::onBackgroundToolbarAction(QAction *action)
+{
+  DrawOverFilter dof = qvariant_cast<DrawOverFilter>(action->data());
+  m_Model->GetGlobalState()->SetDrawOverFilter(dof);
+  this->close();
+}
+
+// Update the contents of the toolbars and stuff
+void LabelSelectionPopup::UpdateContents()
+{
+  ColorLabelTable *clt = m_Model->GetDriver()->GetColorLabelTable();
+
+  // Fill out the foreground toolbar
+  m_ToolBarFore->clear();
+
+  // TODO: add the six labels that were last used
+  int i = 0;
+  std::vector<DrawOverFilter> doflist;
+  doflist.push_back(DrawOverFilter(PAINT_OVER_ALL, 0));
+  doflist.push_back(DrawOverFilter(PAINT_OVER_VISIBLE, 0));
+  doflist.push_back(DrawOverFilter(PAINT_OVER_ONE, 0));
+
+  while(m_ToolBarFore->actions().size() < 6 && i < MAX_COLOR_LABELS)
+    {
+    const ColorLabel &cl = clt->GetColorLabel(i);
+    QAction *action = m_ToolBarFore->addAction(
+          CreateColorBoxIcon(16, 16, GetBrushForColorLabel(i, clt)),
+          GetTitleForColorLabel(i, clt));
+    action->setData(QVariant(i));
+    i = clt->FindNextValidLabel((LabelType) i, false);
+
+    if(doflist.size() < 6)
+      doflist.push_back(DrawOverFilter(PAINT_OVER_ONE, i));
+    }
+
+  m_ToolBarBack->clear();
+  for(int j = 0; j < doflist.size(); j++)
+    {
+    QAction *action = m_ToolBarBack->addAction(
+          CreateColorBoxIcon(16, 16, GetBrushForDrawOverFilter(doflist[j], clt)),
+          GetTitleForDrawOverFilter(doflist[j], clt));
+    action->setData(QVariant::fromValue(doflist[j]));
+    }
+}
diff --git a/GUI/Qt/Windows/LabelSelectionPopup.h b/GUI/Qt/Windows/LabelSelectionPopup.h
new file mode 100644
index 0000000..4d7ebc2
--- /dev/null
+++ b/GUI/Qt/Windows/LabelSelectionPopup.h
@@ -0,0 +1,41 @@
+#ifndef LABELSELECTIONPOPUP_H
+#define LABELSELECTIONPOPUP_H
+
+#include "SNAPComponent.h"
+
+namespace Ui {
+class LabelSelectionPopup;
+}
+
+class GlobalUIModel;
+class QToolBar;
+class EventBucket;
+
+class LabelSelectionPopup : public SNAPComponent
+{
+  Q_OBJECT
+  
+public:
+  explicit LabelSelectionPopup(QWidget *parent = 0);
+  ~LabelSelectionPopup();
+
+  void SetModel(GlobalUIModel *model);
+
+public slots:
+
+  virtual void onModelUpdate(const EventBucket &bucket);
+
+  virtual void onForegroundToolbarAction(QAction *action);
+  virtual void onBackgroundToolbarAction(QAction *action);
+
+private:
+  Ui::LabelSelectionPopup *ui;
+
+  GlobalUIModel *m_Model;
+
+  QToolBar *m_ToolBarFore, *m_ToolBarBack;
+
+  void UpdateContents();
+};
+
+#endif // LABELSELECTIONPOPUP_H
diff --git a/GUI/Qt/Windows/LabelSelectionPopup.ui b/GUI/Qt/Windows/LabelSelectionPopup.ui
new file mode 100644
index 0000000..1026547
--- /dev/null
+++ b/GUI/Qt/Windows/LabelSelectionPopup.ui
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LabelSelectionPopup</class>
+ <widget class="QWidget" name="LabelSelectionPopup">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>236</width>
+    <height>133</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QGroupBox {
+  background-origin: content;
+  margin-top: 15px;
+  font-weight: bold;
+  font-size: 12px;
+  color: rgba(210,210,210,210);
+  background-color: rgba(80,80,80,210);
+  padding: 5px;
+  border-radius: 4px;
+  border: 1px solid rgba(30,30,30,210);
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+}
+QComboBox {
+  background-color: rgba(120,120,120,210);
+}
+LabelSelectionPopup {
+  background-color: rgba(80,80,80,210);
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QFrame" name="frame">
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>4</number>
+      </property>
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item>
+       <widget class="QGroupBox" name="groupBox">
+        <property name="title">
+         <string>Foreground Label:</string>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_3">
+         <property name="spacing">
+          <number>2</number>
+         </property>
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QWidget" name="tbForeground" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout">
+            <property name="spacing">
+             <number>0</number>
+            </property>
+            <property name="margin">
+             <number>0</number>
+            </property>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QComboBox" name="inForeground"/>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QGroupBox" name="groupBox_2">
+        <property name="title">
+         <string>Background Label:</string>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_4">
+         <property name="spacing">
+          <number>2</number>
+         </property>
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QWidget" name="tbBackground" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <property name="spacing">
+             <number>0</number>
+            </property>
+            <property name="margin">
+             <number>0</number>
+            </property>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QComboBox" name="inBackground"/>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <spacer name="verticalSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Expanding</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>10</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/LayerInspectorDialog.cxx b/GUI/Qt/Windows/LayerInspectorDialog.cxx
new file mode 100644
index 0000000..b135b54
--- /dev/null
+++ b/GUI/Qt/Windows/LayerInspectorDialog.cxx
@@ -0,0 +1,433 @@
+#include "LayerInspectorDialog.h"
+#include "ui_LayerInspectorDialog.h"
+#include "ContrastInspector.h"
+#include "GlobalUIModel.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "IRISImageData.h"
+#include "ImageWrapper.h"
+#include "LayerSelectionModel.h"
+#include "GenericImageData.h"
+#include "IntensityCurveModel.h"
+#include "ColorMapModel.h"
+#include "ImageInfoModel.h"
+#include "LatentITKEventNotifier.h"
+#include "QtSliderCoupling.h"
+#include "QtCheckBoxCoupling.h"
+#include "QtSpinBoxCoupling.h"
+#include "LayerGeneralPropertiesModel.h"
+#include "SNAPQtCommon.h"
+#include "LayerInspectorRowDelegate.h"
+#include "QGroupBox"
+#include "QComboBox"
+#include "QToolBar"
+#include <QToolButton>
+#include "CollapsableGroupBox.h"
+#include "LayerTableRowModel.h"
+#include "GlobalUIModel.h"
+#include "QtActionCoupling.h"
+#include "QtActionGroupCoupling.h"
+#include "DisplayLayoutModel.h"
+
+#include <QMenu>
+
+LayerInspectorDialog::LayerInspectorDialog(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::LayerInspectorDialog)
+{
+  ui->setupUi(this);
+
+  // Give the dialog a name for scripting
+  this->setObjectName("dlgLayerInspector");
+
+  // Create a toolbar under the layer list
+  QToolBar *tb = new QToolBar(this);
+  ui->loToolbar->addWidget(tb);
+  tb->setIconSize(QSize(16,16));
+
+  m_SaveSelectedButton = new QToolButton(this);
+
+  tb->addAction(ui->actionOpenLayer);
+  tb->addWidget(m_SaveSelectedButton);
+  tb->addAction(ui->actionEditVisibility);
+  tb->addAction(ui->actionLayoutToggle);
+
+  // Set up the action button
+  QMenu *menu = new QMenu(this);
+  menu->addAction(ui->actionSaveSelectedLayerAs);
+
+
+
+  // Set up the list of custom layer widgets
+  QVBoxLayout *loLayers = new QVBoxLayout();
+  loLayers->setContentsMargins(1, 0, 1, 0);
+  loLayers->setSpacing(0);
+  ui->saLayersContents->setLayout(loLayers);
+  // loLayers->setSizeConstraint(QLayout::SetMinAndMaxSize);
+  // loLayers->setContentsMargins(0,0,0,0);
+  // loLayers->setSpacing(0);
+
+  // Filter events to the widget containing the list of layers. This is
+  // used to hide and show controls (keep UI less busy) and to handle some
+  // basic keyboard interaction.
+  ui->saLayersContents->installEventFilter(this);
+}
+
+LayerInspectorDialog::~LayerInspectorDialog()
+{
+  delete ui;
+}
+
+void LayerInspectorDialog::SetModel(GlobalUIModel *model)
+{
+  this->m_Model = model;
+
+  // Hook up the model to the component inspectors
+  ui->cmpContrast->SetModel(model->GetIntensityCurveModel());
+  ui->cmpColorMap->SetModel(model->GetColorMapModel());
+  ui->cmpInfo->SetModel(model->GetImageInfoModel());
+  ui->cmpMetadata->SetModel(model->GetImageInfoModel());
+  ui->cmpComponent->SetModel(model->GetLayerGeneralPropertiesModel());
+
+  // We need to listen to layer changes in the model
+  LatentITKEventNotifier::connect(
+        model, LayerChangeEvent(),
+        this, SLOT(onModelUpdate(const EventBucket &)));
+
+  // We also need to handle changes to metadata
+  LatentITKEventNotifier::connect(
+        model->GetDriver(), WrapperMetadataChangeEvent(),
+        this, SLOT(onModelUpdate(const EventBucket &)));
+
+  // For the tile/stacked button, we currently don't have a coupling mechanism
+  // that supports it, so instead, we respond to the event directly
+  LatentITKEventNotifier::connect(
+        model->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel(),
+        ValueChangedEvent(),
+        this, SLOT(onModelUpdate(const EventBucket &)));
+
+
+  // The button turning on and off the visibility/reorder/pinning controls
+  // on the layer rows is tied to a model in GenericUIModel
+  makeCoupling(
+        ui->actionEditVisibility,
+        model->GetLayerVisibilityEditableModel());
+
+  // Set up the activation on the open layer button
+  activateOnFlag(ui->actionOpenLayer, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+}
+
+void LayerInspectorDialog::SetPageToContrastAdjustment()
+{
+  ui->tabWidget->setCurrentWidget(ui->cmpContrast);
+}
+
+void LayerInspectorDialog::SetPageToColorMap()
+{
+  ui->tabWidget->setCurrentWidget(ui->cmpColorMap);
+}
+
+void LayerInspectorDialog::SetPageToImageInfo()
+{
+  ui->tabWidget->setCurrentWidget(ui->cmpInfo);
+}
+
+QMenu *LayerInspectorDialog::GetLayerContextMenu(ImageWrapperBase *layer)
+{
+  foreach(LayerInspectorRowDelegate *del, m_Delegates)
+    if(del->GetLayer() == layer)
+      return del->contextMenu();
+
+  return NULL;
+}
+
+QAction *LayerInspectorDialog::GetLayerSaveAction(ImageWrapperBase *layer)
+{
+  foreach(LayerInspectorRowDelegate *del, m_Delegates)
+    if(del->GetLayer() == layer)
+      return del->saveAction();
+
+  return NULL;
+}
+
+bool LayerInspectorDialog::eventFilter(QObject *source, QEvent *event)
+{
+  if(source == ui->saLayersContents)
+    {
+    if(event->type() == QEvent::Enter)
+      emit layerListHover(true);
+    else if(event->type() == QEvent::Leave)
+      emit layerListHover(false);
+    }
+
+  return false;
+}
+
+
+
+
+
+void LayerInspectorDialog::GenerateModelsForLayers()
+{
+  // Iterate over the layers for each class of displayed layers
+  LayerIterator it = m_Model->GetDriver()->GetCurrentImageData()->GetLayers(
+        MAIN_ROLE |
+        OVERLAY_ROLE |
+        SNAP_ROLE);
+
+  for(; !it.IsAtEnd(); ++it)
+    {
+    // Check if a model exists for this layer
+    SmartPtr<LayerTableRowModel> model =
+        dynamic_cast<LayerTableRowModel *>(
+          it.GetLayer()->GetUserData("LayerTableRowModel"));
+
+    // If not, create it and stick as 'user data' into the layer
+    if(!model)
+      {
+      model = LayerTableRowModel::New();
+      model->Initialize(m_Model, it.GetLayer());
+      it.GetLayer()->SetUserData("LayerTableRowModel", model);
+      }
+    }
+}
+
+void LayerInspectorDialog::BuildLayerWidgetHierarchy()
+{
+  // Static names for different roles
+  static QMap<int, QString> mapRoleNames;
+  if(mapRoleNames.size() == 0)
+    {
+    mapRoleNames[MAIN_ROLE] = "Main Image";
+    mapRoleNames[OVERLAY_ROLE] = "Overlays";
+    mapRoleNames[SNAP_ROLE] = "Snake Mode Layers";
+    }
+
+  // Get the top-level layout in the pane
+  QBoxLayout *lo = (QBoxLayout *) ui->saLayersContents->layout();
+
+  // Before deleting all of the existing widgets in the pane,
+  // find the one that is currently selected, and remember its
+  // layer, so we can re-select it if needed
+  bool have_selected_layer = false, found_selected_layer = false;
+  unsigned long selected_layer = 0;
+  for(QList<LayerInspectorRowDelegate *>::iterator itdel = m_Delegates.begin();
+      itdel != m_Delegates.end(); ++itdel)
+    {
+    if((*itdel)->selected() && (*itdel)->GetLayer())
+      {
+      selected_layer = (*itdel)->GetLayer()->GetUniqueId();
+      have_selected_layer = true;
+      break;
+      }
+    }
+
+  // Get rid of all existing widgets in the pane
+  m_Delegates.clear();
+  QLayoutItem * item;
+  while ( (item = lo->takeAt( 0 ) ) != NULL )
+    {
+    if(item->widget())
+      {
+      delete item->widget();
+      }
+    delete item;
+    }
+
+  // Iterate over the layers for each class of displayed layers
+  LayerIterator it = m_Model->GetDriver()->GetCurrentImageData()->GetLayers(
+        MAIN_ROLE | OVERLAY_ROLE | SNAP_ROLE);
+
+  // The current role and associated group box
+  LayerRole currentRole = NO_ROLE;
+  CollapsableGroupBox *currentGroupBox = NULL;
+
+  // The row widget for the main image layer (default selection)
+  LayerInspectorRowDelegate *w_main = NULL;
+
+  // Loop over all the layers
+  for(; !it.IsAtEnd(); ++it)
+    {
+    LayerRole role = it.GetRole();
+    if(role != currentRole)
+      {
+      // Create the new groupbox
+      currentGroupBox = new CollapsableGroupBox();
+      currentRole = role;
+      lo->addWidget(currentGroupBox);
+      currentGroupBox->setTitle(mapRoleNames[currentRole]);
+      }
+
+    // Create the custom widget for this layer
+    LayerInspectorRowDelegate *w = new LayerInspectorRowDelegate(this);
+
+    // Is this the main layer? Then remember the widget
+    if(role == MAIN_ROLE)
+      w_main = w;
+
+    // Find the model for this layer
+    SmartPtr<LayerTableRowModel> model =
+        dynamic_cast<LayerTableRowModel *>(
+          it.GetLayer()->GetUserData("LayerTableRowModel"));
+
+    // Set the model
+    w->SetModel(model);
+
+    // Set a name for this widget for debugging purposes
+    w->setObjectName(QString().sprintf("wgtRowDelegate_%04d", m_Delegates.size()));
+
+    // Listen to select signals from widget
+    connect(w, SIGNAL(selectionChanged(bool)), this, SLOT(layerSelected(bool)));
+
+    // Select the layer if it was previously selected or nothing was previously
+    // selected and the layer is the main layer
+    if((have_selected_layer && it.GetLayer()->GetUniqueId() == selected_layer))
+      {
+      w->setSelected(true);
+      found_selected_layer = true;
+      }
+
+    else
+      {
+      w->setSelected(false);
+      }
+
+    currentGroupBox->addWidget(w);
+    m_Delegates.push_back(w);
+    }
+
+  // If we haven't selected anything, select the main layer's widget
+  if(!found_selected_layer && w_main)
+    w_main->setSelected(true);
+
+  lo->addStretch(1);
+}
+
+void LayerInspectorDialog::onModelUpdate(const EventBucket &bucket)
+{
+  if(bucket.HasEvent(LayerChangeEvent()))
+    {
+    // Make sure each layer is associated with a model
+    // TODO: it would be more attractive to map models to layers somewhere in
+    // the 'model layer' rather than in the Qt code. Think about it...
+    this->GenerateModelsForLayers();
+
+    // Build the left pane
+    this->BuildLayerWidgetHierarchy();
+
+    // TODO: this is the wrong place for this!!!
+    m_Model->GetImageInfoModel()->Update();
+    m_Model->GetColorMapModel()->Update();
+    m_Model->GetIntensityCurveModel()->Update();
+    m_Model->GetLayerGeneralPropertiesModel()->Update();
+    }
+
+  if(bucket.HasEvent(ValueChangedEvent(),
+                     m_Model->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()))
+    {
+    this->UpdateLayerLayoutAction();
+    }
+}
+
+void LayerInspectorDialog::layerSelected(bool flag)
+{
+  // Remove all actions from the save button
+  foreach(QAction *action, m_SaveSelectedButton->actions())
+    m_SaveSelectedButton->removeAction(action);
+
+  // Turn off all the other widgets
+  if(flag)
+    {
+    // Toggle everything else off
+    foreach(LayerInspectorRowDelegate *w, m_Delegates)
+      {
+      if(w != this->sender())
+        w->setSelected(false);
+      }
+
+    // Switch the current layer in all the right-pane models
+    LayerInspectorRowDelegate *wsel = (LayerInspectorRowDelegate *) this->sender();
+    this->SetActiveLayer(wsel->GetLayer());
+
+    // Put this layer's actions on the menu
+    m_SaveSelectedButton->setDefaultAction(wsel->saveAction());
+    }
+}
+
+void LayerInspectorDialog::SetActiveLayer(ImageWrapperBase *layer)
+{
+  // For our purposes, uninitialized layers are just the same as null layers,
+  // they can not participate in layer association.
+  if(layer && !layer->IsInitialized())
+    layer = NULL;
+
+  // For each model, set the layer
+  m_Model->GetColorMapModel()->SetLayer(layer);
+
+  m_Model->GetIntensityCurveModel()->SetLayer(
+        layer->GetDisplayMapping()->GetIntensityCurve() ? layer : NULL);
+
+  m_Model->GetImageInfoModel()->SetLayer(layer);
+  m_Model->GetLayerGeneralPropertiesModel()->SetLayer(layer);
+}
+
+void
+LayerInspectorDialog::UpdateLayerLayoutAction()
+{
+  DisplayLayoutModel *dlm = m_Model->GetDisplayLayoutModel();
+  LayerLayout ll = dlm->GetSliceViewLayerLayoutModel()->GetValue();
+
+  if(ll == LAYOUT_TILED)
+    {
+    ui->actionLayoutToggle->setIcon(QIcon(":/root/layout_overlay_16.png"));
+    ui->actionLayoutToggle->setToolTip("Render image overlays on top of each other");
+    }
+  else if(ll == LAYOUT_STACKED)
+    {
+    ui->actionLayoutToggle->setIcon(QIcon(":/root/layout_tile_16.png"));
+    ui->actionLayoutToggle->setToolTip("Tile image overlays side by side");
+    }
+}
+
+void LayerInspectorDialog::on_actionSaveSelectedLayerAs_triggered()
+{
+  // Save the currently selected layer
+
+
+}
+
+void LayerInspectorDialog::on_actionLayoutToggle_triggered(bool value)
+{
+  DisplayLayoutModel *dlm = m_Model->GetDisplayLayoutModel();
+  LayerLayout ll = dlm->GetSliceViewLayerLayoutModel()->GetValue();
+  if(ll == LAYOUT_TILED)
+    {
+    dlm->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_STACKED);
+    }
+  else
+    {
+    dlm->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED);
+    }
+}
+
+void LayerInspectorDialog::on_buttonBox_accepted()
+{
+  this->close();
+}
+
+void LayerInspectorDialog::on_buttonBox_rejected()
+{
+  this->close();
+}
+
+void LayerInspectorDialog::advanceTab()
+{
+  int pos = ui->tabWidget->currentIndex();
+  int ntab = ui->tabWidget->count();
+  ui->tabWidget->setCurrentIndex((pos + 1) % ntab);
+}
+
+void LayerInspectorDialog::on_actionOpenLayer_triggered()
+{
+  FindUpstreamAction(this, "actionAdd_Overlay")->trigger();
+}
diff --git a/GUI/Qt/Windows/LayerInspectorDialog.h b/GUI/Qt/Windows/LayerInspectorDialog.h
new file mode 100644
index 0000000..2276b25
--- /dev/null
+++ b/GUI/Qt/Windows/LayerInspectorDialog.h
@@ -0,0 +1,85 @@
+#ifndef LAYERINSPECTORDIALOG_H
+#define LAYERINSPECTORDIALOG_H
+
+#include <QDialog>
+#include <QAbstractListModel>
+
+class IntensityCurveBox;
+class ContrastInspector;
+class GlobalUIModel;
+class EventBucket;
+class LayerInspectorRowDelegate;
+class ImageWrapperBase;
+class QToolButton;
+class QMenu;
+class QAction;
+
+namespace Ui {
+    class LayerInspectorDialog;
+}
+
+
+
+
+class LayerInspectorDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+    explicit LayerInspectorDialog(QWidget *parent = 0);
+    ~LayerInspectorDialog();
+
+  void SetModel(GlobalUIModel *model);
+
+  void SetPageToContrastAdjustment();
+  void SetPageToColorMap();
+  void SetPageToImageInfo();
+
+  // Get the context menu corresponding to a specific layer.
+  QMenu *GetLayerContextMenu(ImageWrapperBase *layer);
+
+  // Get the save action for a specific layer
+  QAction *GetLayerSaveAction(ImageWrapperBase *layer);
+
+  bool eventFilter(QObject *source, QEvent *event);
+
+public slots:
+
+  virtual void onModelUpdate(const EventBucket &bucket);
+
+  void layerSelected(bool);
+
+  void advanceTab();
+
+signals:
+
+  void layerListHover(bool);
+
+private slots:
+  void on_actionSaveSelectedLayerAs_triggered();
+
+  void on_actionLayoutToggle_triggered(bool);
+
+  void on_buttonBox_accepted();
+
+  void on_buttonBox_rejected();
+
+  void on_actionOpenLayer_triggered();
+
+private:
+  Ui::LayerInspectorDialog *ui;
+  GlobalUIModel *m_Model;
+
+  void GenerateModelsForLayers();
+  void BuildLayerWidgetHierarchy();
+  void SetActiveLayer(ImageWrapperBase *layer);
+  void UpdateLayerLayoutAction();
+
+  // Tool bar buttons that use actions from the selected layer widgets
+  QToolButton *m_SaveSelectedButton;
+
+  // List of layer delegate widgets
+  QList<LayerInspectorRowDelegate *> m_Delegates;
+};
+
+#endif // LAYERINSPECTORDIALOG_H
diff --git a/GUI/Qt/Windows/LayerInspectorDialog.ui b/GUI/Qt/Windows/LayerInspectorDialog.ui
new file mode 100644
index 0000000..f7fb6d8
--- /dev/null
+++ b/GUI/Qt/Windows/LayerInspectorDialog.ui
@@ -0,0 +1,291 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LayerInspectorDialog</class>
+ <widget class="QDialog" name="LayerInspectorDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>640</width>
+    <height>537</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Image Layer Inspector - ITK-SNAP</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <property name="spacing">
+    <number>12</number>
+   </property>
+   <property name="leftMargin">
+    <number>6</number>
+   </property>
+   <property name="topMargin">
+    <number>6</number>
+   </property>
+   <property name="rightMargin">
+    <number>6</number>
+   </property>
+   <property name="bottomMargin">
+    <number>6</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <property name="minimumSize">
+      <size>
+       <width>162</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">QToolButton {
+	width: 16px;
+	height: 16px;
+	icon-size: 16px;
+	padding: 1px;
+}</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0,0,0">
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <layout class="QHBoxLayout" name="loToolbar">
+        <property name="spacing">
+         <number>4</number>
+        </property>
+       </layout>
+      </item>
+      <item>
+       <widget class="QScrollArea" name="saLayers">
+        <property name="styleSheet">
+         <string notr="true"/>
+        </property>
+        <property name="frameShape">
+         <enum>QFrame::NoFrame</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Plain</enum>
+        </property>
+        <property name="widgetResizable">
+         <bool>true</bool>
+        </property>
+        <widget class="QWidget" name="saLayersContents">
+         <property name="geometry">
+          <rect>
+           <x>0</x>
+           <y>0</y>
+           <width>150</width>
+           <height>409</height>
+          </rect>
+         </property>
+         <property name="styleSheet">
+          <string notr="true">QWidget#saLayersContents {
+	border-left: 1px solid grey;
+	border-right: 1px solid grey;
+	border-bottom: 1px solid grey;
+}</string>
+         </property>
+        </widget>
+       </widget>
+      </item>
+      <item>
+       <spacer name="verticalSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>40</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QDialogButtonBox" name="buttonBox">
+        <property name="standardButtons">
+         <set>QDialogButtonBox::Close</set>
+        </property>
+        <property name="centerButtons">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_2" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout_3">
+         <property name="spacing">
+          <number>8</number>
+         </property>
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTabWidget" name="tabWidget">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+       <horstretch>1</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="currentIndex">
+      <number>1</number>
+     </property>
+     <widget class="GeneralLayerInspector" name="cmpComponent">
+      <attribute name="title">
+       <string>General</string>
+      </attribute>
+      <attribute name="toolTip">
+       <string><html><head/><body><p>Select which channels to show for multi-channel images (images with multiple components per voxel)</p></body></html></string>
+      </attribute>
+     </widget>
+     <widget class="ContrastInspector" name="cmpContrast">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>1</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Contrast</string>
+      </attribute>
+     </widget>
+     <widget class="ColorMapInspector" name="cmpColorMap">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>1</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Color Map</string>
+      </attribute>
+     </widget>
+     <widget class="ImageInfoInspector" name="cmpInfo">
+      <attribute name="title">
+       <string>Info</string>
+      </attribute>
+     </widget>
+     <widget class="MetadataInspector" name="cmpMetadata">
+      <attribute name="title">
+       <string>Metadata</string>
+      </attribute>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+  <action name="actionSaveSelectedLayerAs">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/save_22.png</normaloff>:/root/save_22.png</iconset>
+   </property>
+   <property name="text">
+    <string>Save As...</string>
+   </property>
+  </action>
+  <action name="actionEditVisibility">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/layer_invisible_16.png</normaloff>
+     <normalon>:/root/layer_visible_16.png</normalon>:/root/layer_invisible_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Edit Visibility</string>
+   </property>
+   <property name="toolTip">
+    <string>Press this button to display layer visibility and opacity controls in the list of layers</string>
+   </property>
+  </action>
+  <action name="actionLayoutToggle">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/layout_tile_16.png</normaloff>:/root/layout_tile_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Layout Toggle</string>
+   </property>
+   <property name="toolTip">
+    <string>Toggle layout between tiled and stacked</string>
+   </property>
+  </action>
+  <action name="actionOpenLayer">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/open_22.png</normaloff>:/root/open_22.png</iconset>
+   </property>
+   <property name="text">
+    <string>Open Layer</string>
+   </property>
+   <property name="toolTip">
+    <string>Open an additional image layer</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+G</string>
+   </property>
+  </action>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>ContrastInspector</class>
+   <extends>QWidget</extends>
+   <header>ContrastInspector.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>ColorMapInspector</class>
+   <extends>QWidget</extends>
+   <header>ColorMapInspector.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>ImageInfoInspector</class>
+   <extends>QWidget</extends>
+   <header>ImageInfoInspector.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>MetadataInspector</class>
+   <extends>QWidget</extends>
+   <header location="global">MetadataInspector.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>GeneralLayerInspector</class>
+   <extends>QWidget</extends>
+   <header>GeneralLayerInspector.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/MainControlPanel.cxx b/GUI/Qt/Windows/MainControlPanel.cxx
new file mode 100644
index 0000000..8985846
--- /dev/null
+++ b/GUI/Qt/Windows/MainControlPanel.cxx
@@ -0,0 +1,238 @@
+#include "MainControlPanel.h"
+#include "ui_MainControlPanel.h"
+#include "GlobalUIModel.h"
+#include "QtWidgetActivator.h"
+#include "SNAPQtCommon.h"
+#include "LabelSelectionButton.h"
+#include "LabelSelectionPopup.h"
+#include "MainImageWindow.h"
+#include "GlobalState.h"
+
+#include <QtActionGroupCoupling.h>
+#include <QActionGroup>
+#include <QMenu>
+
+/*
+ * A style sheet for making blue buttons with a drop down. For now we are
+ * not going to use these, but may need them if more tools are added to
+ * the main toolbox
+
+    QToolButton {
+    border-image: url(:/root/fltkbutton.png) repeat;
+    border-top-width: 8px;
+    border-bottom-width: 8px;
+    border-left-width: 3px;
+    border-right-width: 3px;
+    background-origin: content;
+    padding-top: -8px;
+    padding-bottom: -8px;
+    padding-left: -7px;
+    padding-right: 1px;
+    width:33px;
+    height:28px;
+    }
+
+    QToolButton[popupMode="0"]
+    {
+    width:28px;
+    padding-left: -2px;
+    padding-right: -2px;
+
+    }
+
+    QToolButton:pressed, QToolButton:checked {
+      border-image: url(:/root/fltkbutton_pressed.png) repeat;
+    }
+
+    QToolButton::menu-button {
+    border:0px;
+    margin:0px;
+    padding-top: 17px;
+    padding-right: 2px;
+    }
+
+    QToolButton::menu-arrow {
+    image: url(:/root/menu-arrow.png);
+    }
+
+    */
+
+/*
+ * Some commented out code for setting up a dropdown menu of actions
+
+  // Create an action group for the navigation button
+  QMenu *menuNav = new QMenu(this);
+  menuNav->addAction(ui->actionCrosshair);
+  menuNav->addAction(ui->actionZoomPan);
+  ui->btnNavigation->setMenu(menuNav);
+  ui->btnNavigation->setDefaultAction(ui->actionCrosshair);
+
+  connect(menuNav, SIGNAL(triggered(QAction*)),
+          this, SLOT(onNavigationButtonAction(QAction *)));
+
+  // Create an action group for the drawing tool button
+  QMenu *menuDraw = new QMenu(this);
+  menuDraw->addAction(ui->actionPolygon);
+  menuDraw->addAction(ui->actionPaintbrush);
+  ui->btnDrawing->setMenu(menuDraw);
+  ui->btnDrawing->setDefaultAction(ui->actionPolygon);
+
+  connect(menuDraw, SIGNAL(triggered(QAction*)),
+          this, SLOT(onDrawingButtonAction(QAction *)));
+
+ */
+
+#include <QToolBar>
+#include <QWhatsThis>
+
+MainControlPanel::MainControlPanel(MainImageWindow *parent) :
+  SNAPComponent(parent),
+  ui(new Ui::MainControlPanel)
+{
+  ui->setupUi(this);
+
+  m_Model = NULL;
+
+  // The mode toolbar
+  QToolBar *toolbar = new QToolBar(this);
+  ui->panelToolbarMode->layout()->addWidget(toolbar);  
+  toolbar->addActions(parent->GetMainToolActionGroup()->actions());
+
+  // The action toolbar
+  QToolBar *toolCmd = new QToolBar(this);
+  ui->panelToolbarAction->layout()->addWidget(toolCmd);
+
+  // Label selection button
+  m_LabelSelectionButton = new LabelSelectionButton(this);
+
+  toolCmd->addAction(FindUpstreamAction(this, "actionUndo"));
+  toolCmd->addAction(FindUpstreamAction(this, "actionRedo"));
+  toolCmd->addWidget(m_LabelSelectionButton);
+  toolCmd->addAction(FindUpstreamAction(this, "actionLayerInspector"));
+
+  // Add a shortcut for the button
+  m_LabelSelectionButton->setShortcut(QKeySequence("l"));
+
+  // Set up the label popup
+  m_LabelSelectionPopup = new LabelSelectionPopup(this);
+
+  // Set up the 3D toolbar
+  QToolBar *tool3D = new QToolBar(this);
+  ui->panelToolbarMode3D->layout()->addWidget(tool3D);
+  tool3D->addActions(parent->Get3DToolActionGroup()->actions());
+}
+
+void MainControlPanel::SetModel(GlobalUIModel *model)
+{
+  m_Model = model;
+  ui->pageCursorInspector->SetModel(m_Model->GetCursorInspectionModel());
+  ui->pageZoomInspector->SetModel(m_Model);
+  ui->pageLabelInspector->SetModel(m_Model);
+  ui->pageDisplayInspector->SetModel(m_Model->GetDisplayLayoutModel());
+  ui->pageSyncInspector->SetModel(m_Model->GetSynchronizationModel());
+  ui->pagePaintbrushTool->SetModel(m_Model->GetPaintbrushSettingsModel());
+  ui->pageSnakeTool->SetModel(m_Model);
+
+  m_LabelSelectionButton->SetModel(model);
+  m_LabelSelectionPopup->SetModel(model);
+
+  // Set up state machine
+  activateOnFlag(this, m_Model, UIF_BASEIMG_LOADED);
+
+  // Listen to changes in the toolbar mode
+  connectITK(m_Model->GetGlobalState()->GetToolbarModeModel(), ValueChangedEvent());
+  connectITK(m_Model->GetGlobalState()->GetToolbarMode3DModel(), ValueChangedEvent());
+}
+
+void MainControlPanel::onModelUpdate(const EventBucket &bucket)
+{
+  // A static array of widget/mode mappings
+  static QToolButton *mode_inspector_btn[] = {
+    ui->btnCursorInspector,
+    ui->btnZoomInspector,
+    ui->btnLabelInspector,
+    ui->btnToolInspector,
+    ui->btnToolInspector,
+    ui->btnToolInspector };
+
+  static QWidget *mode_tool_pages[] = {
+    ui->pageBlank,
+    ui->pageBlank,
+    ui->pageBlank,
+    ui->pagePaintbrushTool,
+    ui->pageSnakeTool,
+    ui->pageBlank};
+
+  // Respond to changes in toolbar mode
+  GlobalState *gs = m_Model->GetGlobalState();
+  if(bucket.HasEvent(ValueChangedEvent(), gs->GetToolbarModeModel()))
+    {
+    int mode = (int) gs->GetToolbarMode();
+    mode_inspector_btn[mode]->click();
+    ui->stackToolPage->setCurrentWidget(mode_tool_pages[mode]);
+    }
+}
+
+
+MainControlPanel::~MainControlPanel()
+{
+  delete ui;
+}
+
+void MainControlPanel::on_btnCursorInspector_clicked(bool checked)
+{
+  if(checked)
+    {
+    ui->stack->setCurrentWidget(ui->pageCursorInspector);
+    ui->grpInspector->setTitle("Cursor Inspector");
+    }
+
+}
+
+void MainControlPanel::on_btnZoomInspector_clicked(bool checked)
+{
+  if(checked)
+    {
+    ui->stack->setCurrentWidget(ui->pageZoomInspector);
+    ui->grpInspector->setTitle("Zoom Inspector");
+    }
+}
+
+void MainControlPanel::on_btnLabelInspector_clicked(bool checked)
+{
+  if(checked)
+    {
+    ui->stack->setCurrentWidget(ui->pageLabelInspector);
+    ui->grpInspector->setTitle("Label Inspector");
+    }
+}
+
+void MainControlPanel::on_btnDisplayInspector_clicked(bool checked)
+{
+  if(checked)
+    {
+    ui->stack->setCurrentWidget(ui->pageDisplayInspector);
+    ui->grpInspector->setTitle("Display Layout Inspector");
+    }
+}
+
+void MainControlPanel::on_btnSyncInspector_clicked(bool checked)
+{
+  if(checked)
+    {
+    ui->stack->setCurrentWidget(ui->pageSyncInspector);
+    ui->grpInspector->setTitle("Synchronization Inspector");
+    }
+}
+
+void MainControlPanel::on_btnToolInspector_clicked(bool checked)
+{
+  if(checked)
+    {
+    ui->stack->setCurrentWidget(ui->pageToolInspector);
+    ui->grpInspector->setTitle("Active Tool Inspector");
+    }
+}
+
+
+
diff --git a/GUI/Qt/Windows/MainControlPanel.h b/GUI/Qt/Windows/MainControlPanel.h
new file mode 100644
index 0000000..635c51d
--- /dev/null
+++ b/GUI/Qt/Windows/MainControlPanel.h
@@ -0,0 +1,53 @@
+#ifndef MAINCONTROLPANEL_H
+#define MAINCONTROLPANEL_H
+
+#include <SNAPComponent.h>
+
+class LabelSelectionButton;
+class LabelSelectionPopup;
+
+namespace Ui {
+class MainControlPanel;
+}
+
+class GlobalUIModel;
+class MainImageWindow;
+
+class MainControlPanel : public SNAPComponent
+{
+  Q_OBJECT
+  
+public:
+  explicit MainControlPanel(MainImageWindow *parent = 0);
+  ~MainControlPanel();
+
+  void SetModel(GlobalUIModel *model);
+
+protected slots:
+
+  virtual void onModelUpdate(const EventBucket &bucket);
+
+private slots:
+
+  void on_btnCursorInspector_clicked(bool checked);
+
+  void on_btnZoomInspector_clicked(bool checked);
+
+  void on_btnLabelInspector_clicked(bool checked);
+
+  void on_btnDisplayInspector_clicked(bool checked);
+
+  void on_btnSyncInspector_clicked(bool checked);
+
+  void on_btnToolInspector_clicked(bool checked);
+
+
+private:
+  Ui::MainControlPanel *ui;
+  GlobalUIModel *m_Model;
+
+  LabelSelectionButton *m_LabelSelectionButton;
+  LabelSelectionPopup *m_LabelSelectionPopup;
+};
+
+#endif // MAINCONTROLPANEL_H
diff --git a/GUI/Qt/Windows/MainControlPanel.ui b/GUI/Qt/Windows/MainControlPanel.ui
new file mode 100644
index 0000000..7db5f42
--- /dev/null
+++ b/GUI/Qt/Windows/MainControlPanel.ui
@@ -0,0 +1,476 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainControlPanel</class>
+ <widget class="QWidget" name="MainControlPanel">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>184</width>
+    <height>588</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>184</width>
+    <height>0</height>
+   </size>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>184</width>
+    <height>16777215</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QGroupBox {
+  background-origin: content;
+  margin-top: 15px;
+  font-weight: bold;
+  font-size: 12px;
+  color: rgb(30,30,160);
+  background-color: rgb(237,237,237);
+  padding: 5px;
+  border-radius: 4px;
+  border: 1px solid rgb(130,130,130);
+}
+QGroupBox::title {
+  subcontrol-origin: 	margin;
+  subcontrol-position: top left;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>8</number>
+   </property>
+   <property name="margin">
+    <number>5</number>
+   </property>
+   <item>
+    <widget class="QGroupBox" name="grpToolbox">
+     <property name="styleSheet">
+      <string notr="true">
+
+QToolBar {
+	padding: 0px;
+}</string>
+     </property>
+     <property name="title">
+      <string>Main Toolbar</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_4">
+      <property name="spacing">
+       <number>2</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QWidget" name="panelToolbarMode" native="true">
+        <property name="styleSheet">
+         <string notr="true">QToolButton {
+	width: 22px;
+	height: 22px;
+	icon-size: 22px;
+	padding: 1px;
+}</string>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_5">
+         <property name="margin">
+          <number>0</number>
+         </property>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="Line" name="line">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="panelToolbarAction" native="true">
+        <property name="styleSheet">
+         <string notr="true">QToolButton {
+	width: 16px;
+	height: 16px;
+	icon-size: 16px;
+	padding: 1px;
+}</string>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <property name="margin">
+          <number>0</number>
+         </property>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="grpInspector">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>1</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Cursor Inspector</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>5</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QWidget" name="widget" native="true">
+        <property name="styleSheet">
+         <string notr="true">QToolButton {
+  icon-size: 22px;
+  min-width: 1ex;
+  border-top: 1px solid rgb(108, 108, 108);
+  border-bottom: 1px solid rgb(108, 108, 108);
+  border-left: 1px;
+  border-right: 1px;
+  background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.0394089 rgba(245, 245, 245, 255), stop:0.487685 rgba(226, 226, 226, 255), stop:0.502463 rgba(215, 215, 215, 255), stop:1 rgba(245, 245, 245, 255));
+  width: 25px;
+  height: 25px;
+}
+QToolButton:hover, QToolButton:checked {
+  background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.0394089 rgba(214, 228, 245, 255), stop:0.487685 rgba(193, 205, 221, 255), stop:0.502463 rgba(182, 193, 207, 255), stop:1 rgba(215, 228, 245, 255));
+  padding:0px;
+  
+}
+</string>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <property name="spacing">
+          <number>0</number>
+         </property>
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QToolButton" name="btnCursorInspector">
+           <property name="minimumSize">
+            <size>
+             <width>25</width>
+             <height>30</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string><html><head/><body><p><span style=" font-weight:600;">Cursor Inspector</span></p><p>Examine the voxel under the cursor and enter exact 3D cursor location.</p></body></html></string>
+           </property>
+           <property name="styleSheet">
+            <string notr="true"/>
+           </property>
+           <property name="text">
+            <string>...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../Resources/SNAPResources.qrc">
+             <normaloff>:/root/crosshair.gif</normaloff>:/root/crosshair.gif</iconset>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <property name="checked">
+            <bool>true</bool>
+           </property>
+           <property name="autoExclusive">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QToolButton" name="btnZoomInspector">
+           <property name="minimumSize">
+            <size>
+             <width>25</width>
+             <height>30</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string><html><head/><body><p><span style=" font-weight:600;">Zoom Inspector</span></p><p>Control zoom factor in all slice views. </p></body></html></string>
+           </property>
+           <property name="styleSheet">
+            <string notr="true"/>
+           </property>
+           <property name="text">
+            <string>...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../Resources/SNAPResources.qrc">
+             <normaloff>:/root/zoom.gif</normaloff>:/root/zoom.gif</iconset>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <property name="autoExclusive">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QToolButton" name="btnLabelInspector">
+           <property name="minimumSize">
+            <size>
+             <width>25</width>
+             <height>27</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string><html><head/><body><p><span style=" font-weight:600;">Label Inspector</span></p><p>Select the foreground and background labels for segmentation tasks. </p></body></html></string>
+           </property>
+           <property name="styleSheet">
+            <string notr="true"/>
+           </property>
+           <property name="text">
+            <string>...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../Resources/SNAPResources.qrc">
+             <normaloff>:/root/paintbrush.gif</normaloff>:/root/paintbrush.gif</iconset>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <property name="autoExclusive">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QToolButton" name="btnDisplayInspector">
+           <property name="minimumSize">
+            <size>
+             <width>25</width>
+             <height>27</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string><html><head/><body><p><span style=" font-weight:600;">Display Layout Inspector</span></p><p>Control which slice views are shown in the main ITK-SNAP window and how multiple image layers are rendered. </p></body></html></string>
+           </property>
+           <property name="styleSheet">
+            <string notr="true"/>
+           </property>
+           <property name="text">
+            <string>...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../Resources/SNAPResources.qrc">
+             <normaloff>:/root/dl_toolbox.png</normaloff>:/root/dl_toolbox.png</iconset>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <property name="autoExclusive">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QToolButton" name="btnSyncInspector">
+           <property name="minimumSize">
+            <size>
+             <width>25</width>
+             <height>27</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string><html><head/><body><p><span style=" font-weight:600;">Synchronization Inspector</span></p><p>Adjust synchronization of cursor, zoom and pan across multiple ITK-SNAP sessions running on one computer.</p></body></html></string>
+           </property>
+           <property name="styleSheet">
+            <string notr="true"/>
+           </property>
+           <property name="text">
+            <string>...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../Resources/SNAPResources.qrc">
+             <normaloff>:/root/network-wireless.png</normaloff>:/root/network-wireless.png</iconset>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <property name="autoExclusive">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QToolButton" name="btnToolInspector">
+           <property name="minimumSize">
+            <size>
+             <width>25</width>
+             <height>27</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string><html><head/><body><p><span style=" font-weight:600;">Active Tool Inspector</span></p><p>Adjust parameters and settings specific to the currently selected tool in the main toolbar.</p></body></html></string>
+           </property>
+           <property name="styleSheet">
+            <string notr="true"/>
+           </property>
+           <property name="text">
+            <string>...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../Resources/SNAPResources.qrc">
+             <normaloff>:/root/tools.png</normaloff>:/root/tools.png</iconset>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <property name="autoExclusive">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QStackedWidget" name="stack">
+        <property name="currentIndex">
+         <number>0</number>
+        </property>
+        <widget class="CursorInspector" name="pageCursorInspector"/>
+        <widget class="ZoomInspector" name="pageZoomInspector"/>
+        <widget class="LabelInspector" name="pageLabelInspector"/>
+        <widget class="DisplayLayoutInspector" name="pageDisplayInspector">
+         <property name="toolTip">
+          <string/>
+         </property>
+        </widget>
+        <widget class="SynchronizationInspector" name="pageSyncInspector">
+         <property name="toolTip">
+          <string/>
+         </property>
+        </widget>
+        <widget class="QWidget" name="pageToolInspector">
+         <property name="toolTip">
+          <string/>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_3">
+          <property name="spacing">
+           <number>0</number>
+          </property>
+          <property name="margin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QStackedWidget" name="stackToolPage">
+            <property name="currentIndex">
+             <number>1</number>
+            </property>
+            <widget class="SnakeToolROIPanel" name="pageSnakeTool"/>
+            <widget class="PaintbrushToolPanel" name="pagePaintbrushTool"/>
+            <widget class="QWidget" name="pageBlank"/>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="grpToolbox3D">
+     <property name="styleSheet">
+      <string notr="true">
+
+QToolBar {
+	padding: 0px;
+}</string>
+     </property>
+     <property name="title">
+      <string>3D Toolbar</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_6">
+      <property name="spacing">
+       <number>2</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QWidget" name="panelToolbarMode3D" native="true">
+        <property name="styleSheet">
+         <string notr="true">QToolButton {
+	width: 22px;
+	height: 22px;
+	icon-size: 22px;
+	padding: 1px;
+}</string>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_7">
+         <property name="margin">
+          <number>0</number>
+         </property>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>CursorInspector</class>
+   <extends>QWidget</extends>
+   <header>CursorInspector.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>ZoomInspector</class>
+   <extends>QWidget</extends>
+   <header>ZoomInspector.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>LabelInspector</class>
+   <extends>QWidget</extends>
+   <header>LabelInspector.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>SnakeToolROIPanel</class>
+   <extends>QWidget</extends>
+   <header>SnakeToolROIPanel.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>PaintbrushToolPanel</class>
+   <extends>QWidget</extends>
+   <header>PaintbrushToolPanel.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>DisplayLayoutInspector</class>
+   <extends>QWidget</extends>
+   <header>DisplayLayoutInspector.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>SynchronizationInspector</class>
+   <extends>QWidget</extends>
+   <header>SynchronizationInspector.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/MainImageWindow.cxx b/GUI/Qt/Windows/MainImageWindow.cxx
new file mode 100644
index 0000000..ba7c907
--- /dev/null
+++ b/GUI/Qt/Windows/MainImageWindow.cxx
@@ -0,0 +1,1634 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+#include "MeshOptions.h"
+
+#include "MainImageWindow.h"
+#include "ui_MainImageWindow.h"
+
+#include "MainControlPanel.h"
+#include "ImageIOWizard.h"
+#include "ImageIOWizardModel.h"
+#include "GlobalUIModel.h"
+#include "ImageIODelegates.h"
+#include "LayerInspectorDialog.h"
+#include "IntensityCurveModel.h"
+#include "DisplayLayoutModel.h"
+#include "ColorMapModel.h"
+#include "ViewPanel3D.h"
+#include "SnakeWizardPanel.h"
+#include "LatentITKEventNotifier.h"
+#include <QProgressDialog>
+#include "QtReporterDelegates.h"
+#include "SliceWindowCoordinator.h"
+#include "HistoryQListModel.h"
+#include "GenericView3D.h"
+#include "GenericSliceView.h"
+#include "SplashPanel.h"
+#include "QtWidgetCoupling.h"
+#include "SimpleFileDialogWithHistory.h"
+#include "StatisticsDialog.h"
+#include "MeshExportWizard.h"
+#include "ImageWrapperBase.h"
+#include "IRISImageData.h"
+#include "AboutDialog.h"
+#include "HistoryManager.h"
+#include "DefaultBehaviorSettings.h"
+#include "SynchronizationModel.h"
+
+
+
+#include "QtCursorOverride.h"
+#include "QtWarningDialog.h"
+#include <QtWidgetCoupling.h>
+#include <QtWidgetActivator.h>
+#include <QtActionGroupCoupling.h>
+
+#include <LabelEditorDialog.h>
+#include <ReorientImageDialog.h>
+#include <DropActionDialog.h>
+#include <PreferencesDialog.h>
+#include "SaveModifiedLayersDialog.h"
+
+
+#include <QAbstractListModel>
+#include <QItemDelegate>
+#include <QPainter>
+#include <QDockWidget>
+#include <QMessageBox>
+#include <QDropEvent>
+#include <QDragEnterEvent>
+#include <QUrl>
+#include <QFileDialog>
+#include <QGLWidget>
+#include <QDesktopServices>
+#include <SNAPQtCommon.h>
+#include <QMimeData>
+
+#include <QShortcut>
+
+
+MainImageWindow::MainImageWindow(QWidget *parent) :
+    QMainWindow(parent),
+    ui(new Ui::MainImageWindow),
+    m_Model(NULL)
+{
+  ui->setupUi(this);
+
+  // Group mutually exclusive actions into action groups
+  QActionGroup *grpToolbarMain = new QActionGroup(this);
+  ui->actionCrosshair->setActionGroup(grpToolbarMain);
+  ui->actionZoomPan->setActionGroup(grpToolbarMain);
+  ui->actionPolygon->setActionGroup(grpToolbarMain);
+  ui->actionPaintbrush->setActionGroup(grpToolbarMain);
+  ui->actionSnake->setActionGroup(grpToolbarMain);
+
+  QActionGroup *grpToolbar3D = new QActionGroup(this);
+  ui->action3DTrackball->setActionGroup(grpToolbar3D);
+  ui->action3DCrosshair->setActionGroup(grpToolbar3D);
+  ui->action3DSpray->setActionGroup(grpToolbar3D);
+  ui->action3DScalpel->setActionGroup(grpToolbar3D);
+
+  // Make sure we initialize on the intro page
+  ui->stackMain->setCurrentWidget(ui->pageSplash);
+
+  // Create the view panels array
+  m_ViewPanels[0] = ui->panel0;
+  m_ViewPanels[1] = ui->panel1;
+  m_ViewPanels[2] = ui->panel2;
+  m_ViewPanels[3] = ui->panel3D;
+
+  // Initialize the dialogs
+  m_LabelEditor = new LabelEditorDialog(this);
+  m_LabelEditor->setModal(false);
+
+  m_LayerInspector = new LayerInspectorDialog(this);
+  m_LayerInspector->setModal(false);
+
+  m_ReorientImageDialog = new ReorientImageDialog(this);
+  m_ReorientImageDialog->setModal(false);
+
+  m_DropDialog = new DropActionDialog(this);
+
+  m_StatisticsDialog = new StatisticsDialog(this);
+  m_StatisticsDialog->setModal(false);
+
+  // Initialize the docked panels
+  m_DockLeft = new QDockWidget(this);
+  m_DockLeft->setAllowedAreas(Qt::LeftDockWidgetArea);
+  m_DockLeft->setFeatures(
+        QDockWidget::DockWidgetFloatable |
+        QDockWidget::DockWidgetMovable);
+  m_DockLeft->setWindowTitle("ITK-SNAP Toolbox");
+  this->addDockWidget(Qt::LeftDockWidgetArea, m_DockLeft);
+
+  m_ControlPanel = new MainControlPanel(this);
+  m_DockLeft->setWidget(m_ControlPanel);
+
+  m_DockRight = new QDockWidget("Segment 3D", this);
+  m_SnakeWizard = new SnakeWizardPanel(this);
+  m_DockRight->setWidget(m_SnakeWizard);
+  m_DockRight->setAllowedAreas(Qt::RightDockWidgetArea);
+  m_DockRight->setFeatures(
+        QDockWidget::DockWidgetFloatable |
+        QDockWidget::DockWidgetMovable);
+  this->addDockWidget(Qt::RightDockWidgetArea, m_DockRight);
+
+  // Set up the recent items panels
+  connect(ui->panelRecentImages, SIGNAL(RecentItemSelected(QString)),
+          SLOT(LoadMainImage(QString)));
+
+  connect(ui->panelRecentWorkspaces, SIGNAL(RecentItemSelected(QString)),
+          SLOT(LoadProject(QString)));
+
+  // Set the splash panel in the left dock
+  m_SplashPanel = new SplashPanel(this);
+  m_DockLeft->setWidget(m_SplashPanel);
+
+  // Create the about dialog
+  m_AboutDialog = new AboutDialog(this);
+
+  // Create the preferences dialog
+  m_PreferencesDialog = new PreferencesDialog(this);
+
+  // Hide the right dock for now
+  m_DockRight->setVisible(false);
+
+  // Hide the dock when the wizard finishes
+  connect(m_SnakeWizard, SIGNAL(wizardFinished()),
+          this, SLOT(onSnakeWizardFinished()));
+
+  // Make the margins adjust when the docks are attached
+  connect(m_DockLeft, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
+          this, SLOT(AdjustMarginsForDocks()));
+
+  connect(m_DockLeft, SIGNAL(topLevelChanged(bool)),
+          this, SLOT(AdjustMarginsForDocks()));
+
+  connect(m_DockLeft, SIGNAL(visibilityChanged(bool)),
+          this, SLOT(AdjustMarginsForDocks()));
+
+  connect(m_DockRight, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
+          this, SLOT(AdjustMarginsForDocks()));
+
+  connect(m_DockRight, SIGNAL(topLevelChanged(bool)),
+          this, SLOT(AdjustMarginsForDocks()));
+
+  connect(m_DockRight, SIGNAL(visibilityChanged(bool)),
+          this, SLOT(AdjustMarginsForDocks()));
+
+  // Hook up buttons to actions
+  connect(ui->btnLoadMain, SIGNAL(clicked()), ui->actionOpenMain, SLOT(trigger()));
+  connect(ui->btnLoadWorkspace, SIGNAL(clicked()), ui->actionOpenWorkspace, SLOT(trigger()));
+
+
+  // Set up the progress dialog
+  m_Progress = new QProgressDialog(this);
+
+  // Create the delegate to pass in to the model
+  m_ProgressReporterDelegate = new QtProgressReporterDelegate();
+  m_ProgressReporterDelegate->SetProgressDialog(m_Progress);
+
+  // Set title
+  this->setWindowTitle("ITK-SNAP");
+
+  // We accept drop events
+  setAcceptDrops(true);
+
+  // Connect recent file/project menu items
+  connect(ui->actionRecent_1, SIGNAL(triggered()), SLOT(LoadRecentActionTriggered()));
+  connect(ui->actionRecent_2, SIGNAL(triggered()), SLOT(LoadRecentActionTriggered()));
+  connect(ui->actionRecent_3, SIGNAL(triggered()), SLOT(LoadRecentActionTriggered()));
+  connect(ui->actionRecent_4, SIGNAL(triggered()), SLOT(LoadRecentActionTriggered()));
+  connect(ui->actionRecent_5, SIGNAL(triggered()), SLOT(LoadRecentActionTriggered()));
+  connect(ui->actionRecentWorkspace1, SIGNAL(triggered()), SLOT(LoadRecentProjectActionTriggered()));
+  connect(ui->actionRecentWorkspace2, SIGNAL(triggered()), SLOT(LoadRecentProjectActionTriggered()));
+  connect(ui->actionRecentWorkspace3, SIGNAL(triggered()), SLOT(LoadRecentProjectActionTriggered()));
+  connect(ui->actionRecentWorkspace4, SIGNAL(triggered()), SLOT(LoadRecentProjectActionTriggered()));
+  connect(ui->actionRecentWorkspace5, SIGNAL(triggered()), SLOT(LoadRecentProjectActionTriggered()));
+
+  // Set up the animation timer
+  m_AnimateTimer = new QTimer(this);
+  m_AnimateTimer->setInterval(1000);
+  connect(m_AnimateTimer, SIGNAL(timeout()), SLOT(onAnimationTimeout()));
+
+  // Start the timer (it doesn't cost much...)
+  m_AnimateTimer->start();
+
+  // Create keyboard shortcuts for opacity (because there seems to be a bug/feature on MacOS
+  // where keyboard shortcuts require the Fn-key to be pressed in QMenu
+  this->HookupShortcutToAction(QKeySequence("s"), ui->actionSegmentationToggle);
+  this->HookupShortcutToAction(QKeySequence("a"), ui->actionSegmentationDecreaseOpacity);
+  this->HookupShortcutToAction(QKeySequence("d"), ui->actionSegmentationIncreaseOpacity);
+  this->HookupShortcutToAction(QKeySequence("q"), ui->actionOverlayVisibilityDecreaseAll);
+  this->HookupShortcutToAction(QKeySequence("w"), ui->actionOverlayVisibilityToggleAll);
+  this->HookupShortcutToAction(QKeySequence("e"), ui->actionOverlayVisibilityIncreaseAll);
+  this->HookupShortcutToAction(QKeySequence(Qt::Key_X), ui->actionToggle_All_Annotations);
+  this->HookupShortcutToAction(QKeySequence(Qt::SHIFT + Qt::Key_X), ui->actionToggle_Crosshair);
+  this->HookupShortcutToAction(QKeySequence("<"), ui->actionForegroundLabelPrev);
+  this->HookupShortcutToAction(QKeySequence(">"), ui->actionForegroundLabelNext);
+  this->HookupSecondaryShortcutToAction(QKeySequence(","), ui->actionForegroundLabelPrev);
+  this->HookupSecondaryShortcutToAction(QKeySequence("."), ui->actionForegroundLabelNext);
+  this->HookupShortcutToAction(QKeySequence("C"), ui->actionCenter_on_Cursor);
+}
+
+
+MainImageWindow::~MainImageWindow()
+{
+  delete m_ProgressReporterDelegate;
+  delete ui;
+}
+
+void MainImageWindow::HookupShortcutToAction(const QKeySequence &ks, QAction *action)
+{
+  // The bug/feature of single-key shortcuts not working is only in MacOS
+#ifdef __APPLE__
+  QShortcut *short_S = new QShortcut(ks, this);
+  connect(short_S, SIGNAL(activated()), action, SLOT(trigger()));
+#endif
+}
+
+void MainImageWindow::HookupSecondaryShortcutToAction(const QKeySequence &ks, QAction *action)
+{
+  QShortcut *short_S = new QShortcut(ks, this);
+  connect(short_S, SIGNAL(activated()), action, SLOT(trigger()));
+}
+
+
+void MainImageWindow::Initialize(GlobalUIModel *model)
+{
+  m_Model = model;
+
+  // Initialize all the child panels
+  ui->panel0->Initialize(model,0);
+  ui->panel1->Initialize(model,1);
+  ui->panel2->Initialize(model,2);
+  ui->panel3D->Initialize(model);
+
+  // Initialize the dialogs
+  m_LabelEditor->SetModel(model->GetLabelEditorModel());
+  m_LayerInspector->SetModel(model);
+  m_SnakeWizard->SetModel(model);
+  m_ReorientImageDialog->SetModel(model->GetReorientImageModel());
+  m_DropDialog->SetModel(model);
+  m_StatisticsDialog->SetModel(model);
+  m_PreferencesDialog->SetModel(model->GetGlobalPreferencesModel());
+
+  // Initialize the docked panels
+  m_ControlPanel->SetModel(model);
+
+  // Attach the progress reporter delegate to the model
+  m_Model->SetProgressReporterDelegate(m_ProgressReporterDelegate);
+
+  // Listen for changes to the main image, updating the recent image file
+  // menu. TODO: a more direct way would be to listen to changes to the
+  // history, but that requires making history an event-firing object
+  LatentITKEventNotifier::connect(model->GetDriver(), LayerChangeEvent(),
+                                  this, SLOT(onModelUpdate(const EventBucket&)));
+
+  // Also listen to changes in the image filenames
+  LatentITKEventNotifier::connect(model->GetDriver(), WrapperMetadataChangeEvent(),
+                                  this, SLOT(onModelUpdate(const EventBucket&)));
+
+  // Hook up the recent lists
+  ui->panelRecentImages->Initialize(m_Model, "MainImage");
+  ui->panelRecentWorkspaces->Initialize(m_Model, "Project");
+
+  // Observe changes to the main image history, since that affects the recent
+  // menu items
+  LatentITKEventNotifier::connect(
+        model->GetHistoryModel("MainImage"), ValueChangedEvent(),
+        this, SLOT(onModelUpdate(EventBucket)));
+
+  // Likewise for the project history, they affect the menu titles
+  LatentITKEventNotifier::connect(
+        model->GetHistoryModel("Project"), ValueChangedEvent(),
+        this, SLOT(onModelUpdate(EventBucket)));
+
+  // Also listen to changes to the project filename
+  LatentITKEventNotifier::connect(
+        model->GetGlobalState()->GetProjectFilenameModel(), ValueChangedEvent(),
+        this, SLOT(onModelUpdate(EventBucket)));
+
+  // Couple the visibility of each view panel to the correponding property
+  // model in DisplayLayoutModel
+  DisplayLayoutModel *layoutModel = m_Model->GetDisplayLayoutModel();
+  for(int i = 0; i < 4; i++)
+    {
+    makeWidgetVisibilityCoupling(m_ViewPanels[i],
+                                 layoutModel->GetViewPanelVisibilityModel(i));
+    }
+
+  // Populate the recent file menu
+  this->UpdateRecentMenu();
+  this->UpdateRecentProjectsMenu();
+
+  // Update which page is shown
+  this->UpdateMainLayout();
+
+  // Set up activations - File menu
+  activateOnFlag(ui->actionOpenMain, m_Model, UIF_IRIS_MODE);
+  activateOnFlag(ui->menuRecent_Images, m_Model, UIF_IRIS_MODE);
+  activateOnFlag(ui->actionSaveMain, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+  activateOnFlag(ui->actionSaveSpeed, m_Model, UIF_SNAKE_MODE);
+  activateOnFlag(ui->actionSaveLevelSet, m_Model, UIF_LEVEL_SET_ACTIVE);
+  activateOnFlag(ui->actionSaveMainROI, m_Model, UIF_SNAKE_MODE);
+  activateOnFlag(ui->menuExport, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionUnload_All, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+
+  // Set up activations - Edit menu
+  activateOnFlag(ui->actionUndo, m_Model, UIF_UNDO_POSSIBLE);
+  activateOnFlag(ui->actionRedo, m_Model, UIF_REDO_POSSIBLE);
+  activateOnFlag(ui->actionForegroundLabelNext, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionForegroundLabelPrev, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionBackgroundLabelNext, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionBackgroundLabelPrev, m_Model, UIF_BASEIMG_LOADED);
+
+  // Add actions that are not on the menu
+  activateOnFlag(ui->actionZoomToFitInAllViews, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionCenter_on_Cursor, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionZoom_to_100, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionZoom_to_200, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionZoom_to_400, m_Model, UIF_BASEIMG_LOADED);
+
+
+  // Set up activations - Segmentation menu
+  activateOnFlag(ui->actionLoad_from_Image, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+  activateOnFlag(ui->actionClear, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionSaveSegmentation, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+  activateOnFlag(ui->actionSaveSegmentationAs, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+  activateOnFlag(ui->actionSave_as_Mesh, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+  activateOnFlag(ui->actionLoadLabels, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+  activateOnFlag(ui->actionSaveLabels, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+  activateOnFlag(ui->actionVolumesAndStatistics, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->menuAppearance, m_Model, UIF_BASEIMG_LOADED);
+
+  // Overlay action activations
+  activateOnFlag(ui->actionAdd_Overlay, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+  activateOnAllFlags(ui->actionUnload_Last_Overlay, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED, UIF_OVERLAY_LOADED);
+  activateOnAllFlags(ui->actionUnload_All_Overlays, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED, UIF_OVERLAY_LOADED);
+  activateOnFlag(ui->menuOverlayAppearance, m_Model, UIF_OVERLAY_LOADED);
+
+  // Workspace menu
+  activateOnFlag(ui->actionOpenWorkspace, m_Model, UIF_IRIS_MODE);
+  activateOnFlag(ui->actionSaveWorkspace, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+  activateOnFlag(ui->actionSaveWorkspaceAs, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+
+  // Tool action activations
+  activateOnFlag(ui->actionCrosshair, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionZoomPan, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionPolygon, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionSnake, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+  activateOnFlag(ui->actionPaintbrush, m_Model, UIF_BASEIMG_LOADED);
+
+  activateOnFlag(ui->action3DCrosshair, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->action3DTrackball, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->action3DScalpel, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+  activateOnFlag(ui->action3DSpray, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+
+  activateOnFlag(ui->actionLayerInspector, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionImage_Contrast, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionAutoContrastGlobal, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionResetContrastGlobal, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionColor_Map_Editor, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionLabel_Editor, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionImage_Information, m_Model, UIF_BASEIMG_LOADED);
+  activateOnFlag(ui->actionLabel_Editor, m_Model, UIF_BASEIMG_LOADED);
+
+  activateOnFlag(ui->actionReorient_Image, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED);
+
+  // Hook up toolbar actions to the toolbar
+  makeActionGroupCoupling(this->GetMainToolActionGroup(),
+                          m_Model->GetGlobalState()->GetToolbarModeModel());
+
+  makeActionGroupCoupling(this->Get3DToolActionGroup(),
+                          m_Model->GetGlobalState()->GetToolbarMode3DModel());
+
+  // Set the synchronization state
+  m_Model->GetSynchronizationModel()->SetCanBroadcast(this->isActiveWindow());
+}
+
+void MainImageWindow::ShowFirstTime()
+{
+  // Before showing the window, select the right pages for the main view
+  // and the sidebar, otherwise we get an annoying flashing of windows at
+  // startup, as the pages are changed in response to an event
+  this->UpdateMainLayout();
+
+  // Also make sure the other elements look right before showing the window
+  this->UpdateRecentMenu();
+  this->UpdateRecentProjectsMenu();
+  this->UpdateWindowTitle();
+
+  // Show the window
+  this->show();
+  this->raise();
+}
+
+// Slot for model updates
+void MainImageWindow::onModelUpdate(const EventBucket &b)
+{
+  if(b.HasEvent(MainImageDimensionsChangeEvent()))
+    {
+    // Delaying the relayout of the main window seems to reduce the amount of
+    // flashing that occurs when loading images.
+    // TODO: figure out if we can avoid flashing altogether
+    QTimer::singleShot(200, this, SLOT(UpdateMainLayout()));
+    }
+
+  if(b.HasEvent(LayerChangeEvent()) || b.HasEvent(WrapperMetadataChangeEvent()))
+    {
+    // Update the window title
+    this->UpdateWindowTitle();
+    }
+
+  if(b.HasEvent(ValueChangedEvent(), m_Model->GetHistoryModel("MainImage")))
+    {
+    this->UpdateRecentMenu();
+    }
+
+  if(b.HasEvent(ValueChangedEvent(), m_Model->GetHistoryModel("Project")))
+    {
+    this->UpdateRecentProjectsMenu();
+    }
+
+  if(b.HasEvent(ValueChangedEvent(), m_Model->GetGlobalState()->GetProjectFilenameModel()))
+    {
+    this->UpdateProjectMenuItems();
+    }
+}
+
+void MainImageWindow::UpdateMainLayout()
+{
+  // Choose what page to show depending on if an image has been loaded
+  if(m_Model->GetDriver()->IsMainImageLoaded())
+    {
+    ui->stackMain->setCurrentWidget(ui->pageMain);
+    m_DockLeft->setWidget(m_ControlPanel);
+    }
+  else
+    {
+    // Go to the splash page
+    ui->stackMain->setCurrentWidget(ui->pageSplash);
+    m_DockLeft->setWidget(m_SplashPanel);
+
+    // Choose the appropriate page depending on whether there are recent images
+    // available
+    if(m_Model->IsHistoryEmpty("MainImage"))
+      ui->tabSplash->setCurrentWidget(ui->tabGettingStarted);
+
+    else if(ui->tabSplash->currentWidget() == ui->tabGettingStarted)
+      ui->tabSplash->setCurrentWidget(ui->tabRecent);
+    }
+}
+
+
+void MainImageWindow::UpdateRecentMenu()
+{
+  // Menus to populate
+  QAction *menus[] = {
+    ui->actionRecent_1,
+    ui->actionRecent_2,
+    ui->actionRecent_3,
+    ui->actionRecent_4,
+    ui->actionRecent_5};
+
+  // List of filenames
+  std::vector<std::string> recent = m_Model->GetRecentHistoryItems("MainImage", 5);
+
+  // Toggle the state of each menu item
+  for(int i = 0; i < 5; i++)
+    {
+    if(i < recent.size())
+      {
+      menus[i]->setText(from_utf8(recent[i]));
+      menus[i]->setEnabled(true);
+      }
+    else
+      {
+      menus[i]->setText("Not available");
+      menus[i]->setEnabled(false);
+      }
+    }
+}
+
+void MainImageWindow::UpdateRecentProjectsMenu()
+{
+  // Menus to populate
+  QAction *menus[] = {
+    ui->actionRecentWorkspace1,
+    ui->actionRecentWorkspace2,
+    ui->actionRecentWorkspace3,
+    ui->actionRecentWorkspace4,
+    ui->actionRecentWorkspace5};
+
+  // List of filenames
+  std::vector<std::string> recent = m_Model->GetRecentHistoryItems("Project", 5);
+
+  // Toggle the state of each menu item
+  for(int i = 0; i < 5; i++)
+    {
+    if(i < recent.size())
+      {
+      menus[i]->setText(from_utf8(recent[i]));
+      menus[i]->setEnabled(true);
+      }
+    else
+      {
+      menus[i]->setText("Not available");
+      menus[i]->setEnabled(false);
+      }
+    }
+}
+
+
+
+void MainImageWindow::UpdateWindowTitle()
+{
+  GenericImageData *gid = m_Model->GetDriver()->GetIRISImageData();
+  QString mainfile, segfile;
+  if(gid && gid->IsMainLoaded())
+    {
+    mainfile = QFileInfo(from_utf8(gid->GetMain()->GetFileName())).fileName();
+    segfile = QFileInfo(from_utf8(gid->GetSegmentation()->GetFileName())).fileName();
+    }
+
+  if(mainfile.length())
+    {
+    if(segfile.length())
+      {
+      this->setWindowTitle(QString("%1 - %2 - ITK-SNAP").arg(mainfile).arg(segfile));
+      ui->actionSaveSegmentation->setText(QString("Save \"%1\"").arg(segfile));
+      ui->actionSaveSegmentationAs->setText(QString("Save \"%1\" as...").arg(segfile));
+      ui->actionSaveSegmentationAs->setVisible(true);
+      }
+    else
+      {
+      this->setWindowTitle(QString("%1 - New Segmentation - ITK-SNAP").arg(mainfile));
+      ui->actionSaveSegmentation->setText(QString("Save Segmentation Image ..."));
+      ui->actionSaveSegmentationAs->setVisible(false);
+      }
+    }
+  else
+    {
+    this->setWindowTitle("ITK-SNAP");
+    ui->actionSaveSegmentation->setText(QString("Save"));
+    ui->actionSaveSegmentationAs->setText(QString("Save as..."));
+    }
+}
+
+void MainImageWindow::UpdateProjectMenuItems()
+{
+  // Get the project filename
+  QString project = from_utf8(m_Model->GetGlobalState()->GetProjectFilename());
+  if(project.length())
+    {
+    // Get the filename without path
+    ui->actionSaveWorkspace->setText(
+          QString("Save Workspace \"%1\"").arg(QFileInfo(project).fileName()));
+    }
+  else
+    {
+    ui->actionSaveWorkspace->setText(QString("Save Workspace ..."));
+    }
+}
+
+SliceViewPanel * MainImageWindow::GetSlicePanel(unsigned int i)
+{
+  if(i == 0)
+    return ui->panel0;
+  else if (i == 1)
+    return ui->panel1;
+  else if (i == 2)
+    return ui->panel2;
+  else
+    return NULL;
+}
+
+void MainImageWindow::closeEvent(QCloseEvent *event)
+{
+  // Prompt for unsaved changes
+  if(!SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model))
+    {
+    event->ignore();
+    return;
+    }
+
+  // Close all the windows that are open
+  QApplication::closeAllWindows();
+
+  // Unload all images (this causes the associations to be saved)
+  m_Model->GetDriver()->Quit();
+
+  // Exit the application
+  QCoreApplication::exit();
+}
+
+void MainImageWindow::on_actionQuit_triggered()
+{ 
+  // Close the main window
+  this->close();
+}
+
+void MainImageWindow::on_actionLoad_from_Image_triggered()
+{
+  // Prompt for unsaved changes
+  if(!SaveModifiedLayersDialog::PromptForUnsavedSegmentationChanges(m_Model))
+    return;
+
+  // Create a model for IO
+  SmartPtr<LoadSegmentationImageDelegate> delegate = LoadSegmentationImageDelegate::New();
+  delegate->Initialize(m_Model->GetDriver());
+
+  SmartPtr<ImageIOWizardModel> model = ImageIOWizardModel::New();
+  model->InitializeForLoad(m_Model, delegate, "LabelImage", "Segmentation Image");
+
+  // Execute the IO wizard
+  ImageIOWizard wiz(this);
+  wiz.SetModel(model);
+  wiz.exec();
+}
+
+
+void MainImageWindow::on_actionImage_Contrast_triggered()
+{
+  // Go to the contrast page in the dialog
+  m_LayerInspector->SetPageToContrastAdjustment();
+
+  // Show the dialog
+  RaiseDialog(m_LayerInspector);
+}
+
+void MainImageWindow::on_actionColor_Map_Editor_triggered()
+{
+  // Go to the contrast page in the dialog
+  m_LayerInspector->SetPageToContrastAdjustment();
+
+  // Show the dialog
+  RaiseDialog(m_LayerInspector);
+}
+
+void MainImageWindow::on_actionImage_Information_triggered()
+{
+  // Go to the contrast page in the dialog
+  m_LayerInspector->SetPageToImageInfo();
+
+  // Show the dialog
+  RaiseDialog(m_LayerInspector);
+}
+
+void MainImageWindow::on_actionLabel_Editor_triggered()
+{
+  // Execute the label editor
+  RaiseDialog(m_LabelEditor);
+}
+
+void MainImageWindow::OpenSnakeWizard()
+{
+  // Initialize the snake wizard
+  this->m_SnakeWizard->Initialize();
+
+  // Remember the size of the window before the right dock was shown
+  m_SizeWithoutRightDock = this->size();
+
+  // Make the dock containing the wizard visible
+  m_DockRight->setVisible(true);
+}
+
+void MainImageWindow::AdjustMarginsForDocks()
+{
+  // Get the current margins
+  QMargins margin = ui->centralwidget->layout()->contentsMargins();
+  QMargins mld = m_DockLeft->widget()->layout()->contentsMargins();
+  QMargins mrd = m_DockRight->widget()->layout()->contentsMargins();
+
+  // Whether each of the docks is attached
+  bool leftDockAtLeft =
+      (dockWidgetArea(m_DockLeft) == Qt::LeftDockWidgetArea &&
+       !m_DockLeft->isWindow() &&
+       m_DockLeft->isVisible());
+
+  bool rightDockAtRight =
+      (dockWidgetArea(m_DockRight) == Qt::RightDockWidgetArea &&
+       !m_DockRight->isWindow() &&
+       m_DockRight->isVisible());
+
+  margin.setLeft(leftDockAtLeft ? 0 : 4);
+  margin.setRight(rightDockAtRight ? 0 : 4);
+  ui->centralwidget->layout()->setContentsMargins(margin);
+
+  mld.setRight(leftDockAtLeft ? 0 : 5);
+  m_DockLeft->widget()->layout()->setContentsMargins(mld);
+
+  mrd.setLeft(rightDockAtRight ? 0 : 5);
+  m_DockRight->widget()->layout()->setContentsMargins(mrd);
+
+}
+
+void MainImageWindow::dragEnterEvent(QDragEnterEvent *event)
+{
+  const QMimeData *md = event->mimeData();
+  if(md->hasUrls() && md->urls().size() == 1)
+    {
+    QUrl url = md->urls().first();
+    if(url.isLocalFile())
+      {
+      event->setDropAction(Qt::CopyAction);
+      event->accept();
+      }
+    }
+}
+
+void MainImageWindow::LoadDroppedFile(QString file)
+{
+  // Check if the dropped file is a project
+  if(m_Model->GetDriver()->IsProjectFile(to_utf8(file).c_str()))
+    {
+    // For the time being, the feature of opening the workspace in a new
+    // window is not implemented. Instead, we just prompt the user for
+    // unsaved changes.
+    if(!SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model))
+      return;
+
+    // Load the project
+    LoadProject(file);
+    }
+
+  else
+    {
+    if(m_Model->GetDriver()->IsMainImageLoaded())
+      {
+      // If an image is already loaded, we show the dialog
+      m_DropDialog->SetDroppedFilename(file);
+      m_DropDialog->setModal(true);
+      RaiseDialog(m_DropDialog);
+      }
+    else
+      {
+      // Otherwise, attempt to load the image
+      this->LoadMainImage(file);
+      }
+    }
+}
+
+void MainImageWindow::dropEvent(QDropEvent *event)
+{
+  QString file = event->mimeData()->urls().first().toLocalFile();
+  LoadDroppedFile(file);
+  event->acceptProposedAction();
+}
+
+QActionGroup *MainImageWindow::GetMainToolActionGroup()
+{
+  return ui->actionCrosshair->actionGroup();
+}
+
+QActionGroup *MainImageWindow::Get3DToolActionGroup()
+{
+  return ui->action3DCrosshair->actionGroup();
+}
+
+LayerInspectorDialog *MainImageWindow::GetLayerInspector()
+{
+  return m_LayerInspector;
+}
+
+void MainImageWindow::LoadMainImage(const QString &file)
+{
+  // Prompt for unsaved changes
+  if(!SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model))
+    return;
+
+  // Try loading the image
+  try
+    {
+    // Change cursor for this operation
+    QtCursorOverride c(Qt::WaitCursor);
+    IRISWarningList warnings;
+    SmartPtr<LoadMainImageDelegate> del = LoadMainImageDelegate::New();
+    del->Initialize(m_Model->GetDriver());
+    m_Model->GetDriver()->LoadImageViaDelegate(file.toUtf8().constData(), del, warnings);
+    }
+  catch(exception &exc)
+    {
+    ReportNonLethalException(this, exc, "Image IO Error",
+                             QString("Failed to load image %1").arg(file));
+    }
+}
+
+void MainImageWindow::LoadRecentActionTriggered()
+{
+  // Get the filename that wants to be loaded
+  QAction *action = qobject_cast<QAction *>(sender());
+  QString file = action->text();
+  LoadMainImage(file);
+}
+
+void MainImageWindow::LoadProject(const QString &file)
+{
+  // Try loading the image
+  try
+    {
+    // Change cursor for this operation
+    QtCursorOverride c(Qt::WaitCursor);
+    IRISWarningList warnings;
+
+    // Load the project
+    m_Model->GetDriver()->OpenProject(to_utf8(file), warnings);
+    }
+  catch(exception &exc)
+    {
+    ReportNonLethalException(this, exc, "Error Opening Project",
+                             QString("Failed to open project %1").arg(file));
+  }
+}
+
+void MainImageWindow::onAnimationTimeout()
+{
+  if(m_Model)
+    m_Model->AnimateLayerComponents();
+}
+
+void MainImageWindow::LoadRecentProjectActionTriggered()
+{
+  // Check for unsaved changes before loading new data
+  if(!SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model))
+    return;
+
+  // Get the filename that wants to be loaded
+  QAction *action = qobject_cast<QAction *>(sender());
+  QString file = action->text();
+  LoadProject(file);
+}
+
+
+void MainImageWindow::onSnakeWizardFinished()
+{
+  // Make the dock containing the wizard visible
+  m_DockRight->setVisible(false);
+
+  // TODO: this way of handling the size of the main window after the right
+  // dock is hidden is rudimentary. I should learn how to use sizePolicy and
+  // sizeHint fields more effectively.
+
+  // Return to previous size
+  this->layout()->activate();
+  resize(m_SizeWithoutRightDock.width(), m_SizeWithoutRightDock.height());
+}
+
+void MainImageWindow::on_actionUnload_All_triggered()
+{
+  // Prompt for unsaved changes
+  if(!SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model))
+    return;
+
+  // Unload the main image
+  m_Model->GetDriver()->UnloadMainImage();
+}
+
+void MainImageWindow::on_actionReorient_Image_triggered()
+{
+  // Show the reorientation dialog
+  RaiseDialog(m_ReorientImageDialog);
+}
+
+void MainImageWindow::on_actionZoomToFitInAllViews_triggered()
+{
+  // Reset the common zoom factor
+  m_Model->GetSliceCoordinator()->ResetViewToFitInAllWindows();
+}
+
+void MainImageWindow::on_actionCenter_on_Cursor_triggered()
+{
+  m_Model->GetSliceCoordinator()->CenterViewOnCursorInAllWindows();
+}
+
+void MainImageWindow::on_actionZoom_to_100_triggered()
+{
+  m_Model->GetSliceCoordinator()->SetZoomPercentageInAllWindows(1);
+}
+
+void MainImageWindow::on_actionZoom_to_200_triggered()
+{
+  m_Model->GetSliceCoordinator()->SetZoomPercentageInAllWindows(2);
+}
+
+void MainImageWindow::on_actionZoom_to_400_triggered()
+{
+  m_Model->GetSliceCoordinator()->SetZoomPercentageInAllWindows(4);
+}
+
+
+void MainImageWindow::on_actionUndo_triggered()
+{
+  m_Model->GetDriver()->Undo();
+}
+
+void MainImageWindow::on_actionRedo_triggered()
+{
+  m_Model->GetDriver()->Redo();
+}
+
+#include <QKeyEvent>
+bool MainImageWindow::event(QEvent *event)
+{
+    /*
+  if(dynamic_cast<QKeyEvent *>(event))
+    {
+    QKeyEvent *kevent = dynamic_cast<QKeyEvent *>(event);
+    std::cout << "KEY event: " << kevent->text().toStdString() << std::endl;
+    std::cout << "  "
+    std::cout << "MODIFIERS: " << (int) kevent->modifiers() << std::endl;
+    }
+    */
+  return QWidget::event(event);
+}
+
+void MainImageWindow::on_actionOpenMain_triggered()
+{
+  // Prompt for unsaved changes
+  if(!SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model))
+    return;
+
+  // Create a model for IO
+  SmartPtr<LoadMainImageDelegate> delegate = LoadMainImageDelegate::New();
+  delegate->Initialize(m_Model->GetDriver());
+  SmartPtr<ImageIOWizardModel> model = ImageIOWizardModel::New();
+  model->InitializeForLoad(m_Model, delegate,
+                           "AnatomicImage", "Main Image");
+
+  // Execute the IO wizard
+  ImageIOWizard wiz(this);
+  wiz.SetModel(model);
+  wiz.exec();
+}
+
+void MainImageWindow::on_actionAdd_Overlay_triggered()
+{
+  SmartPtr<LoadOverlayImageDelegate> delegate = LoadOverlayImageDelegate::New();
+  delegate->Initialize(m_Model->GetDriver());
+  SmartPtr<ImageIOWizardModel> model = ImageIOWizardModel::New();
+  model->InitializeForLoad(m_Model, delegate,
+                           "AnatomicImage", "Overlay Image");
+
+  // Execute the IO wizard
+  ImageIOWizard wiz(this);
+  wiz.SetModel(model);
+  wiz.exec();
+}
+
+void MainImageWindow::ExportScreenshot(int panelIndex)
+{
+  // Generate a filename for the screenshot
+  std::string finput = m_Model->GenerateScreenshotFilename();
+
+  // Open a file browser and have the user select something
+  QString fuser = ShowSimpleSaveDialogWithHistory(
+        this, m_Model, "Snapshots",
+        "Save Snapshot - ITK-SNAP",
+        "Snapshot File:",
+        "PNG Image (*.png);;TIFF Image (*.tiff *.tif);;JPEG Image (*.jpg *.jpeg)",
+        true,
+        from_utf8(finput));
+
+  // If nothing selected, exit
+  if(fuser.length() == 0)
+    return;
+
+  // What panel is this?
+  QtAbstractOpenGLBox *target = NULL;
+  if(panelIndex == 3)
+    {
+    target = ui->panel3D->Get3DView();
+    }
+  else
+    {
+    SliceViewPanel *svp = reinterpret_cast<SliceViewPanel *>(m_ViewPanels[panelIndex]);
+    target = svp->GetSliceView();
+    }
+
+  // Call the screenshot saving method, which will execute asynchronously
+  target->SaveScreenshot(to_utf8(fuser));
+
+  // Store the last filename
+  m_Model->SetLastScreenshotFileName(to_utf8(fuser));
+}
+
+void MainImageWindow::on_actionSSAxial_triggered()
+{
+  ExportScreenshot(
+        m_Model->GetDriver()->GetDisplayWindowForAnatomicalDirection(ANATOMY_AXIAL));
+}
+
+void MainImageWindow::on_actionSSCoronal_triggered()
+{
+  ExportScreenshot(
+        m_Model->GetDriver()->GetDisplayWindowForAnatomicalDirection(ANATOMY_CORONAL));
+}
+
+void MainImageWindow::on_actionSSSagittal_triggered()
+{
+  ExportScreenshot(
+        m_Model->GetDriver()->GetDisplayWindowForAnatomicalDirection(ANATOMY_SAGITTAL));
+}
+
+
+#include "SynchronizationModel.h"
+
+void MainImageWindow::ExportScreenshotSeries(AnatomicalDirection direction)
+{
+  // Get the corresponding window
+  unsigned int iWindow =
+      m_Model->GetDriver()->GetDisplayWindowForAnatomicalDirection(direction);
+
+  // Get the corresponding image direction
+  unsigned int iImageDir =
+      m_Model->GetDriver()->GetImageDirectionForAnatomicalDirection(direction);
+
+  // Browse for the output directory
+  QString duser = QFileDialog::getExistingDirectory(
+        this,
+        "Directory where to save the screenshot series");
+
+  if(!duser.length())
+    return;
+
+  // Generate the output filename
+  const char *names[] = { "axial0001.png", "coronal0001.png", "sagittal0001.png" };
+  std::string filename = to_utf8(QDir(duser).filePath(names[direction]));
+
+  // back up cursor location
+  Vector3ui xCrossImageOld = m_Model->GetDriver()->GetCursorPosition();
+  Vector3ui xCrossImage = xCrossImageOld;
+  Vector3ui xSize = m_Model->GetDriver()->GetCurrentImageData()->GetVolumeExtents();
+  xCrossImage[iImageDir] = 0;
+
+  // Get the panel that's saving
+  SliceViewPanel *svp = reinterpret_cast<SliceViewPanel *>(m_ViewPanels[iWindow]);
+  QtAbstractOpenGLBox *target = svp->GetSliceView();
+
+  // turn sync off temporarily
+  bool sync_state = m_Model->GetSynchronizationModel()->GetSyncEnabled();
+  m_Model->GetSynchronizationModel()->SetSyncEnabled(false);
+
+  for (size_t i = 0; i < xSize[iImageDir]; ++i)
+  {
+    // Set the cursor position
+    m_Model->GetDriver()->SetCursorPosition(xCrossImage);
+
+    // Repaint the GL window and save screenshot
+    target->SaveScreenshot(filename);
+    target->updateGL();
+    // QCoreApplication::processEvents();
+
+    // Go to the next slice
+    xCrossImage[iImageDir]++;
+
+    // Generate the next filename
+    m_Model->SetLastScreenshotFileName(filename);
+    filename = m_Model->GenerateScreenshotFilename();
+  }
+
+  // recover the original cursor position
+  m_Model->GetDriver()->SetCursorPosition(xCrossImageOld);
+
+  // turn sync back on
+  m_Model->GetSynchronizationModel()->SetSyncEnabled(sync_state);
+}
+
+
+
+void MainImageWindow::on_actionSegmentationIncreaseOpacity_triggered()
+{
+  int opacity = m_Model->GetSegmentationOpacity();
+  m_Model->SetSegmentationOpacity(std::min(opacity+5, 100));
+}
+
+void MainImageWindow::on_actionSegmentationDecreaseOpacity_triggered()
+{
+  int opacity = m_Model->GetSegmentationOpacity();
+  m_Model->SetSegmentationOpacity(std::max(opacity-5, 0));
+}
+
+void MainImageWindow::on_actionSegmentationToggle_triggered()
+{
+  bool value = m_Model->GetSegmentationVisibility();
+  m_Model->SetSegmentationVisibility(!value);
+}
+
+
+void MainImageWindow::on_actionLoadLabels_triggered()
+{
+  // Ask for a filename
+  QString selection = ShowSimpleOpenDialogWithHistory(
+        this, m_Model, "LabelDescriptions",
+        "Open Label Descriptions - ITK-SNAP",
+        "Label Description File",
+        "Text Files (*.txt);; Label Files (*.label)");
+
+  // Open the labels from the selection
+  if(selection.length())
+    {
+    try
+      {
+      std::string utf = to_utf8(selection);
+      m_Model->GetDriver()->LoadLabelDescriptions(utf.c_str());
+      }
+    catch(std::exception &exc)
+      {
+      ReportNonLethalException(this, exc, "Label Description IO Error",
+                               QString("Failed to load label descriptions"));
+      }
+    }
+}
+
+void MainImageWindow::on_actionSaveLabels_triggered()
+{
+  // Ask for a filename
+  QString selection = ShowSimpleSaveDialogWithHistory(
+        this, m_Model, "LabelDescriptions",
+        "Save Label Descriptions - ITK-SNAP",
+        "Label Description File",
+        "Text Files (*.txt);; Label Files (*.label)",
+        true);
+
+  // Open the labels from the selection
+  if(selection.length())
+    {
+    try
+      {
+      std::string utf = to_utf8(selection);
+      m_Model->GetDriver()->SaveLabelDescriptions(utf.c_str());
+      }
+    catch(std::exception &exc)
+      {
+      ReportNonLethalException(this, exc, "Label Description IO Error",
+                               QString("Failed to save label descriptions"));
+      }
+    }
+}
+
+void MainImageWindow::on_actionVolumesAndStatistics_triggered()
+{
+  m_StatisticsDialog->Activate();
+}
+
+bool MainImageWindow::SaveSegmentation(bool interactive)
+{
+  return SaveImageLayer(
+        m_Model, m_Model->GetDriver()->GetCurrentImageData()->GetSegmentation(),
+        LABEL_ROLE, interactive, this);
+}
+
+void MainImageWindow::RaiseDialog(QDialog *dialog)
+{
+  dialog->show();
+  dialog->activateWindow();
+  dialog->raise();
+}
+
+void MainImageWindow::on_actionSaveSegmentation_triggered()
+{
+  SaveSegmentation(false);
+}
+
+void MainImageWindow::on_actionSaveSegmentationAs_triggered()
+{
+  SaveSegmentation(true);
+}
+
+
+void MainImageWindow::on_actionOverlayVisibilityToggleAll_triggered()
+{
+  m_Model->ToggleOverlayVisibility();
+}
+
+void MainImageWindow::on_actionOverlayVisibilityIncreaseAll_triggered()
+{
+  m_Model->AdjustOverlayOpacity(5);
+}
+
+void MainImageWindow::on_actionOverlayVisibilityDecreaseAll_triggered()
+{
+  m_Model->AdjustOverlayOpacity(-5);
+}
+
+void MainImageWindow::on_actionLayerInspector_triggered()
+{
+  // Show the dialog
+  if(m_LayerInspector->isVisible() && m_LayerInspector->isActiveWindow())
+    m_LayerInspector->advanceTab();
+  else
+    RaiseDialog(m_LayerInspector);
+}
+
+void MainImageWindow::on_actionAbout_triggered()
+{
+  // Show the about window
+  RaiseDialog(m_AboutDialog);
+}
+
+
+
+
+
+void MainImageWindow::on_actionClear_triggered()
+{
+  IRISApplication *app = m_Model->GetDriver();
+
+  // In snake mode, it is possible to clear the segmentation, but we don't
+  // need to prompt for save
+  if(app->IsSnakeModeActive())
+    {
+    app->ResetSNAPSegmentationImage();
+    }
+  else
+    {
+    // Prompt for unsaved changes
+    if(!SaveModifiedLayersDialog::PromptForUnsavedSegmentationChanges(m_Model))
+      return;
+
+    app->ResetIRISSegmentationImage();
+    }
+}
+
+void MainImageWindow::on_actionSave_as_Mesh_triggered()
+{
+  MeshExportWizard wizard(this);
+  wizard.SetModel(m_Model->GetMeshExportModel());
+  wizard.exec();
+}
+
+void MainImageWindow::on_actionSaveMain_triggered()
+{
+  // This should only happen in SNAP mode
+  assert(!m_Model->GetDriver()->IsSnakeModeActive());
+
+  // Handle this through the layer manager
+  ImageWrapperBase *wrapper =
+      m_Model->GetDriver()->GetIRISImageData()->GetMain();
+  QAction *save_action = m_LayerInspector->GetLayerSaveAction(wrapper);
+  if(save_action)
+    save_action->trigger();
+}
+
+#include "SNAPImageData.h"
+void MainImageWindow::on_actionSaveSpeed_triggered()
+{
+  // This should only happen in SNAP mode
+  assert(m_Model->GetDriver()->IsSnakeModeActive());
+
+  // Handle this through the layer manager
+  ImageWrapperBase *wrapper =
+      m_Model->GetDriver()->GetSNAPImageData()->GetSpeed();
+  QAction *save_action = m_LayerInspector->GetLayerSaveAction(wrapper);
+  if(save_action)
+    save_action->trigger();
+}
+
+void MainImageWindow::on_actionSaveLevelSet_triggered()
+{
+  // This should only happen in SNAP mode
+  assert(m_Model->GetDriver()->IsSnakeModeLevelSetActive());
+
+  // Handle this through the layer manager
+  ImageWrapperBase *wrapper =
+      m_Model->GetDriver()->GetSNAPImageData()->GetSnake();
+  QAction *save_action = m_LayerInspector->GetLayerSaveAction(wrapper);
+  if(save_action)
+    save_action->trigger();
+}
+
+void MainImageWindow::on_actionSaveMainROI_triggered()
+{
+  // This should only happen in SNAP mode
+  assert(m_Model->GetDriver()->IsSnakeModeActive());
+
+  // Handle this through the layer manager
+  ImageWrapperBase *wrapper =
+      m_Model->GetDriver()->GetSNAPImageData()->GetMain();
+  QAction *save_action = m_LayerInspector->GetLayerSaveAction(wrapper);
+  if(save_action)
+    save_action->trigger();
+}
+
+QSize MainImageWindow::sizeHint() const
+{
+  return QSize(900,700);
+}
+
+void MainImageWindow::on_actionPreferences_triggered()
+{
+  m_PreferencesDialog->ShowDialog();
+}
+
+
+void MainImageWindow::on_actionOpenWorkspace_triggered()
+{
+  // Check for unsaved changes before loading new data
+  if(!SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model))
+    return;
+
+  // Use the dialog with history - to be consistent with other parts of SNAP
+  QString file = ShowSimpleOpenDialogWithHistory(
+        this, m_Model, "Project", "Open Workspace",
+        "Workspace File", "ITK-SNAP Workspace Files (*.itksnap)");
+
+  // If user hits cancel, move on
+  if(file.isNull())
+    return;
+
+  // Make sure to get an absolute path, because the project needs that info
+  QString file_abs = QFileInfo(file).absoluteFilePath();
+
+  // Try loading the image
+  try
+    {
+    // Change cursor for this operation
+    QtCursorOverride c(Qt::WaitCursor);
+    IRISWarningList warnings;
+
+    // Load the project
+    m_Model->GetDriver()->OpenProject(to_utf8(file_abs), warnings);
+    }
+  catch(exception &exc)
+    {
+    ReportNonLethalException(this, exc, "Error Opening Project",
+                             QString("Failed to open project %1").arg(file_abs));
+    }
+}
+
+bool MainImageWindow::SaveWorkspace(bool interactive)
+{
+  // Make sure that there are no unsaved changes. This is necessary before
+  // a workspace can be saved. We disable the discard feature here because
+  // the subsequent action does not close anything. The real purpose of this
+  // dialog is to make sure each layer is assigned a name before saving the
+  // workspace
+  if(!SaveModifiedLayersDialog::PromptForUnsavedChanges(
+       m_Model, ALL_ROLES,
+       SaveModifiedLayersDialog::DiscardDisabled
+       | SaveModifiedLayersDialog::ProjectsDisabled))
+    return false;
+
+  // Use the global method
+  return ::SaveWorkspace(this, m_Model, interactive, this);
+}
+
+void MainImageWindow::on_actionSaveWorkspace_triggered()
+{
+  SaveWorkspace(false);
+}
+
+void MainImageWindow::on_actionSaveWorkspaceAs_triggered()
+{
+  SaveWorkspace(true);
+}
+
+
+void MainImageWindow::ExportSlice(AnatomicalDirection direction)
+{
+  // Generate a default filename for this slice
+  static const char *defpref[3] = {"axial", "sagittal", "coronal"};
+  char deffn[40];
+
+  // Figure out what slice it is
+  size_t iSliceImg =
+    m_Model->GetDriver()->GetImageDirectionForAnatomicalDirection(direction);
+
+  sprintf(deffn,"%s_slice_%04d.png", defpref[direction],
+    m_Model->GetDriver()->GetCursorPosition()[iSliceImg] + 1);
+
+  // Open a file browser and have the user select something
+  std::string fuser = to_utf8(ShowSimpleSaveDialogWithHistory(
+        this, m_Model, "Slices",
+        "Save Slice - ITK-SNAP",
+        "Slice Image File",
+        "PNG Image (*.png);;TIFF Image (*.tiff *.tif);;JPEG Image (*.jpg *.jpeg)",true));
+
+  if(fuser.length())
+    m_Model->GetDriver()->ExportSlice(direction, fuser.c_str());
+}
+
+void MainImageWindow::on_actionExportAxial_triggered()
+{
+  this->ExportSlice(ANATOMY_AXIAL);
+}
+
+void MainImageWindow::on_actionExportCoronal_triggered()
+{
+  this->ExportSlice(ANATOMY_CORONAL);
+}
+
+void MainImageWindow::on_actionExportSagittal_triggered()
+{
+  this->ExportSlice(ANATOMY_SAGITTAL);
+}
+
+void MainImageWindow::on_actionSSSeriesAxial_triggered()
+{
+  this->ExportScreenshotSeries(ANATOMY_AXIAL);
+}
+
+void MainImageWindow::on_actionSSSeriesCoronal_triggered()
+{
+  this->ExportScreenshotSeries(ANATOMY_CORONAL);
+}
+
+void MainImageWindow::on_actionSSSeriesSagittal_triggered()
+{
+  this->ExportScreenshotSeries(ANATOMY_SAGITTAL);
+}
+
+void MainImageWindow::on_actionForegroundLabelPrev_triggered()
+{
+  // Decrement the active label
+  m_Model->IncrementDrawingColorLabel(-1);
+}
+
+void MainImageWindow::on_actionForegroundLabelNext_triggered()
+{
+  // Increment the active label
+  m_Model->IncrementDrawingColorLabel(1);
+}
+
+void MainImageWindow::on_actionBackgroundLabelPrev_triggered()
+{
+  m_Model->IncrementDrawOverColorLabel(-1);
+}
+
+void MainImageWindow::on_actionBackgroundLabelNext_triggered()
+{
+  m_Model->IncrementDrawOverColorLabel(1);
+}
+
+void MainImageWindow::on_actionToggle_All_Annotations_triggered()
+{
+  // Toggle the overall visibility
+  m_Model->GetAppearanceSettings()->SetOverallVisibility(
+        !m_Model->GetAppearanceSettings()->GetOverallVisibility());
+}
+
+void MainImageWindow::on_actionToggle_Crosshair_triggered()
+{
+  // Toggle the crosshair visibility
+  OpenGLAppearanceElement *elt = m_Model->GetAppearanceSettings()->GetUIElement(
+        SNAPAppearanceSettings::CROSSHAIRS);
+  elt->SetVisible(!elt->GetVisible());
+}
+
+void MainImageWindow::on_actionAnnotation_Preferences_triggered()
+{
+  // Show the preferences dialog
+  m_PreferencesDialog->ShowDialog();
+  m_PreferencesDialog->GoToAppearancePage();
+}
+
+void MainImageWindow::on_actionAutoContrastGlobal_triggered()
+{
+  // This triggers the autocontrast option for all layers.
+  m_Model->AutoContrastAllLayers();
+}
+
+void MainImageWindow::on_actionResetContrastGlobal_triggered()
+{
+  // This triggers the autocontrast option for all layers.
+  m_Model->ResetContrastAllLayers();
+}
+
+void MainImageWindow::DoUpdateCheck(bool quiet)
+{
+  std::string nver;
+
+  // Check for the update
+  SystemInterface::UpdateStatus  us =
+      m_Model->GetSystemInterface()->CheckUpdate(nver, 1, 0, !quiet);
+
+  // Communicate with the user
+  if(us == SystemInterface::US_OUT_OF_DATE)
+    {
+    QMessageBox mbox(this);
+    QPushButton *downloadButton = mbox.addButton("Open Download Page", QMessageBox::ActionRole);
+    mbox.addButton("Not Now", QMessageBox::RejectRole);
+    mbox.setIcon(QMessageBox::Question);
+    mbox.setText(QString("A newer ITK-SNAP version (%1) is available.").arg(nver.c_str()));
+    mbox.setInformativeText("Do you want to download the latest version?");
+    mbox.setWindowTitle("ITK-SNAP Update Check");
+    mbox.exec();
+
+    if (mbox.clickedButton() == downloadButton)
+      {
+      QDesktopServices::openUrl(QUrl("http://www.itksnap.org/pmwiki/pmwiki.php?n=Downloads.SNAP3"));
+      }
+    }
+  else if(us == SystemInterface::US_UP_TO_DATE && !quiet)
+    {
+    QMessageBox::information(this, "ITK-SNAP Update Check",
+                             "Your version of ITK-SNAP is up to date!",
+                             QMessageBox::Ok);
+    }
+  else if(us == SystemInterface::US_CONNECTION_FAILED && !quiet)
+    {
+    QMessageBox::warning(this,
+                         "ITK-SNAP Update Check Failed",
+                         "Could not connect to server. Go to itksnap.org to check if a new"
+                         " version is available.");
+    }
+}
+
+void MainImageWindow::UpdateAutoCheck()
+{
+  // Get the update state
+  DefaultBehaviorSettings::UpdateCheckingPermission permission =
+      m_Model->GetGlobalState()->GetDefaultBehaviorSettings()->GetCheckForUpdates();
+
+  // If permission is unknown, prompt and change the setting
+  if(permission == DefaultBehaviorSettings::UPDATE_UNKNOWN)
+    {
+    if(QMessageBox::Yes == QMessageBox::question(
+         this, "Allow Automatic Update Checks?",
+         "ITK-SNAP can check for software updates automatically.\n"
+         "Do you want to enable this feature?",
+         QMessageBox::Yes, QMessageBox::No))
+      {
+      permission = DefaultBehaviorSettings::UPDATE_YES;
+      }
+    else
+      {
+      permission = DefaultBehaviorSettings::UPDATE_NO;
+      }
+    m_Model->GetGlobalState()->GetDefaultBehaviorSettings()->SetCheckForUpdates(permission);
+    }
+
+  // Execute the update check
+  if(permission == DefaultBehaviorSettings::UPDATE_YES)
+    {
+    DoUpdateCheck(true);
+    }
+}
+
+void MainImageWindow::on_actionCheck_for_Updates_triggered()
+{
+  DoUpdateCheck(false);
+}
+
+void MainImageWindow::on_actionDocumentation_Home_triggered()
+{
+  QDesktopServices::openUrl(QUrl("http://www.itksnap.org/pmwiki/pmwiki.php?n=Documentation.SNAP3"));
+}
+
+void MainImageWindow::on_actionNew_ITK_SNAP_Window_triggered()
+{
+  // Launch a new SNAP
+  std::list<std::string> args;
+  m_Model->GetSystemInterface()->LaunchChildSNAPSimple(args);
+}
+
+void MainImageWindow::on_actionUnload_All_Overlays_triggered()
+{
+  // Prompt for changes to the overlays
+  if(SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model, OVERLAY_ROLE))
+    {
+    m_Model->GetDriver()->UnloadAllOverlays();
+    }
+}
+
+void MainImageWindow::changeEvent(QEvent *)
+{
+  if(m_Model)
+    m_Model->GetSynchronizationModel()->SetCanBroadcast(this->isActiveWindow());
+}
+
+void MainImageWindow::on_actionUnload_Last_Overlay_triggered()
+{
+  // What is the last overlay?
+  ImageWrapperBase *last = m_Model->GetDriver()->GetIRISImageData()->GetLastOverlay();
+
+  if(SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model, OVERLAY_ROLE))
+    {
+    m_Model->GetDriver()->UnloadOverlay(last);
+    }
+
+}
diff --git a/GUI/Qt/Windows/MainImageWindow.h b/GUI/Qt/Windows/MainImageWindow.h
new file mode 100644
index 0000000..c43953b
--- /dev/null
+++ b/GUI/Qt/Windows/MainImageWindow.h
@@ -0,0 +1,351 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef MAINIMAGEWINDOW_H
+#define MAINIMAGEWINDOW_H
+
+#include <QMainWindow>
+#include "GlobalState.h"
+#include "SNAPCommon.h"
+
+class GenericSliceView;
+class SliceViewPanel;
+class GlobalUIModel;
+class QDockWidget;
+class SnakeWizardPanel;
+class EventBucket;
+class QModelIndex;
+class QProgressDialog;
+class AboutDialog;
+
+class LabelEditorDialog;
+class LayerInspectorDialog;
+class QtProgressReporterDelegate;
+class ReorientImageDialog;
+class DropActionDialog;
+class MainControlPanel;
+class StatisticsDialog;
+class QActionGroup;
+class PreferencesDialog;
+class ImageIOWizard;
+class ImageIOWizardModel;
+
+class QTimer;
+
+class SplashPanel;
+
+#include <QDebug>
+
+namespace Ui {
+class MainImageWindow;
+}
+
+class MainImageWindow : public QMainWindow
+{
+  Q_OBJECT
+
+public:
+  explicit MainImageWindow(QWidget *parent = 0);
+  ~MainImageWindow();
+
+  SliceViewPanel *GetSlicePanel(unsigned int i);
+
+  // Initialize with a model
+  void Initialize(GlobalUIModel *model);
+
+  // Show the window for the first time
+  void ShowFirstTime();
+
+  // Get model
+  irisGetMacro(Model, GlobalUIModel *)
+
+  // Initiate active contour segmentation
+  void OpenSnakeWizard();
+
+  // Load a drag-n-dropped file
+  void LoadDroppedFile(QString file);
+
+  // Export a screenshot from one of the panels
+  void ExportScreenshot(int panelIndex);
+
+  // Export a screenshot series from one of the panels
+  void ExportScreenshotSeries(AnatomicalDirection direction);
+
+  // Export a slice from one of the panels
+  void ExportSlice(AnatomicalDirection direction);
+
+  // Handle drag and drop
+  void dragEnterEvent(QDragEnterEvent *event);
+  void dropEvent(QDropEvent *event);
+
+  // Handle main window being closed
+  void closeEvent(QCloseEvent *);
+
+  bool event(QEvent *event);
+
+  // Get the action group for the main tool
+  QActionGroup *GetMainToolActionGroup();
+
+  // Get the action group for the 3D tool
+  QActionGroup *Get3DToolActionGroup();
+
+  // Get the layer inspector
+  LayerInspectorDialog *GetLayerInspector();
+
+  /** Check for updates (automatically at regular periods) */
+  void UpdateAutoCheck();
+
+public slots:
+
+  void LoadRecentActionTriggered();
+  void LoadRecentProjectActionTriggered();
+
+  void AdjustMarginsForDocks();
+  void onModelUpdate(const EventBucket &b);
+
+private slots:
+  void on_actionQuit_triggered();
+
+  void on_actionLoad_from_Image_triggered();
+
+  void on_actionImage_Contrast_triggered();
+
+  void on_actionLabel_Editor_triggered();
+
+  void onSnakeWizardFinished();
+
+  void on_actionUnload_All_triggered();
+
+  void on_actionReorient_Image_triggered();
+
+  void on_actionZoomToFitInAllViews_triggered();
+
+  void on_actionCenter_on_Cursor_triggered();
+
+  void on_actionUndo_triggered();
+
+  void on_actionRedo_triggered();
+
+  void on_actionOpenMain_triggered();
+
+  void on_actionAdd_Overlay_triggered();
+
+  void on_actionSSAxial_triggered();
+
+  void on_actionSSCoronal_triggered();
+
+  void on_actionSSSagittal_triggered();
+
+  void on_actionSegmentationIncreaseOpacity_triggered();
+
+  void on_actionSegmentationDecreaseOpacity_triggered();
+
+  void on_actionSegmentationToggle_triggered();
+
+  void on_actionLoadLabels_triggered();
+
+  void on_actionSaveLabels_triggered();
+
+  void on_actionVolumesAndStatistics_triggered();
+
+  void on_actionSaveSegmentation_triggered();
+
+  void on_actionSaveSegmentationAs_triggered();
+
+
+  void on_actionOverlayVisibilityToggleAll_triggered();
+
+  void on_actionOverlayVisibilityIncreaseAll_triggered();
+
+  void on_actionOverlayVisibilityDecreaseAll_triggered();
+
+  void on_actionLayerInspector_triggered();
+
+  void on_actionAbout_triggered();
+
+  void on_actionColor_Map_Editor_triggered();
+
+  void on_actionImage_Information_triggered();
+
+  void on_actionUnload_Last_Overlay_triggered();
+
+  void on_actionClear_triggered();
+
+  void on_actionSave_as_Mesh_triggered();
+
+  void on_actionSaveMain_triggered();
+
+  void on_actionSaveSpeed_triggered();
+
+  void on_actionSaveLevelSet_triggered();
+
+  void on_actionSaveMainROI_triggered();
+
+  virtual QSize sizeHint() const;
+
+  void on_actionPreferences_triggered();
+
+  void on_actionOpenWorkspace_triggered();
+
+  void on_actionSaveWorkspace_triggered();
+
+  void on_actionSaveWorkspaceAs_triggered();
+
+  void UpdateMainLayout();
+
+  // Load image without interaction (used for recent/drop action).
+  void LoadMainImage(const QString &file);
+
+  // Load project without interaction (used for recent/drop action)
+  void LoadProject(const QString &file);
+
+  void onAnimationTimeout();
+
+  void on_actionExportAxial_triggered();
+
+  void on_actionExportCoronal_triggered();
+
+  void on_actionExportSagittal_triggered();
+
+  void on_actionSSSeriesAxial_triggered();
+
+  void on_actionSSSeriesCoronal_triggered();
+
+  void on_actionSSSeriesSagittal_triggered();
+
+  void on_actionForegroundLabelPrev_triggered();
+
+  void on_actionForegroundLabelNext_triggered();
+
+  void on_actionBackgroundLabelPrev_triggered();
+
+  void on_actionBackgroundLabelNext_triggered();
+
+  void on_actionToggle_All_Annotations_triggered();
+
+  void on_actionToggle_Crosshair_triggered();
+
+  void on_actionAnnotation_Preferences_triggered();
+
+  void on_actionAutoContrastGlobal_triggered();
+
+  void on_actionResetContrastGlobal_triggered();
+
+  void on_actionZoom_to_100_triggered();
+
+  void on_actionZoom_to_200_triggered();
+
+  void on_actionZoom_to_400_triggered();
+
+  void on_actionCheck_for_Updates_triggered();
+
+  void on_actionDocumentation_Home_triggered();
+
+  void on_actionNew_ITK_SNAP_Window_triggered();
+
+  void on_actionUnload_All_Overlays_triggered();
+
+protected:
+
+  // bool eventFilter(QObject *obj, QEvent *event);
+
+  // Change event (for tracking active / non-active window)
+  virtual void changeEvent(QEvent *);
+
+private:
+
+  void UpdateRecentMenu();
+  void UpdateWindowTitle();
+  void UpdateProjectMenuItems();
+  void UpdateRecentProjectsMenu();
+
+
+  // Save the segmentation (interactively or not). Return true if save was
+  // successful
+  bool SaveSegmentation(bool interactive);
+
+  // Save the project (interactively or not)
+  bool SaveWorkspace(bool interactive);
+
+  // Raise a dialog (equivalent to calling show, raise, activateWindow)
+  void RaiseDialog(QDialog *dialog);
+
+  // Check for updates (quietly or loudly)
+  void DoUpdateCheck(bool quiet);
+
+  // Hookup check
+  void HookupShortcutToAction(const QKeySequence &ks, QAction *action);
+  void HookupSecondaryShortcutToAction(const QKeySequence &ks, QAction *action);
+
+  // For convenience, an array of the four panels (3 slice/1 3D)
+  QWidget *m_ViewPanels[4];
+
+  // Left and right docks
+  QDockWidget *m_DockLeft, *m_DockRight;
+
+  // Size before the right dock is shown
+  QSize m_SizeWithoutRightDock;
+
+  // Progress dialog
+  QProgressDialog *m_Progress;
+
+  // IRIS main toolbox (in left dock)
+  MainControlPanel *m_ControlPanel;
+
+  friend class QtScriptTest1;
+
+  // SNAP wizard panel (in right dock)
+  SnakeWizardPanel *m_SnakeWizard;
+
+  Ui::MainImageWindow *ui;
+
+  GlobalUIModel *m_Model;
+
+  LabelEditorDialog *m_LabelEditor;
+
+  LayerInspectorDialog *m_LayerInspector;
+
+  ReorientImageDialog *m_ReorientImageDialog;
+
+  DropActionDialog *m_DropDialog;
+
+  QtProgressReporterDelegate *m_ProgressReporterDelegate;
+
+  SplashPanel *m_SplashPanel;
+
+  AboutDialog *m_AboutDialog;
+
+  StatisticsDialog *m_StatisticsDialog;
+
+  PreferencesDialog *m_PreferencesDialog;
+
+  // A timer used to animate components
+  QTimer *m_AnimateTimer;
+};
+
+
+
+#endif // MAINIMAGEWINDOW_H
diff --git a/GUI/Qt/Windows/MainImageWindow.ui b/GUI/Qt/Windows/MainImageWindow.ui
new file mode 100644
index 0000000..546556c
--- /dev/null
+++ b/GUI/Qt/Windows/MainImageWindow.ui
@@ -0,0 +1,1381 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainImageWindow</class>
+ <widget class="QMainWindow" name="MainImageWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>907</width>
+    <height>700</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QVBoxLayout" name="verticalLayout">
+    <property name="spacing">
+     <number>0</number>
+    </property>
+    <property name="leftMargin">
+     <number>0</number>
+    </property>
+    <property name="topMargin">
+     <number>0</number>
+    </property>
+    <property name="rightMargin">
+     <number>0</number>
+    </property>
+    <property name="bottomMargin">
+     <number>0</number>
+    </property>
+    <item>
+     <widget class="QStackedWidget" name="stackMain">
+      <property name="currentIndex">
+       <number>0</number>
+      </property>
+      <widget class="QWidget" name="pageMain">
+       <layout class="QGridLayout" name="gridLayout_2">
+        <property name="leftMargin">
+         <number>4</number>
+        </property>
+        <property name="topMargin">
+         <number>4</number>
+        </property>
+        <property name="rightMargin">
+         <number>4</number>
+        </property>
+        <property name="bottomMargin">
+         <number>4</number>
+        </property>
+        <property name="spacing">
+         <number>4</number>
+        </property>
+        <item row="0" column="0">
+         <widget class="SliceViewPanel" name="panel0" native="true"/>
+        </item>
+        <item row="0" column="1">
+         <widget class="SliceViewPanel" name="panel1" native="true"/>
+        </item>
+        <item row="1" column="0">
+         <widget class="ViewPanel3D" name="panel3D" native="true">
+          <property name="styleSheet">
+           <string notr="true"/>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="SliceViewPanel" name="panel2" native="true"/>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="pageSplash">
+       <layout class="QVBoxLayout" name="verticalLayout_2">
+        <property name="spacing">
+         <number>0</number>
+        </property>
+        <property name="leftMargin">
+         <number>0</number>
+        </property>
+        <property name="topMargin">
+         <number>0</number>
+        </property>
+        <property name="rightMargin">
+         <number>0</number>
+        </property>
+        <property name="bottomMargin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QTabWidget" name="tabSplash">
+          <property name="styleSheet">
+           <string notr="true">QTabWidget::pane {
+	margin-top: 0px;
+	border:none;
+}
+
+QTabWidget::tab-bar {
+	border-top: 1px solid black;
+	left:20px;
+}
+
+QTabBar:tab {
+	border:none;
+	margin-left: 20px;
+	margin-top: 12px;
+	padding-left: 5px;
+	padding-right: 5px;
+	min-width: 132px;
+	color: rgb(102, 102, 102);
+}
+
+QTabBar:tab:selected {
+	font-weight:bold;
+	text-decoration: underline;
+}
+
+QTabBar:tab:hover {
+	text-decoration: underline;
+}</string>
+          </property>
+          <property name="tabPosition">
+           <enum>QTabWidget::North</enum>
+          </property>
+          <property name="currentIndex">
+           <number>0</number>
+          </property>
+          <widget class="QWidget" name="tabGettingStarted">
+           <attribute name="title">
+            <string>Getting Started</string>
+           </attribute>
+           <layout class="QVBoxLayout" name="verticalLayout_4">
+            <property name="leftMargin">
+             <number>12</number>
+            </property>
+            <property name="rightMargin">
+             <number>12</number>
+            </property>
+            <property name="bottomMargin">
+             <number>12</number>
+            </property>
+            <item>
+             <widget class="QFrame" name="frame">
+              <property name="styleSheet">
+               <string notr="true">QFrame#frame {
+	background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:0.537, y2:0.0340909, stop:0 rgba(210, 230, 230, 255), stop:1 rgba(255, 255, 255, 255));
+    border: 1px solid black;
+}
+
+QTextBrowser {
+	background-color: rgba(1,1,1,0);
+    border: none;
+}
+	
+
+</string>
+              </property>
+              <property name="frameShape">
+               <enum>QFrame::StyledPanel</enum>
+              </property>
+              <property name="frameShadow">
+               <enum>QFrame::Raised</enum>
+              </property>
+              <layout class="QGridLayout" name="gridLayout_3">
+               <item row="2" column="0" colspan="2">
+                <widget class="QTextBrowser" name="brsGettingStarted">
+                 <property name="autoFillBackground">
+                  <bool>false</bool>
+                 </property>
+                 <property name="styleSheet">
+                  <string notr="true">padding: -16px;</string>
+                 </property>
+                 <property name="frameShape">
+                  <enum>QFrame::NoFrame</enum>
+                 </property>
+                 <property name="frameShadow">
+                  <enum>QFrame::Plain</enum>
+                 </property>
+                 <property name="lineWidth">
+                  <number>0</number>
+                 </property>
+                 <property name="html">
+                  <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'.Lucida Grande UI'; font-size:13pt; font-weight:400; font-style:normal;">
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande';"><br /></p>
+<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Lucida Grande';" style=" margin-top:12px; margin-bottom:4px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Learn about the <a href="http://www.itksnap.org/pmwiki/pmwiki.php?n=Documentation.NewFeaturesVersion30"><span style=" text-decoration: underline; color:#0000ff;& [...]
+<li style=" font-family:'Lucida Grande';" style=" margin-top:0px; margin-bottom:4px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Read a <a href="http://www.itksnap.org/pmwiki/pmwiki.php?n=Documentation.UpgradingTo30"><span style=" text-decoration: underline; color:#0000ff;">quick transition guide</span></a> for Version 2 users</li>
+<li style=" font-family:'Lucida Grande';" style=" margin-top:0px; margin-bottom:4px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Download <a href="http://www.itksnap.org/pmwiki/pmwiki.php?n=Downloads.Data"><span style=" text-decoration: underline; color:#0000ff;">sample datasets</span></a></li>
+<li style=" font-family:'Lucida Grande';" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Connect to the <a href="http://www.itksnap.org/pmwiki/pmwiki.php?n=MailingLists.MailingLists"><span style=" text-decoration: underline; color:#0000ff;">ITK-SNAP community</span></a></li></ul></body></html></string>
+                 </property>
+                 <property name="openExternalLinks">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="0" colspan="2">
+                <widget class="Line" name="line">
+                 <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="0" alignment="Qt::AlignBottom">
+                <widget class="QLabel" name="label_2">
+                 <property name="autoFillBackground">
+                  <bool>false</bool>
+                 </property>
+                 <property name="styleSheet">
+                  <string notr="true">font-size:16px;
+font-weight:bold;
+color:rgb(103, 103, 103);
+</string>
+                 </property>
+                 <property name="text">
+                  <string>Getting started with ITK-SNAP Version 3</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="1" alignment="Qt::AlignRight">
+                <widget class="QLabel" name="label_3">
+                 <property name="text">
+                  <string/>
+                 </property>
+                 <property name="pixmap">
+                  <pixmap resource="../Resources/SNAPResources.qrc">:/root/logo_square_shadow.png</pixmap>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+          <widget class="QWidget" name="tabRecent">
+           <attribute name="title">
+            <string>Recent Images</string>
+           </attribute>
+           <layout class="QVBoxLayout" name="verticalLayout_3">
+            <property name="leftMargin">
+             <number>12</number>
+            </property>
+            <property name="rightMargin">
+             <number>12</number>
+            </property>
+            <property name="bottomMargin">
+             <number>12</number>
+            </property>
+            <item>
+             <widget class="RecentHistoryItemsView" name="panelRecentImages" native="true"/>
+            </item>
+           </layout>
+          </widget>
+          <widget class="QWidget" name="tabRecentWorkspaces">
+           <attribute name="title">
+            <string>Recent Workspaces</string>
+           </attribute>
+           <layout class="QVBoxLayout" name="verticalLayout_5">
+            <property name="leftMargin">
+             <number>12</number>
+            </property>
+            <property name="rightMargin">
+             <number>12</number>
+            </property>
+            <property name="bottomMargin">
+             <number>12</number>
+            </property>
+            <item>
+             <widget class="RecentHistoryItemsView" name="panelRecentWorkspaces" native="true"/>
+            </item>
+           </layout>
+          </widget>
+         </widget>
+        </item>
+        <item>
+         <widget class="QWidget" name="widget" native="true">
+          <layout class="QHBoxLayout" name="horizontalLayout">
+           <item>
+            <spacer name="horizontalSpacer">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+           <item>
+            <widget class="QPushButton" name="btnLoadMain">
+             <property name="text">
+              <string>Open Image ...</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QPushButton" name="btnLoadWorkspace">
+             <property name="text">
+              <string>Open Workspace ...</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>907</width>
+     <height>22</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menuFile">
+    <property name="title">
+     <string>File</string>
+    </property>
+    <widget class="QMenu" name="menuRecent_Images">
+     <property name="title">
+      <string>Recent Images</string>
+     </property>
+     <addaction name="actionRecent_1"/>
+     <addaction name="actionRecent_2"/>
+     <addaction name="actionRecent_3"/>
+     <addaction name="actionRecent_4"/>
+     <addaction name="actionRecent_5"/>
+    </widget>
+    <widget class="QMenu" name="menuSave_Image">
+     <property name="title">
+      <string>Save Image</string>
+     </property>
+     <addaction name="actionSaveMain"/>
+     <addaction name="separator"/>
+     <addaction name="actionSaveSpeed"/>
+     <addaction name="actionSaveLevelSet"/>
+     <addaction name="actionSaveMainROI"/>
+    </widget>
+    <widget class="QMenu" name="menuExport">
+     <property name="title">
+      <string>Export</string>
+     </property>
+     <widget class="QMenu" name="menuImage_Slice">
+      <property name="title">
+       <string>Image Slice</string>
+      </property>
+      <addaction name="actionExportAxial"/>
+      <addaction name="actionExportCoronal"/>
+      <addaction name="actionExportSagittal"/>
+     </widget>
+     <widget class="QMenu" name="menuScreenshot">
+      <property name="title">
+       <string>Screenshot</string>
+      </property>
+      <addaction name="actionSSAxial"/>
+      <addaction name="actionSSCoronal"/>
+      <addaction name="actionSSSagittal"/>
+     </widget>
+     <widget class="QMenu" name="menuScreenshot_Series">
+      <property name="title">
+       <string>Screenshot Series</string>
+      </property>
+      <addaction name="actionSSSeriesAxial"/>
+      <addaction name="actionSSSeriesCoronal"/>
+      <addaction name="actionSSSeriesSagittal"/>
+     </widget>
+     <addaction name="menuImage_Slice"/>
+     <addaction name="menuScreenshot"/>
+     <addaction name="menuScreenshot_Series"/>
+    </widget>
+    <addaction name="actionOpenMain"/>
+    <addaction name="menuRecent_Images"/>
+    <addaction name="separator"/>
+    <addaction name="menuSave_Image"/>
+    <addaction name="menuExport"/>
+    <addaction name="separator"/>
+    <addaction name="actionUnload_All"/>
+    <addaction name="separator"/>
+    <addaction name="actionNew_ITK_SNAP_Window"/>
+    <addaction name="separator"/>
+    <addaction name="actionQuit"/>
+   </widget>
+   <widget class="QMenu" name="menuSegmentation">
+    <property name="title">
+     <string>Segmentation</string>
+    </property>
+    <widget class="QMenu" name="menuAppearance">
+     <property name="title">
+      <string>Appearance</string>
+     </property>
+     <addaction name="actionSegmentationToggle"/>
+     <addaction name="separator"/>
+     <addaction name="actionSegmentationIncreaseOpacity"/>
+     <addaction name="actionSegmentationDecreaseOpacity"/>
+    </widget>
+    <addaction name="actionLoad_from_Image"/>
+    <addaction name="separator"/>
+    <addaction name="actionSaveSegmentation"/>
+    <addaction name="actionSaveSegmentationAs"/>
+    <addaction name="separator"/>
+    <addaction name="actionClear"/>
+    <addaction name="separator"/>
+    <addaction name="actionSave_as_Mesh"/>
+    <addaction name="separator"/>
+    <addaction name="actionLoadLabels"/>
+    <addaction name="actionSaveLabels"/>
+    <addaction name="separator"/>
+    <addaction name="actionVolumesAndStatistics"/>
+    <addaction name="separator"/>
+    <addaction name="menuAppearance"/>
+   </widget>
+   <widget class="QMenu" name="menuOverlay">
+    <property name="title">
+     <string>Overlay</string>
+    </property>
+    <widget class="QMenu" name="menuOverlayAppearance">
+     <property name="title">
+      <string>Appearance</string>
+     </property>
+     <addaction name="actionOverlayVisibilityToggleAll"/>
+     <addaction name="separator"/>
+     <addaction name="actionOverlayVisibilityIncreaseAll"/>
+     <addaction name="actionOverlayVisibilityDecreaseAll"/>
+    </widget>
+    <addaction name="actionAdd_Overlay"/>
+    <addaction name="separator"/>
+    <addaction name="actionUnload_Last_Overlay"/>
+    <addaction name="actionUnload_All_Overlays"/>
+    <addaction name="separator"/>
+    <addaction name="menuOverlayAppearance"/>
+   </widget>
+   <widget class="QMenu" name="menuTools">
+    <property name="title">
+     <string>Tools</string>
+    </property>
+    <widget class="QMenu" name="menuActive_Main_Tool">
+     <property name="title">
+      <string>Active Main Tool</string>
+     </property>
+     <addaction name="actionCrosshair"/>
+     <addaction name="actionZoomPan"/>
+     <addaction name="actionPolygon"/>
+     <addaction name="actionPaintbrush"/>
+     <addaction name="actionSnake"/>
+    </widget>
+    <widget class="QMenu" name="menuActive_3D_Tool">
+     <property name="title">
+      <string>Active 3D Tool</string>
+     </property>
+     <addaction name="action3DTrackball"/>
+     <addaction name="action3DCrosshair"/>
+     <addaction name="action3DScalpel"/>
+     <addaction name="action3DSpray"/>
+    </widget>
+    <widget class="QMenu" name="menuContrast">
+     <property name="title">
+      <string>Image Contrast</string>
+     </property>
+     <addaction name="actionImage_Contrast"/>
+     <addaction name="separator"/>
+     <addaction name="actionAutoContrastGlobal"/>
+     <addaction name="actionResetContrastGlobal"/>
+    </widget>
+    <addaction name="actionLayerInspector"/>
+    <addaction name="separator"/>
+    <addaction name="menuContrast"/>
+    <addaction name="actionColor_Map_Editor"/>
+    <addaction name="actionImage_Information"/>
+    <addaction name="separator"/>
+    <addaction name="menuActive_Main_Tool"/>
+    <addaction name="menuActive_3D_Tool"/>
+    <addaction name="separator"/>
+    <addaction name="actionLabel_Editor"/>
+    <addaction name="separator"/>
+    <addaction name="actionReorient_Image"/>
+    <addaction name="separator"/>
+    <addaction name="actionPreferences"/>
+   </widget>
+   <widget class="QMenu" name="menuEdit">
+    <property name="title">
+     <string>Edit</string>
+    </property>
+    <widget class="QMenu" name="menuForeground_Label">
+     <property name="title">
+      <string>Foreground Label</string>
+     </property>
+     <addaction name="actionForegroundLabelPrev"/>
+     <addaction name="actionForegroundLabelNext"/>
+    </widget>
+    <widget class="QMenu" name="menuBackground_Label">
+     <property name="title">
+      <string>Background Label</string>
+     </property>
+     <addaction name="actionBackgroundLabelPrev"/>
+     <addaction name="actionBackgroundLabelNext"/>
+    </widget>
+    <widget class="QMenu" name="menuSlice_Annotations">
+     <property name="title">
+      <string>Slice Annotations</string>
+     </property>
+     <addaction name="actionToggle_All_Annotations"/>
+     <addaction name="actionToggle_Crosshair"/>
+     <addaction name="separator"/>
+     <addaction name="actionAnnotation_Preferences"/>
+    </widget>
+    <widget class="QMenu" name="menuZoom">
+     <property name="title">
+      <string>View Zoom</string>
+     </property>
+     <addaction name="actionZoomToFitInAllViews"/>
+     <addaction name="separator"/>
+     <addaction name="actionZoom_to_100"/>
+     <addaction name="actionZoom_to_200"/>
+     <addaction name="actionZoom_to_400"/>
+     <addaction name="separator"/>
+     <addaction name="actionCenter_on_Cursor"/>
+    </widget>
+    <addaction name="actionUndo"/>
+    <addaction name="actionRedo"/>
+    <addaction name="separator"/>
+    <addaction name="menuForeground_Label"/>
+    <addaction name="menuBackground_Label"/>
+    <addaction name="separator"/>
+    <addaction name="menuSlice_Annotations"/>
+    <addaction name="separator"/>
+    <addaction name="menuZoom"/>
+   </widget>
+   <widget class="QMenu" name="menuHelp">
+    <property name="title">
+     <string>Help</string>
+    </property>
+    <addaction name="actionAbout"/>
+    <addaction name="separator"/>
+    <addaction name="actionCheck_for_Updates"/>
+    <addaction name="separator"/>
+    <addaction name="actionDocumentation_Home"/>
+   </widget>
+   <widget class="QMenu" name="menuProject">
+    <property name="title">
+     <string>Workspace</string>
+    </property>
+    <widget class="QMenu" name="menuRecentWorkspaces">
+     <property name="title">
+      <string>Recent Workspaces</string>
+     </property>
+     <addaction name="actionRecentWorkspace1"/>
+     <addaction name="actionRecentWorkspace2"/>
+     <addaction name="actionRecentWorkspace3"/>
+     <addaction name="actionRecentWorkspace4"/>
+     <addaction name="actionRecentWorkspace5"/>
+    </widget>
+    <addaction name="actionOpenWorkspace"/>
+    <addaction name="menuRecentWorkspaces"/>
+    <addaction name="separator"/>
+    <addaction name="actionSaveWorkspace"/>
+    <addaction name="actionSaveWorkspaceAs"/>
+   </widget>
+   <addaction name="menuFile"/>
+   <addaction name="menuEdit"/>
+   <addaction name="menuSegmentation"/>
+   <addaction name="menuOverlay"/>
+   <addaction name="menuProject"/>
+   <addaction name="menuTools"/>
+   <addaction name="menuHelp"/>
+  </widget>
+  <action name="actionOpenMain">
+   <property name="text">
+    <string>Open Image ...</string>
+   </property>
+   <property name="toolTip">
+    <string>Open the main anatomy image that you wish to display or segment</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+G</string>
+   </property>
+  </action>
+  <action name="actionQuit">
+   <property name="text">
+    <string>Quit</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Q</string>
+   </property>
+  </action>
+  <action name="actionLoad_from_Image">
+   <property name="text">
+    <string>Open Segmentation ...</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+O</string>
+   </property>
+  </action>
+  <action name="actionSaveMain">
+   <property name="text">
+    <string>Main Image ...</string>
+   </property>
+   <property name="toolTip">
+    <string>Main Image</string>
+   </property>
+  </action>
+  <action name="actionSaveSpeed">
+   <property name="text">
+    <string>Speed Image ...</string>
+   </property>
+   <property name="toolTip">
+    <string>Save the Speed Image in Active Contour Mode</string>
+   </property>
+  </action>
+  <action name="actionSaveLevelSet">
+   <property name="text">
+    <string>Level Set Image ...</string>
+   </property>
+   <property name="toolTip">
+    <string>Save level set image in active snake mode</string>
+   </property>
+  </action>
+  <action name="actionSaveMainROI">
+   <property name="text">
+    <string>Main Image (Region of Interest) ...</string>
+   </property>
+   <property name="toolTip">
+    <string>Save the region of interest selected for active contour segmentation</string>
+   </property>
+  </action>
+  <action name="actionRecent_1">
+   <property name="text">
+    <string>Recent 1</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+1</string>
+   </property>
+  </action>
+  <action name="actionRecent_2">
+   <property name="text">
+    <string>Recent 2</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+2</string>
+   </property>
+  </action>
+  <action name="actionRecent_3">
+   <property name="text">
+    <string>Recent 3</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+3</string>
+   </property>
+  </action>
+  <action name="actionRecent_4">
+   <property name="text">
+    <string>Recent 4</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+4</string>
+   </property>
+  </action>
+  <action name="actionRecent_5">
+   <property name="text">
+    <string>Recent 5</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+5</string>
+   </property>
+  </action>
+  <action name="actionExportAxial">
+   <property name="text">
+    <string>Axial</string>
+   </property>
+   <property name="toolTip">
+    <string>Export axial image slice as an image</string>
+   </property>
+  </action>
+  <action name="actionExportCoronal">
+   <property name="text">
+    <string>Coronal</string>
+   </property>
+   <property name="toolTip">
+    <string>Export coronal image slice as an image</string>
+   </property>
+  </action>
+  <action name="actionExportSagittal">
+   <property name="text">
+    <string>Sagittal</string>
+   </property>
+   <property name="toolTip">
+    <string>Export sagittal image slice as an image</string>
+   </property>
+  </action>
+  <action name="actionUnload_All">
+   <property name="text">
+    <string>Unload All Images</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+U</string>
+   </property>
+  </action>
+  <action name="actionClear">
+   <property name="text">
+    <string>Unload Segmentation</string>
+   </property>
+  </action>
+  <action name="actionAdd_Overlay">
+   <property name="text">
+    <string>Add Overlay ...</string>
+   </property>
+   <property name="toolTip">
+    <string>Load an image to overlay over the images currently loaded into SNAP</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+G</string>
+   </property>
+  </action>
+  <action name="actionImage_Contrast">
+   <property name="text">
+    <string>Contrast Adjustment...</string>
+   </property>
+   <property name="toolTip">
+    <string>Adjust image contrast</string>
+   </property>
+  </action>
+  <action name="actionLabel_Editor">
+   <property name="text">
+    <string>Label Editor ...</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+L</string>
+   </property>
+  </action>
+  <action name="actionReorient_Image">
+   <property name="text">
+    <string>Reorient Image...</string>
+   </property>
+  </action>
+  <action name="actionZoomToFitInAllViews">
+   <property name="text">
+    <string>Zoom to Fit in All Views</string>
+   </property>
+   <property name="toolTip">
+    <string>Reset the zoom factor in all views to fit</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+F</string>
+   </property>
+  </action>
+  <action name="actionCenter_on_Cursor">
+   <property name="text">
+    <string>Center All Views on Cursor</string>
+   </property>
+   <property name="toolTip">
+    <string>Center each slice view on the cursor position</string>
+   </property>
+   <property name="shortcut">
+    <string>C</string>
+   </property>
+  </action>
+  <action name="actionUndo">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/undo_22.png</normaloff>:/root/undo_22.png</iconset>
+   </property>
+   <property name="text">
+    <string>Undo</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Z</string>
+   </property>
+  </action>
+  <action name="actionRedo">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/redo_22.png</normaloff>:/root/redo_22.png</iconset>
+   </property>
+   <property name="text">
+    <string>Redo</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+Z</string>
+   </property>
+  </action>
+  <action name="actionRecentWorkspace_1">
+   <property name="text">
+    <string>Recent 1</string>
+   </property>
+  </action>
+  <action name="actionRecentWorkspace_2">
+   <property name="text">
+    <string>Recent 2</string>
+   </property>
+  </action>
+  <action name="actionRecentWorkspace_3">
+   <property name="text">
+    <string>Recent 3</string>
+   </property>
+  </action>
+  <action name="actionRecentWorkspace_4">
+   <property name="text">
+    <string>Recent 4</string>
+   </property>
+  </action>
+  <action name="actionSSAxial">
+   <property name="text">
+    <string>Axial</string>
+   </property>
+   <property name="toolTip">
+    <string>Export a screenshot of the axial view as an image</string>
+   </property>
+  </action>
+  <action name="actionSSCoronal">
+   <property name="text">
+    <string>Coronal</string>
+   </property>
+   <property name="toolTip">
+    <string>Export a screenshot of the axial view as an image</string>
+   </property>
+  </action>
+  <action name="actionSSSagittal">
+   <property name="text">
+    <string>Sagittal</string>
+   </property>
+   <property name="toolTip">
+    <string>Export a screenshot of the axial view as an image</string>
+   </property>
+  </action>
+  <action name="actionSaveSegmentationAs">
+   <property name="text">
+    <string>Save as...</string>
+   </property>
+  </action>
+  <action name="actionSave_as_Mesh">
+   <property name="text">
+    <string>Export as Surface Mesh...</string>
+   </property>
+  </action>
+  <action name="actionLoadLabels">
+   <property name="text">
+    <string>Import Label Descriptions...</string>
+   </property>
+  </action>
+  <action name="actionSaveLabels">
+   <property name="text">
+    <string>Export Label Descriptions...</string>
+   </property>
+  </action>
+  <action name="actionVolumesAndStatistics">
+   <property name="text">
+    <string>Volumes and Statistics...</string>
+   </property>
+  </action>
+  <action name="actionSegmentationToggle">
+   <property name="checked">
+    <bool>false</bool>
+   </property>
+   <property name="text">
+    <string>Toggle Visibility</string>
+   </property>
+   <property name="shortcut">
+    <string>S</string>
+   </property>
+  </action>
+  <action name="actionSegmentationIncreaseOpacity">
+   <property name="text">
+    <string>Increase Opacity</string>
+   </property>
+   <property name="shortcut">
+    <string>D</string>
+   </property>
+  </action>
+  <action name="actionSegmentationDecreaseOpacity">
+   <property name="text">
+    <string>Decrease Opacity</string>
+   </property>
+   <property name="shortcut">
+    <string>A</string>
+   </property>
+  </action>
+  <action name="actionColor_Map_Editor">
+   <property name="text">
+    <string>Color Map Editor...</string>
+   </property>
+  </action>
+  <action name="actionImage_Information">
+   <property name="text">
+    <string>Image Information...</string>
+   </property>
+  </action>
+  <action name="actionUnload_Last_Overlay">
+   <property name="text">
+    <string>Remove Last Overlay</string>
+   </property>
+   <property name="toolTip">
+    <string>Remove the last overlay that was loaded from the workspace</string>
+   </property>
+  </action>
+  <action name="actionUnload_All_Overlays">
+   <property name="text">
+    <string>Remove All Overlays</string>
+   </property>
+   <property name="toolTip">
+    <string>Remove all overlays from the current workspace. Only the main image will remain open.</string>
+   </property>
+  </action>
+  <action name="actionLayerInspector">
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/layer_Inspector_16.png</normaloff>:/root/layer_Inspector_16.png</iconset>
+   </property>
+   <property name="text">
+    <string>Layer Inspector...</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+I</string>
+   </property>
+  </action>
+  <action name="actionCrosshair">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/crosshair.gif</normaloff>:/root/crosshair.gif</iconset>
+   </property>
+   <property name="text">
+    <string>Crosshair Tool</string>
+   </property>
+   <property name="toolTip">
+    <string><html><head/><body><p><span style=" font-weight:600;">Crosshair Mode</span></p><p>Click and drag the left mouse button to move the 3D cursor in the image. Use the right mouse button to zoom, and the middle mouse button to pan.</p></body></html></string>
+   </property>
+   <property name="shortcut">
+    <string>1</string>
+   </property>
+  </action>
+  <action name="actionZoomPan">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/zoom.gif</normaloff>:/root/zoom.gif</iconset>
+   </property>
+   <property name="text">
+    <string>Zoom/Pan Mode</string>
+   </property>
+   <property name="toolTip">
+    <string><html><head/><body><p><span style=" font-weight:600;">Zoom/Pan Mode</span></p><p>Click and drag the left mouse button to pan the slice views. Use the right mouse button to zoom in and out.</p></body></html></string>
+   </property>
+   <property name="shortcut">
+    <string>2</string>
+   </property>
+  </action>
+  <action name="actionPolygon">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/poly.gif</normaloff>:/root/poly.gif</iconset>
+   </property>
+   <property name="text">
+    <string>Polygon Drawing Mode</string>
+   </property>
+   <property name="toolTip">
+    <string><html><head/><body><p><span style=" font-weight:600;">Polygon Mode</span></p><p>Primary tool for manual segmentation. Use the mouse to draw polygons on the 2D slice views, then edit the polygons and fill them with segmentation labels.</p></body></html></string>
+   </property>
+   <property name="shortcut">
+    <string>3</string>
+   </property>
+  </action>
+  <action name="actionPaintbrush">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/paintbrush.gif</normaloff>:/root/paintbrush.gif</iconset>
+   </property>
+   <property name="text">
+    <string>Paintbrush Mode</string>
+   </property>
+   <property name="toolTip">
+    <string><html><head/><body><p><span style=" font-weight:600;">Paintbrush Mode</span></p><p>A tool for manual editing of segmentations. Hold the left mouse button and drag the mouse to draw with the currently selected label using one of the available brush shapes. Use the right mouse button to draw wuth the background label.</p></body></html></string>
+   </property>
+   <property name="shortcut">
+    <string>4</string>
+   </property>
+  </action>
+  <action name="actionSnake">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/snake.gif</normaloff>:/root/snake.gif</iconset>
+   </property>
+   <property name="text">
+    <string>Active Contour Segmentation Mode</string>
+   </property>
+   <property name="toolTip">
+    <string><html><head/><body><p><span style=" font-weight:600;">Active Contour Segmentation (Snake) Mode</span></p><p>Select a region of interest (ROI) for automatic segmentation. Use the mouse to move the boundaries of the ROI, then click the &quot;Segment 3D&quot; button to begin automatic segmentation.</p></body></html></string>
+   </property>
+   <property name="shortcut">
+    <string>5</string>
+   </property>
+  </action>
+  <action name="actionSaveSegmentation">
+   <property name="text">
+    <string>Save</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+S</string>
+   </property>
+  </action>
+  <action name="action3DTrackball">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/rotate3d.gif</normaloff>:/root/rotate3d.gif</iconset>
+   </property>
+   <property name="text">
+    <string>3D Trackball Tool</string>
+   </property>
+   <property name="toolTip">
+    <string><html><head/><body><p><span style=" font-weight:600;">3D Trackball Mode</span></p><p>Click and drag the left mouse button to rotate the 3D scene. Use the right mouse button to zoom, and the middle mouse button to pan the 3D scene.</p></body></html></string>
+   </property>
+  </action>
+  <action name="action3DCrosshair">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/crosshair3D.gif</normaloff>:/root/crosshair3D.gif</iconset>
+   </property>
+   <property name="text">
+    <string>3D Crosshair Tool</string>
+   </property>
+   <property name="toolTip">
+    <string><html><head/><body><p><span style=" font-weight:600;">3D Crosshair Mode</span></p><p>Click the left button over a segmentation surface in the 3D window to position the 3D cursor at that position.</p></body></html></string>
+   </property>
+  </action>
+  <action name="action3DScalpel">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/scalpel.gif</normaloff>:/root/scalpel.gif</iconset>
+   </property>
+   <property name="text">
+    <string>3D Scalpel Tool</string>
+   </property>
+   <property name="toolTip">
+    <string><html><head/><body><p><span style=" font-weight:600;">3D Scalpel Mode</span></p><p>Left-click on two points in the 3D window to define a cutplane. Then click 'Accept' to relabel the segmentation on one side of the cutplane.</p></body></html></string>
+   </property>
+  </action>
+  <action name="action3DSpray">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="../Resources/SNAPResources.qrc">
+     <normaloff>:/root/spray.gif</normaloff>:/root/spray.gif</iconset>
+   </property>
+   <property name="text">
+    <string>3D Spray Paint Tool</string>
+   </property>
+   <property name="toolTip">
+    <string><html><head/><body><p><span style=" font-weight:600;">Spray Paint Mode</span></p><p>Click and hold the left mouse button to relabel voxels on the boundaries of segmented objects.</p></body></html></string>
+   </property>
+  </action>
+  <action name="actionOverlayVisibilityToggleAll">
+   <property name="text">
+    <string>Toggle Visibility (All)</string>
+   </property>
+   <property name="toolTip">
+    <string>Toggle Visibility (All)</string>
+   </property>
+   <property name="shortcut">
+    <string>W</string>
+   </property>
+  </action>
+  <action name="actionOverlayVisibilityIncreaseAll">
+   <property name="text">
+    <string>Increase Opacity (All)</string>
+   </property>
+   <property name="shortcut">
+    <string>E</string>
+   </property>
+  </action>
+  <action name="actionOverlayVisibilityDecreaseAll">
+   <property name="text">
+    <string>Decrease Opacity (All)</string>
+   </property>
+   <property name="shortcut">
+    <string>Q</string>
+   </property>
+  </action>
+  <action name="actionAbout">
+   <property name="text">
+    <string>About ITK-SNAP</string>
+   </property>
+   <property name="menuRole">
+    <enum>QAction::AboutRole</enum>
+   </property>
+  </action>
+  <action name="actionPreferences">
+   <property name="text">
+    <string>Preferences ...</string>
+   </property>
+  </action>
+  <action name="actionSaveWorkspace">
+   <property name="text">
+    <string>Save Workspace ...</string>
+   </property>
+   <property name="toolTip">
+    <string>Save the current workspace, including open image layers and associated settings and parameters</string>
+   </property>
+  </action>
+  <action name="actionOpenWorkspace">
+   <property name="text">
+    <string>Open Workspace ...</string>
+   </property>
+   <property name="toolTip">
+    <string>Open a workspace containing multiple image layers and associated settings and parameters</string>
+   </property>
+  </action>
+  <action name="actionSaveWorkspaceAs">
+   <property name="text">
+    <string>Save Workspace As ...</string>
+   </property>
+   <property name="toolTip">
+    <string>Save the current workspace, including open image layers and associated settings and parameters</string>
+   </property>
+  </action>
+  <action name="actionRecentWorkspace_5">
+   <property name="text">
+    <string>Recent 5</string>
+   </property>
+  </action>
+  <action name="actionRecentWorkspace1">
+   <property name="text">
+    <string>Recent 1</string>
+   </property>
+  </action>
+  <action name="actionRecentWorkspace2">
+   <property name="text">
+    <string>Recent 2</string>
+   </property>
+  </action>
+  <action name="actionRecentWorkspace3">
+   <property name="text">
+    <string>Recent 3</string>
+   </property>
+  </action>
+  <action name="actionRecentWorkspace4">
+   <property name="text">
+    <string>Recent 4</string>
+   </property>
+  </action>
+  <action name="actionRecentWorkspace5">
+   <property name="text">
+    <string>Recent 5</string>
+   </property>
+  </action>
+  <action name="actionOpen">
+   <property name="text">
+    <string>Open ...</string>
+   </property>
+  </action>
+  <action name="actionSave">
+   <property name="text">
+    <string>Save ...</string>
+   </property>
+  </action>
+  <action name="actionReset">
+   <property name="text">
+    <string>Reset to Defaults</string>
+   </property>
+  </action>
+  <action name="actionSSSeriesAxial">
+   <property name="text">
+    <string>Axial</string>
+   </property>
+   <property name="toolTip">
+    <string>Iterate through all the slices in the axial view and save as a series of PNG image files.</string>
+   </property>
+  </action>
+  <action name="actionSSSeriesCoronal">
+   <property name="text">
+    <string>Coronal</string>
+   </property>
+   <property name="toolTip">
+    <string>Iterate through all the slices in the coronal view and save as a series of PNG image files.</string>
+   </property>
+  </action>
+  <action name="actionSSSeriesSagittal">
+   <property name="text">
+    <string>Sagittal</string>
+   </property>
+   <property name="toolTip">
+    <string>Iterate through all the slices in the sagittal view and save as a series of PNG image files.</string>
+   </property>
+  </action>
+  <action name="actionForegroundLabelPrev">
+   <property name="text">
+    <string>Previous</string>
+   </property>
+   <property name="shortcut">
+    <string><</string>
+   </property>
+  </action>
+  <action name="actionForegroundLabelNext">
+   <property name="text">
+    <string>Next</string>
+   </property>
+   <property name="shortcut">
+    <string>></string>
+   </property>
+  </action>
+  <action name="actionBackgroundLabelPrev">
+   <property name="text">
+    <string>Previous</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+,</string>
+   </property>
+  </action>
+  <action name="actionBackgroundLabelNext">
+   <property name="text">
+    <string>Next</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+.</string>
+   </property>
+  </action>
+  <action name="actionToggle_All_Annotations">
+   <property name="text">
+    <string>Toggle All Annotations</string>
+   </property>
+   <property name="shortcut">
+    <string>X</string>
+   </property>
+  </action>
+  <action name="actionToggle_Crosshair">
+   <property name="text">
+    <string>Toggle Crosshair</string>
+   </property>
+   <property name="shortcut">
+    <string>Shift+X</string>
+   </property>
+  </action>
+  <action name="actionAnnotation_Preferences">
+   <property name="text">
+    <string>Annotation Preferences...</string>
+   </property>
+  </action>
+  <action name="actionAutoContrastGlobal">
+   <property name="text">
+    <string>Auto-Adjust Contrast (all layers)</string>
+   </property>
+   <property name="toolTip">
+    <string>Automatically adjust contrast in the main image and all overlays</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+J</string>
+   </property>
+  </action>
+  <action name="actionResetContrastGlobal">
+   <property name="text">
+    <string>Reset Contrast (all layers)</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+J</string>
+   </property>
+  </action>
+  <action name="actionHa">
+   <property name="text">
+    <string>Ha</string>
+   </property>
+  </action>
+  <action name="actionZoom_to_100">
+   <property name="text">
+    <string>Zoom to Actual Size x1</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+F, 1</string>
+   </property>
+  </action>
+  <action name="actionZoom_to_200">
+   <property name="text">
+    <string>Zoom to Actual Size x2</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+F, 2</string>
+   </property>
+  </action>
+  <action name="actionZoom_to_400">
+   <property name="text">
+    <string>Zoom to Actual Size x4</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+F, 4</string>
+   </property>
+  </action>
+  <action name="actionCheck_for_Updates">
+   <property name="text">
+    <string>Check for Software Updates ...</string>
+   </property>
+  </action>
+  <action name="actionDocumentation_Home">
+   <property name="text">
+    <string>Documentation Home ...</string>
+   </property>
+  </action>
+  <action name="actionNew_ITK_SNAP_Window">
+   <property name="text">
+    <string>New ITK-SNAP Window</string>
+   </property>
+  </action>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>SliceViewPanel</class>
+   <extends>QWidget</extends>
+   <header>SliceViewPanel.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>ViewPanel3D</class>
+   <extends>QWidget</extends>
+   <header>ViewPanel3D.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>RecentHistoryItemsView</class>
+   <extends>QWidget</extends>
+   <header location="global">RecentHistoryItemsView.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>brsGettingStarted</tabstop>
+  <tabstop>btnLoadMain</tabstop>
+  <tabstop>btnLoadWorkspace</tabstop>
+  <tabstop>tabSplash</tabstop>
+ </tabstops>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections/>
+ <designerdata>
+  <property name="gridDeltaX">
+   <number>10</number>
+  </property>
+  <property name="gridDeltaY">
+   <number>10</number>
+  </property>
+  <property name="gridSnapX">
+   <bool>true</bool>
+  </property>
+  <property name="gridSnapY">
+   <bool>true</bool>
+  </property>
+  <property name="gridVisible">
+   <bool>true</bool>
+  </property>
+ </designerdata>
+</ui>
diff --git a/GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.cxx b/GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.cxx
new file mode 100644
index 0000000..ee64fdf
--- /dev/null
+++ b/GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.cxx
@@ -0,0 +1,104 @@
+#include "MeshExportBrowsePage.h"
+#include "ui_MeshExportBrowsePage.h"
+
+#include "MeshExportModel.h"
+#include "QtComboBoxCoupling.h"
+#include "QtLineEditCoupling.h"
+#include <QFileInfo>
+#include <QMenu>
+#include <QFileDialog>
+#include "SNAPQtCommon.h"
+#include <QtCursorOverride.h>
+
+Q_DECLARE_METATYPE(GuidedMeshIO::FileFormat)
+
+MeshExportBrowsePage::MeshExportBrowsePage(QWidget *parent) :
+  QWizardPage(parent),
+  ui(new Ui::MeshExportBrowsePage)
+{
+  ui->setupUi(this);
+
+  // Connect changes to the filename
+  QObject::connect(ui->filePanel, SIGNAL(absoluteFilenameChanged(QString)),
+                   this, SIGNAL(completeChanged()));
+}
+
+MeshExportBrowsePage::~MeshExportBrowsePage()
+{
+  delete ui;
+}
+
+void MeshExportBrowsePage::SetModel(MeshExportModel *model)
+{
+  // Store the model
+  m_Model = model;
+}
+
+void MeshExportBrowsePage::initializePage()
+{
+  // Filter string (generate by hand...)
+  QString filter;
+
+  // Get the domain
+  MeshExportModel::FileFormat dummy;
+  MeshExportModel::FileFormatDomain domain;
+  m_Model->GetExportFormatModel()->GetValueAndDomain(dummy, &domain);
+
+  if(m_Model->GetSaveMode() == MeshExportModel::SAVE_SCENE)
+    {
+    filter = QString("%1 (.vtk);; %2 (.vrml)")
+        .arg(from_utf8(domain[GuidedMeshIO::FORMAT_VTK]))
+        .arg(from_utf8(domain[GuidedMeshIO::FORMAT_VRML]));
+    }
+  else
+    {
+    filter = QString("%1 (.vtk);; %2 (.stl);; %3 (.byu .y)")
+        .arg(from_utf8(domain[GuidedMeshIO::FORMAT_VTK]))
+        .arg(from_utf8(domain[GuidedMeshIO::FORMAT_STL]))
+        .arg(from_utf8(domain[GuidedMeshIO::FORMAT_BYU]));
+    }
+
+  // Create the file panel
+  ui->filePanel->initializeForSaveFile(
+        m_Model->GetParentModel(),
+        "Mesh file name:",
+        from_utf8(m_Model->GetHistoryName()),
+        filter, false,
+        QString(), from_utf8(domain[GuidedMeshIO::FORMAT_VTK]));
+}
+
+bool MeshExportBrowsePage::validatePage()
+{
+  // Change cursor until this object moves out of scope
+  QtCursorOverride curse(Qt::WaitCursor);
+
+  try
+  {
+    m_Model->SetExportFileName(to_utf8(ui->filePanel->absoluteFilename()));
+    m_Model->SetExportFormat(m_Model->GetFileFormatByName(to_utf8(ui->filePanel->activeFormat())));
+    m_Model->SaveMesh();
+    return true;
+  }
+  catch(std::exception &exc)
+  {
+    QString html_template =
+        "<tr><td width=40><img src=\":/root/%1.png\" /></td>"
+        "<td><p>%2</p></td></tr>";
+
+    QString text = QString::fromUtf8(exc.what());
+    QString head = text.section(".",0,0);
+    QString tail = text.section(".", 1);
+
+    QString html = QString("<table>%1</table>").arg(
+          QString(html_template).arg(
+            "dlg_error_32", QString("<b>%1.</b> %2").arg(head, tail)));
+
+    ui->outMessage->setText(html);
+    return false;
+  }
+}
+
+bool MeshExportBrowsePage::isComplete()
+{
+  return ui->filePanel->absoluteFilename().length() > 0;
+}
diff --git a/GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.h b/GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.h
new file mode 100644
index 0000000..4fe8eaa
--- /dev/null
+++ b/GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.h
@@ -0,0 +1,32 @@
+#ifndef MESHEXPORTBROWSEPAGE_H
+#define MESHEXPORTBROWSEPAGE_H
+
+#include <QWizardPage>
+
+namespace Ui {
+class MeshExportBrowsePage;
+}
+
+class MeshExportModel;
+
+class MeshExportBrowsePage : public QWizardPage
+{
+  Q_OBJECT
+  
+public:
+  explicit MeshExportBrowsePage(QWidget *parent = 0);
+  ~MeshExportBrowsePage();
+  
+  void SetModel(MeshExportModel *model);
+
+  virtual void initializePage();
+  virtual bool validatePage();
+  virtual bool isComplete();
+
+private:
+  Ui::MeshExportBrowsePage *ui;
+
+  MeshExportModel *m_Model;
+};
+
+#endif // MESHEXPORTBROWSEPAGE_H
diff --git a/GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.ui b/GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.ui
new file mode 100644
index 0000000..88bce18
--- /dev/null
+++ b/GUI/Qt/Windows/MeshExportWizard/MeshExportBrowsePage.ui
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MeshExportBrowsePage</class>
+ <widget class="QWizardPage" name="MeshExportBrowsePage">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>WizardPage</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>4</number>
+   </property>
+   <item>
+    <widget class="FileChooserPanelWithHistory" name="filePanel" native="true"/>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QLabel" name="outMessage">
+     <property name="text">
+      <string/>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>FileChooserPanelWithHistory</class>
+   <extends>QWidget</extends>
+   <header>FileChooserPanelWithHistory.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.cxx b/GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.cxx
new file mode 100644
index 0000000..3295b66
--- /dev/null
+++ b/GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.cxx
@@ -0,0 +1,44 @@
+#include "MeshExportModePage.h"
+#include "ui_MeshExportModePage.h"
+
+#include "MeshExportModel.h"
+#include "QtRadioButtonCoupling.h"
+#include "QtComboBoxCoupling.h"
+#include "QtWidgetActivator.h"
+
+#include <map>
+
+MeshExportModePage::MeshExportModePage(QWidget *parent) :
+  QWizardPage(parent),
+  ui(new Ui::MeshExportModePage)
+{
+  ui->setupUi(this);
+}
+
+MeshExportModePage::~MeshExportModePage()
+{
+  delete ui;
+}
+
+void MeshExportModePage::SetModel(MeshExportModel *model)
+{
+  m_Model = model;
+
+  // Couple the widgets to the radio buttons
+  std::map<MeshExportModel::SaveMode, QAbstractButton *> button_map;
+  button_map[MeshExportModel::SAVE_SINGLE_LABEL] = ui->btnExportOne;
+  button_map[MeshExportModel::SAVE_MULTIPLE_FILES] = ui->btnExportMultipleFiles;
+  button_map[MeshExportModel::SAVE_SCENE] = ui->btnExportScene;
+  makeRadioGroupCoupling(this, button_map, m_Model->GetSaveModeModel());
+
+  // Couple the label widget
+  makeCoupling(ui->inLabel, m_Model->GetExportedLabelModel());
+
+  // Handle activation
+  activateOnFlag(ui->inLabel, m_Model, MeshExportModel::UIF_LABEL_SELECTION_ACTIVE);
+}
+
+void MeshExportModePage::initializePage()
+{
+  m_Model->OnDialogOpen();
+}
diff --git a/GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.h b/GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.h
new file mode 100644
index 0000000..000a4b7
--- /dev/null
+++ b/GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.h
@@ -0,0 +1,30 @@
+#ifndef MESHEXPORTMODEPAGE_H
+#define MESHEXPORTMODEPAGE_H
+
+#include <QWizardPage>
+
+namespace Ui {
+class MeshExportModePage;
+}
+
+class MeshExportModel;
+
+class MeshExportModePage : public QWizardPage
+{
+  Q_OBJECT
+  
+public:
+  explicit MeshExportModePage(QWidget *parent = 0);
+  ~MeshExportModePage();
+
+  void SetModel(MeshExportModel *model);
+
+  virtual void initializePage();
+  
+private:
+  Ui::MeshExportModePage *ui;
+
+  MeshExportModel *m_Model;
+};
+
+#endif // MESHEXPORTMODEPAGE_H
diff --git a/GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.ui b/GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.ui
new file mode 100644
index 0000000..746cb4b
--- /dev/null
+++ b/GUI/Qt/Windows/MeshExportWizard/MeshExportModePage.ui
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MeshExportModePage</class>
+ <widget class="QWizardPage" name="MeshExportModePage">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>WizardPage</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>6</number>
+   </property>
+   <item>
+    <widget class="QRadioButton" name="btnExportOne">
+     <property name="text">
+      <string>Export a mesh for a single label</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_3">
+      <property name="spacing">
+       <number>6</number>
+      </property>
+      <property name="leftMargin">
+       <number>24</number>
+      </property>
+      <property name="topMargin">
+       <number>6</number>
+      </property>
+      <property name="rightMargin">
+       <number>6</number>
+      </property>
+      <property name="bottomMargin">
+       <number>6</number>
+      </property>
+      <item>
+       <widget class="QComboBox" name="inLabel"/>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Fixed</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>5</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QRadioButton" name="btnExportMultipleFiles">
+     <property name="text">
+      <string>Export meshes for all labels as separate files</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_2" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="leftMargin">
+       <number>24</number>
+      </property>
+      <property name="topMargin">
+       <number>6</number>
+      </property>
+      <property name="rightMargin">
+       <number>6</number>
+      </property>
+      <property name="bottomMargin">
+       <number>6</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="label">
+        <property name="styleSheet">
+         <string notr="true">font-size:11px;
+color:rgb(128, 128, 128);</string>
+        </property>
+        <property name="text">
+         <string>Filenames will include label number (e.g., 001, 002)</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_3">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Fixed</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>5</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QRadioButton" name="btnExportScene">
+     <property name="text">
+      <string>Export meshes for all labels as a single scene</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_3" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="leftMargin">
+       <number>24</number>
+      </property>
+      <property name="topMargin">
+       <number>6</number>
+      </property>
+      <property name="rightMargin">
+       <number>6</number>
+      </property>
+      <property name="bottomMargin">
+       <number>6</number>
+      </property>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.cxx b/GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.cxx
new file mode 100644
index 0000000..ab91ef5
--- /dev/null
+++ b/GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.cxx
@@ -0,0 +1,21 @@
+#include "MeshExportWizard.h"
+#include "ui_MeshExportWizard.h"
+
+MeshExportWizard::MeshExportWizard(QWidget *parent) :
+  QWizard(parent),
+  ui(new Ui::MeshExportWizard)
+{
+  ui->setupUi(this);
+}
+
+MeshExportWizard::~MeshExportWizard()
+{
+  delete ui;
+}
+
+void MeshExportWizard::SetModel(MeshExportModel *model)
+{
+  ui->pageMode->SetModel(model);
+  ui->pageBrowse->SetModel(model);
+  m_Model = model;
+}
diff --git a/GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.h b/GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.h
new file mode 100644
index 0000000..60386f3
--- /dev/null
+++ b/GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.h
@@ -0,0 +1,29 @@
+#ifndef MESHEXPORTWIZARD_H
+#define MESHEXPORTWIZARD_H
+
+#include <QWizard>
+
+namespace Ui {
+class MeshExportWizard;
+}
+
+class MeshExportModel;
+
+class MeshExportWizard : public QWizard
+{
+  Q_OBJECT
+  
+public:
+  explicit MeshExportWizard(QWidget *parent = 0);
+  ~MeshExportWizard();
+
+  void SetModel(MeshExportModel *model);
+  
+private:
+
+  MeshExportModel *m_Model;
+
+  Ui::MeshExportWizard *ui;
+};
+
+#endif // MESHEXPORTWIZARD_H
diff --git a/GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.ui b/GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.ui
new file mode 100644
index 0000000..6528ecb
--- /dev/null
+++ b/GUI/Qt/Windows/MeshExportWizard/MeshExportWizard.ui
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MeshExportWizard</class>
+ <widget class="QWizard" name="MeshExportWizard">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Wizard</string>
+  </property>
+  <widget class="MeshExportModePage" name="pageMode">
+   <property name="title">
+    <string>Which labels will be exported?</string>
+   </property>
+  </widget>
+  <widget class="MeshExportBrowsePage" name="pageBrowse">
+   <property name="title">
+    <string>Export destination</string>
+   </property>
+   <property name="subTitle">
+    <string/>
+   </property>
+  </widget>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>MeshExportBrowsePage</class>
+   <extends>QWizardPage</extends>
+   <header>MeshExportBrowsePage.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>MeshExportModePage</class>
+   <extends>QWizardPage</extends>
+   <header>MeshExportModePage.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/PreferencesDialog.cxx b/GUI/Qt/Windows/PreferencesDialog.cxx
new file mode 100644
index 0000000..c72f902
--- /dev/null
+++ b/GUI/Qt/Windows/PreferencesDialog.cxx
@@ -0,0 +1,269 @@
+#include "PreferencesDialog.h"
+#include "ui_PreferencesDialog.h"
+#include "GlobalPreferencesModel.h"
+#include "MeshOptions.h"
+#include "DefaultBehaviorSettings.h"
+
+#include "QtCheckBoxCoupling.h"
+#include "QtComboBoxCoupling.h"
+#include "QtSpinBoxCoupling.h"
+#include "QtDoubleSpinBoxCoupling.h"
+#include "QtRadioButtonCoupling.h"
+#include "QtComboBoxCoupling.h"
+#include "QtAbstractButtonCoupling.h"
+#include "QtLabelCoupling.h"
+#include "QtWidgetActivator.h"
+#include "GlobalUIModel.h"
+#include "ColorMapModel.h"
+
+#include <QTreeView>
+#include <QPushButton>
+#include <QtAbstractItemViewCoupling.h>
+
+Q_DECLARE_METATYPE(GlobalDisplaySettings::UIGreyInterpolation)
+Q_DECLARE_METATYPE(SNAPAppearanceSettings::UIElements)
+Q_DECLARE_METATYPE(LayerLayout)
+
+PreferencesDialog::PreferencesDialog(QWidget *parent) :
+  QDialog(parent),
+  ui(new Ui::PreferencesDialog)
+{
+  ui->setupUi(this);
+
+  // Set up list of interpolation modes
+  ui->inInterpolationMode->clear();
+  ui->inInterpolationMode->addItem("Nearest Neighbor", QVariant::fromValue(GlobalDisplaySettings::NEAREST));
+  ui->inInterpolationMode->addItem("Linear", QVariant::fromValue(GlobalDisplaySettings::LINEAR));
+
+  // Set up layoyt options
+  ui->inOverlayLayout->clear();
+  ui->inOverlayLayout->addItem(QIcon(":/root/layout_overlay_16.png"),
+                               "Stack", QVariant::fromValue(LAYOUT_STACKED));
+  ui->inOverlayLayout->addItem(QIcon(":/root/layout_tile_16.png"),
+                               "Tile", QVariant::fromValue(LAYOUT_TILED));
+
+  // Set up tree of appearance elements
+  QStandardItemModel *model = new QStandardItemModel();
+
+  QStandardItem *itemSliceViews = append_category_item(model->invisibleRootItem(), "Slice Views");
+  append_appearance_item(itemSliceViews, SNAPAppearanceSettings::BACKGROUND_2D, "Background");
+  append_appearance_item(itemSliceViews, SNAPAppearanceSettings::CROSSHAIRS, "Crosshair");
+  append_appearance_item(itemSliceViews, SNAPAppearanceSettings::RULER, "Rulers");
+  append_appearance_item(itemSliceViews, SNAPAppearanceSettings::MARKERS, "Anatomic Markers");
+  append_appearance_item(itemSliceViews, SNAPAppearanceSettings::ROI_BOX, "ROI Edges");
+  append_appearance_item(itemSliceViews, SNAPAppearanceSettings::PAINTBRUSH_OUTLINE, "Paintbrush");
+
+  QStandardItem *item3DView = append_category_item(model->invisibleRootItem(), "3D View");
+  append_appearance_item(item3DView, SNAPAppearanceSettings::BACKGROUND_3D, "Background");
+  append_appearance_item(item3DView, SNAPAppearanceSettings::CROSSHAIRS_3D, "Crosshair");
+
+  QStandardItem *itemThumb = append_category_item(model->invisibleRootItem(), "Zoom Thumbnail");
+  append_appearance_item(itemThumb, SNAPAppearanceSettings::ZOOM_THUMBNAIL, "Image");
+  append_appearance_item(itemThumb, SNAPAppearanceSettings::CROSSHAIRS_THUMB, "Crosshair");
+
+  QStandardItem *itemPoly = append_category_item(model->invisibleRootItem(), "Polygon Tool");
+  append_appearance_item(itemPoly, SNAPAppearanceSettings::POLY_DRAW_MAIN, "Outline (drawing)");
+  append_appearance_item(itemPoly, SNAPAppearanceSettings::POLY_EDIT, "Outline (editing)");
+  append_appearance_item(itemPoly, SNAPAppearanceSettings::POLY_DRAW_CLOSE, "Completion line");
+
+  ui->treeVisualElements->setModel(model);
+  ui->treeVisualElements->expandAll();
+
+  // Set the correct page
+  ui->stack->setCurrentIndex(0);
+}
+
+PreferencesDialog::~PreferencesDialog()
+{
+  delete ui;
+}
+
+void PreferencesDialog::SetModel(GlobalPreferencesModel *model)
+{
+  // Copy the model
+  m_Model = model;
+
+  // Hook up the default behavior settings
+  DefaultBehaviorSettings *dbs = m_Model->GetDefaultBehaviorSettings();
+  makeCoupling(ui->chkLinkedZoom, dbs->GetLinkedZoomModel());
+  makeCoupling(ui->chkContinuousUpdate, dbs->GetContinuousMeshUpdateModel());
+  makeCoupling(ui->chkSynchronize, dbs->GetSynchronizationModel());
+  makeCoupling(ui->chkSyncCursor, dbs->GetSyncCursorModel());
+  makeCoupling(ui->chkSyncZoom, dbs->GetSyncZoomModel());
+  makeCoupling(ui->chkSyncPan, dbs->GetSyncPanModel());
+  makeCoupling(ui->chkCheckForUpdates, m_Model->GetCheckForUpdateModel());
+  makeCoupling(ui->chkAutoContrast, dbs->GetAutoContrastModel());
+
+  // Hook up the display layout properties
+  GlobalDisplaySettings *gds = m_Model->GetGlobalDisplaySettings();
+  makeCoupling(ui->chkLayoutAnteriorSide, gds->GetFlagLayoutPatientAnteriorShownLeftModel());
+  makeCoupling(ui->chkLayoutRightLeft, gds->GetFlagLayoutPatientRightShownLeftModel());
+
+  // Layout radio buttons
+  std::map<GlobalDisplaySettings::UISliceLayout, QAbstractButton *> btnmap;
+  btnmap[GlobalDisplaySettings::LAYOUT_ACS] = ui->btnACS;
+  btnmap[GlobalDisplaySettings::LAYOUT_ASC] = ui->btnASC;
+  btnmap[GlobalDisplaySettings::LAYOUT_CAS] = ui->btnCAS;
+  btnmap[GlobalDisplaySettings::LAYOUT_CSA] = ui->btnCSA;
+  btnmap[GlobalDisplaySettings::LAYOUT_SAC] = ui->btnSAC;
+  btnmap[GlobalDisplaySettings::LAYOUT_SCA] = ui->btnSCA;
+  makeRadioGroupCoupling(ui->grpLayoutRadio, btnmap, gds->GetSliceLayoutModel());
+
+  // The text labels for different layouts
+  makeCoupling(ui->outViewTopLeft, m_Model->GetLayoutLabelModel(0));
+  makeCoupling(ui->outViewTopRight, m_Model->GetLayoutLabelModel(1));
+  makeCoupling(ui->outViewBottomRight, m_Model->GetLayoutLabelModel(2));
+
+  makeCoupling(ui->chkShowThumbnail, gds->GetFlagDisplayZoomThumbnailModel());
+  makeCoupling(ui->inThumbnailFraction, gds->GetZoomThumbnailSizeInPercentModel());
+  makeCoupling(ui->inThumbnailMaxSize, gds->GetZoomThumbnailMaximumSizeModel());
+
+  // Couple the interpolation mode (the domain is not provided by the model)
+  makeCoupling(ui->inInterpolationMode, gds->GetGreyInterpolationModeModel());
+
+  // Couple the color map preset selection.
+  UpdateColorMapPresets();
+  makeCoupling(ui->inDefaultColorMap, dbs->GetOverlayColorMapPresetModel());
+
+  // We also want to monitor changes to the color map presets. If these changes
+  // occur, we have to modify the list of presets.
+  LatentITKEventNotifier::connect(m_Model->GetParentModel()->GetColorMapModel(),
+                                  ColorMapModel::PresetUpdateEvent(),
+                                  this, SLOT(onModelUpdate(EventBucket)));
+
+  // Couple the list of apperance elements. First we m
+  makeCoupling((QAbstractItemView *) ui->treeVisualElements, m_Model->GetActiveUIElementModel());
+
+  // Hook up the appearance widgets
+  OpenGLAppearanceElement *elt = m_Model->GetActiveUIElementAppearance();
+  QtCouplingOptions opts_elt(QtCouplingOptions::DEACTIVATE_WHEN_INVALID);
+  makeCoupling(ui->chkElementVisible, elt->GetVisibleModel(), opts_elt);
+  makeCoupling(ui->btnElementNormalColor, elt->GetNormalColorModel(), opts_elt);
+  makeCoupling(ui->btnElementActiveColor, elt->GetActiveColorModel(), opts_elt);
+  makeCoupling(ui->inElementThickness, elt->GetLineThicknessModel(), opts_elt);
+  makeCoupling(ui->inElementDashSpacing, elt->GetDashSpacingModel(), opts_elt);
+  makeCoupling(ui->inElementFontSize, elt->GetFontSizeModel(), opts_elt);
+  makeCoupling(ui->chkElementAntiAlias, elt->GetAlphaBlendingModel(), opts_elt);
+
+  // Make sure the labels are activated along with the widgets
+  activateOnFlag(ui->labelElementNormalColor, elt->GetNormalColorModel(), UIF_PROPERTY_IS_VALID);
+  activateOnFlag(ui->labelElementActiveColor, elt->GetActiveColorModel(), UIF_PROPERTY_IS_VALID);
+  activateOnFlag(ui->labelElementLineThickness, elt->GetLineThicknessModel(), UIF_PROPERTY_IS_VALID);
+  activateOnFlag(ui->labelElementDashSpacing, elt->GetDashSpacingModel(), UIF_PROPERTY_IS_VALID);
+  activateOnFlag(ui->labelElementFontSize, elt->GetFontSizeModel(), UIF_PROPERTY_IS_VALID);
+
+  // Hook up activation for the appearance panel
+  activateOnFlag(ui->grpAppearance, m_Model, GlobalPreferencesModel::UIF_VALID_UI_ELEMENT_SELECTED);
+
+
+  // Hook up the mesh options
+  MeshOptions *mo = m_Model->GetMeshOptions();
+
+  makeCoupling(ui->chkGaussianSmooth, mo->GetUseGaussianSmoothingModel());
+  makeCoupling(ui->inGaussianSmoothDeviation, mo->GetGaussianStandardDeviationModel());
+  makeCoupling(ui->inGaussianSmoothMaxError, mo->GetGaussianErrorModel());
+
+  makeCoupling(ui->chkMeshSmooth, mo->GetUseMeshSmoothingModel());
+  makeCoupling(ui->inMeshSmoothConvergence, mo->GetMeshSmoothingConvergenceModel());
+  makeCoupling(ui->inMeshSmoothFeatureAngle, mo->GetMeshSmoothingFeatureAngleModel());
+  makeCoupling(ui->inMeshSmoothIterations, mo->GetMeshSmoothingIterationsModel());
+  makeCoupling(ui->inMeshSmoothRelaxation, mo->GetMeshSmoothingRelaxationFactorModel());
+  makeCoupling(ui->chkMeshSmoothBoundarySmoothing, mo->GetMeshSmoothingBoundarySmoothingModel());
+  makeCoupling(ui->chkMeshSmoothFeatureEdgeSmoothing, mo->GetMeshSmoothingFeatureEdgeSmoothingModel());
+
+  makeCoupling(ui->chkDecimate, mo->GetUseDecimationModel());
+  makeCoupling(ui->inDecimateFeatureAngle, mo->GetDecimateFeatureAngleModel());
+  makeCoupling(ui->inDecimateMaxError, mo->GetDecimateMaximumErrorModel());
+  makeCoupling(ui->inDecimateTargetReduction, mo->GetDecimateTargetReductionModel());
+  makeCoupling(ui->chkDecimatePreserveTopology, mo->GetDecimatePreserveTopologyModel());
+}
+
+void PreferencesDialog::ShowDialog()
+{
+  if(!this->isVisible())
+    {
+    m_Model->InitializePreferences();
+    ui->listWidget->setCurrentRow(0);
+    this->show();
+    }
+
+  this->activateWindow();
+  this->raise();
+}
+
+void PreferencesDialog::GoToAppearancePage()
+{
+  ui->listWidget->setCurrentRow(2);
+}
+
+void PreferencesDialog::on_listWidget_itemSelectionChanged()
+{
+  // Select the right page in the right pane
+  QItemSelectionModel *selm = ui->listWidget->selectionModel();
+  int row = selm->currentIndex().row();
+  ui->stack->setCurrentIndex(row);
+  ui->outPage->setText(ui->listWidget->item(row)->text());
+}
+
+void PreferencesDialog::on_buttonBox_clicked(QAbstractButton *button)
+{
+  if (button == ui->buttonBox->button(QDialogButtonBox::Apply))
+    {
+    m_Model->ApplyPreferences();
+    }
+  else if (button == ui->buttonBox->button(QDialogButtonBox::Ok))
+    {
+    m_Model->ApplyPreferences();
+    this->accept();
+    }
+}
+
+void PreferencesDialog::on_btnElementReset_clicked()
+{
+  m_Model->ResetCurrentElement();
+}
+
+void PreferencesDialog::on_btnElementResetAll_clicked()
+{
+  m_Model->ResetAllElements();
+}
+
+void PreferencesDialog::onModelUpdate(const EventBucket &bucket)
+{
+  if(bucket.HasEvent(ColorMapModel::PresetUpdateEvent()))
+    {
+    // Update the presets
+    UpdateColorMapPresets();
+
+    // TODO: what to do if the preset was deleted?
+    }
+}
+
+void PreferencesDialog::UpdateColorMapPresets()
+{
+  ColorMapModel *cmm = m_Model->GetParentModel()->GetColorMapModel();
+  PopulateColorMapPresetCombo(ui->inDefaultColorMap, cmm);
+}
+
+QStandardItem *PreferencesDialog::append_appearance_item(
+    QStandardItem *parent,
+    SNAPAppearanceSettings::UIElements elt,
+    const QString &text)
+{
+  QStandardItem *item = new QStandardItem(text);
+  item->setData(QVariant::fromValue(elt), Qt::UserRole);
+  parent->appendRow(item);
+  return item;
+}
+
+QStandardItem *PreferencesDialog::append_category_item(
+    QStandardItem *parent,
+    const QString &text)
+{
+  QStandardItem *item = new QStandardItem(text);
+  item->setData(QVariant::fromValue(SNAPAppearanceSettings::ELEMENT_COUNT), Qt::UserRole);
+  item->setSelectable(false);
+  parent->appendRow(item);
+  return item;
+}
+
diff --git a/GUI/Qt/Windows/PreferencesDialog.h b/GUI/Qt/Windows/PreferencesDialog.h
new file mode 100644
index 0000000..4bba9a1
--- /dev/null
+++ b/GUI/Qt/Windows/PreferencesDialog.h
@@ -0,0 +1,61 @@
+#ifndef PREFERENCESDIALOG_H
+#define PREFERENCESDIALOG_H
+
+#include <QDialog>
+#include "SNAPAppearanceSettings.h"
+
+namespace Ui {
+class PreferencesDialog;
+}
+
+class GlobalPreferencesModel;
+class QAbstractButton;
+class QStandardItem;
+
+class PreferencesDialog : public QDialog
+{
+  Q_OBJECT
+  
+public:
+  explicit PreferencesDialog(QWidget *parent = 0);
+  ~PreferencesDialog();
+
+  void SetModel(GlobalPreferencesModel *model);
+
+  // This method should be used to show the dialog each time!
+  void ShowDialog();
+
+  // Goes to a particular page
+  void GoToAppearancePage();
+
+private slots:
+  void on_listWidget_itemSelectionChanged();
+
+  void on_buttonBox_clicked(QAbstractButton *button);
+
+  void on_btnElementReset_clicked();
+
+  void on_btnElementResetAll_clicked();
+
+  void onModelUpdate(const EventBucket &bucket);
+
+private:
+  Ui::PreferencesDialog *ui;
+
+  GlobalPreferencesModel *m_Model;
+
+  // Fill the color map presets
+  void UpdateColorMapPresets();
+
+  // Helper methods for building the appearance tree
+  QStandardItem *append_appearance_item(
+      QStandardItem *parent,
+      SNAPAppearanceSettings::UIElements elt,
+      const QString &text);
+
+  QStandardItem *append_category_item(
+      QStandardItem *parent,
+      const QString &text);
+};
+
+#endif // PREFERENCESDIALOG_H
diff --git a/GUI/Qt/Windows/PreferencesDialog.ui b/GUI/Qt/Windows/PreferencesDialog.ui
new file mode 100644
index 0000000..1a9f424
--- /dev/null
+++ b/GUI/Qt/Windows/PreferencesDialog.ui
@@ -0,0 +1,1488 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PreferencesDialog</class>
+ <widget class="QDialog" name="PreferencesDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>689</width>
+    <height>554</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Preferences - ITK-SNAP</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout" columnstretch="0,0">
+   <item row="2" column="0" colspan="2">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="QStackedWidget" name="stack">
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="pageGeneral">
+      <layout class="QVBoxLayout" name="verticalLayout">
+       <property name="leftMargin">
+        <number>0</number>
+       </property>
+       <property name="topMargin">
+        <number>0</number>
+       </property>
+       <property name="rightMargin">
+        <number>0</number>
+       </property>
+       <property name="bottomMargin">
+        <number>0</number>
+       </property>
+       <item>
+        <widget class="QTabWidget" name="tabWidget_4">
+         <property name="currentIndex">
+          <number>0</number>
+         </property>
+         <widget class="QWidget" name="tab_6">
+          <attribute name="title">
+           <string>Default Behavior</string>
+          </attribute>
+          <layout class="QVBoxLayout" name="verticalLayout_11">
+           <item>
+            <widget class="QCheckBox" name="chkAutoContrast">
+             <property name="toolTip">
+              <string>When this option is checked, image contrast will be adjusted automatically based on the image histogram whenever a new image is loaded into ITK-SNAP.</string>
+             </property>
+             <property name="text">
+              <string>Automatically adjust contrast when loading images</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QCheckBox" name="chkLinkedZoom">
+             <property name="text">
+              <string>Maintain same zoom factor in all slices ("linked zoom")</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QCheckBox" name="chkContinuousUpdate">
+             <property name="text">
+              <string>Automatically update 3D mesh in a background process</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QCheckBox" name="chkSynchronize">
+             <property name="text">
+              <string>Synchronize view between multiple ITK-SNAP sessions</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox">
+             <property name="title">
+              <string/>
+             </property>
+             <layout class="QHBoxLayout" name="horizontalLayout_3">
+              <property name="leftMargin">
+               <number>6</number>
+              </property>
+              <property name="topMargin">
+               <number>6</number>
+              </property>
+              <property name="rightMargin">
+               <number>6</number>
+              </property>
+              <property name="bottomMargin">
+               <number>6</number>
+              </property>
+              <item>
+               <spacer name="horizontalSpacer">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <widget class="QCheckBox" name="chkSyncCursor">
+                <property name="text">
+                 <string>Cursor position</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QCheckBox" name="chkSyncZoom">
+                <property name="text">
+                 <string>Zoom</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QCheckBox" name="chkSyncPan">
+                <property name="text">
+                 <string>Pan</string>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <spacer name="verticalSpacer_8">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>40</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
+         <widget class="QWidget" name="tab_7">
+          <attribute name="title">
+           <string>Permissions</string>
+          </attribute>
+          <layout class="QVBoxLayout" name="verticalLayout_14">
+           <item>
+            <widget class="QCheckBox" name="chkCheckForUpdates">
+             <property name="text">
+              <string>Allow ITK-SNAP to check for updates periodically</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <spacer name="verticalSpacer">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>40</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="pageLayout">
+      <layout class="QVBoxLayout" name="verticalLayout_5">
+       <property name="leftMargin">
+        <number>0</number>
+       </property>
+       <property name="topMargin">
+        <number>0</number>
+       </property>
+       <property name="rightMargin">
+        <number>0</number>
+       </property>
+       <property name="bottomMargin">
+        <number>0</number>
+       </property>
+       <item>
+        <widget class="QTabWidget" name="tabWidget">
+         <property name="currentIndex">
+          <number>0</number>
+         </property>
+         <widget class="QWidget" name="tab_3">
+          <attribute name="title">
+           <string>Display</string>
+          </attribute>
+          <layout class="QVBoxLayout" name="verticalLayout_9">
+           <property name="spacing">
+            <number>20</number>
+           </property>
+           <item>
+            <widget class="QGroupBox" name="groupBox_7">
+             <property name="title">
+              <string>Anatomic image display:</string>
+             </property>
+             <layout class="QFormLayout" name="formLayout_2">
+              <property name="fieldGrowthPolicy">
+               <enum>QFormLayout::FieldsStayAtSizeHint</enum>
+              </property>
+              <item row="0" column="0">
+               <widget class="QLabel" name="label_5">
+                <property name="text">
+                 <string>Interpolation mode:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="0" column="1">
+               <widget class="QComboBox" name="inInterpolationMode"/>
+              </item>
+              <item row="2" column="0">
+               <widget class="QLabel" name="label_8">
+                <property name="text">
+                 <string>Default layout for overlays:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="0">
+               <widget class="QLabel" name="label_10">
+                <property name="text">
+                 <string>Default colormap for overays:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="1">
+               <widget class="QComboBox" name="inDefaultColorMap"/>
+              </item>
+              <item row="2" column="1">
+               <widget class="QComboBox" name="inOverlayLayout"/>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_6">
+             <property name="title">
+              <string>Zoom Thumbnail</string>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_10">
+              <item>
+               <widget class="QCheckBox" name="chkShowThumbnail">
+                <property name="text">
+                 <string>Show thumbnail when the slice does not fit in window</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QWidget" name="widget_4" native="true">
+                <layout class="QFormLayout" name="formLayout">
+                 <property name="verticalSpacing">
+                  <number>6</number>
+                 </property>
+                 <property name="leftMargin">
+                  <number>36</number>
+                 </property>
+                 <property name="topMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="bottomMargin">
+                  <number>0</number>
+                 </property>
+                 <item row="0" column="0">
+                  <widget class="QLabel" name="label_6">
+                   <property name="text">
+                    <string>Thumbnail size, relative to slice:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="1">
+                  <widget class="QSpinBox" name="inThumbnailFraction">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                   <property name="suffix">
+                    <string>%</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="1">
+                  <widget class="QSpinBox" name="inThumbnailMaxSize">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                   <property name="suffix">
+                    <string> px</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="0">
+                  <widget class="QLabel" name="label_7">
+                   <property name="text">
+                    <string>Maximum thumbnail size:</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <spacer name="verticalSpacer_4">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>40</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
+         <widget class="QWidget" name="tab">
+          <attribute name="title">
+           <string>Layout</string>
+          </attribute>
+          <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
+           <item>
+            <widget class="QWidget" name="widget_2" native="true">
+             <layout class="QVBoxLayout" name="verticalLayout_6">
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="topMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <property name="bottomMargin">
+               <number>0</number>
+              </property>
+              <item>
+               <widget class="QGroupBox" name="groupBox_3">
+                <property name="title">
+                 <string>Current screen layout:</string>
+                </property>
+                <layout class="QGridLayout" name="gridLayout_2">
+                 <property name="leftMargin">
+                  <number>6</number>
+                 </property>
+                 <property name="topMargin">
+                  <number>6</number>
+                 </property>
+                 <property name="rightMargin">
+                  <number>6</number>
+                 </property>
+                 <property name="bottomMargin">
+                  <number>6</number>
+                 </property>
+                 <item row="1" column="0">
+                  <widget class="QLabel" name="outViewTopLeft">
+                   <property name="minimumSize">
+                    <size>
+                     <width>64</width>
+                     <height>64</height>
+                    </size>
+                   </property>
+                   <property name="maximumSize">
+                    <size>
+                     <width>64</width>
+                     <height>64</height>
+                    </size>
+                   </property>
+                   <property name="styleSheet">
+                    <string notr="true">background-color:rgb(179, 179, 179);
+border-color:rgb(51, 51, 51);
+border-style:solid;
+border-width:1px;
+color:white;</string>
+                   </property>
+                   <property name="text">
+                    <string>Axial</string>
+                   </property>
+                   <property name="alignment">
+                    <set>Qt::AlignCenter</set>
+                   </property>
+                   <property name="wordWrap">
+                    <bool>true</bool>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="1">
+                  <widget class="QLabel" name="outViewTopRight">
+                   <property name="minimumSize">
+                    <size>
+                     <width>64</width>
+                     <height>64</height>
+                    </size>
+                   </property>
+                   <property name="maximumSize">
+                    <size>
+                     <width>64</width>
+                     <height>64</height>
+                    </size>
+                   </property>
+                   <property name="styleSheet">
+                    <string notr="true">background-color:rgb(179, 179, 179);
+border-color:rgb(51, 51, 51);
+border-style:solid;
+border-width:1px;
+color:white;</string>
+                   </property>
+                   <property name="text">
+                    <string>Coronal</string>
+                   </property>
+                   <property name="alignment">
+                    <set>Qt::AlignCenter</set>
+                   </property>
+                   <property name="wordWrap">
+                    <bool>true</bool>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="2" column="0">
+                  <widget class="QLabel" name="outViewBottomLeft">
+                   <property name="minimumSize">
+                    <size>
+                     <width>64</width>
+                     <height>64</height>
+                    </size>
+                   </property>
+                   <property name="maximumSize">
+                    <size>
+                     <width>64</width>
+                     <height>64</height>
+                    </size>
+                   </property>
+                   <property name="styleSheet">
+                    <string notr="true">background-color:rgb(179, 179, 179);
+border-color:rgb(51, 51, 51);
+border-style:solid;
+border-width:1px;
+color:white;</string>
+                   </property>
+                   <property name="text">
+                    <string>3D View</string>
+                   </property>
+                   <property name="alignment">
+                    <set>Qt::AlignCenter</set>
+                   </property>
+                   <property name="wordWrap">
+                    <bool>true</bool>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="2" column="1">
+                  <widget class="QLabel" name="outViewBottomRight">
+                   <property name="minimumSize">
+                    <size>
+                     <width>64</width>
+                     <height>64</height>
+                    </size>
+                   </property>
+                   <property name="maximumSize">
+                    <size>
+                     <width>64</width>
+                     <height>64</height>
+                    </size>
+                   </property>
+                   <property name="styleSheet">
+                    <string notr="true">background-color:rgb(179, 179, 179);
+border-color:rgb(51, 51, 51);
+border-style:solid;
+border-width:1px;
+color:white;</string>
+                   </property>
+                   <property name="text">
+                    <string>Sagittal</string>
+                   </property>
+                   <property name="alignment">
+                    <set>Qt::AlignCenter</set>
+                   </property>
+                   <property name="wordWrap">
+                    <bool>true</bool>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item>
+               <spacer name="verticalSpacer_2">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>213</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <widget class="QWidget" name="widget_3" native="true">
+             <layout class="QVBoxLayout" name="verticalLayout_7">
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="topMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <property name="bottomMargin">
+               <number>0</number>
+              </property>
+              <item>
+               <widget class="QGroupBox" name="grpLayoutRadio">
+                <property name="title">
+                 <string>Available Layouts:</string>
+                </property>
+                <layout class="QGridLayout" name="gridLayout_4">
+                 <item row="0" column="0">
+                  <widget class="QRadioButton" name="btnASC">
+                   <property name="text">
+                    <string>ASC</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="2">
+                  <widget class="QRadioButton" name="btnCAS">
+                   <property name="text">
+                    <string>CAS</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="1">
+                  <widget class="QRadioButton" name="btnSAC">
+                   <property name="text">
+                    <string>SAC</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="0">
+                  <widget class="QRadioButton" name="btnACS">
+                   <property name="text">
+                    <string>ACS</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="1">
+                  <widget class="QRadioButton" name="btnSCA">
+                   <property name="text">
+                    <string>SCA</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="2">
+                  <widget class="QRadioButton" name="btnCSA">
+                   <property name="text">
+                    <string>CSA</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item>
+               <widget class="QGroupBox" name="groupBox_5">
+                <property name="title">
+                 <string>Additional options:</string>
+                </property>
+                <layout class="QVBoxLayout" name="verticalLayout_8">
+                 <item>
+                  <widget class="QCheckBox" name="chkLayoutAnteriorSide">
+                   <property name="text">
+                    <string>Display anterior on the left</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QCheckBox" name="chkLayoutRightLeft">
+                   <property name="text">
+                    <string>Patient right is screen left</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item>
+               <spacer name="verticalSpacer_3">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>40</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="page">
+      <layout class="QHBoxLayout" name="horizontalLayout_5">
+       <property name="leftMargin">
+        <number>0</number>
+       </property>
+       <property name="topMargin">
+        <number>0</number>
+       </property>
+       <property name="rightMargin">
+        <number>0</number>
+       </property>
+       <property name="bottomMargin">
+        <number>0</number>
+       </property>
+       <item>
+        <widget class="QTabWidget" name="tabWidget_2">
+         <property name="currentIndex">
+          <number>0</number>
+         </property>
+         <widget class="QWidget" name="tab_2">
+          <attribute name="title">
+           <string>Appearance</string>
+          </attribute>
+          <layout class="QHBoxLayout" name="horizontalLayout_6" stretch="1,0">
+           <item>
+            <widget class="QGroupBox" name="groupBox_8">
+             <property name="title">
+              <string>Visual elements:</string>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_13">
+              <item>
+               <widget class="QTreeView" name="treeVisualElements">
+                <attribute name="headerVisible">
+                 <bool>false</bool>
+                </attribute>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="grpAppearance">
+             <property name="title">
+              <string>Appearance:</string>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_12">
+              <item>
+               <widget class="QWidget" name="widget_7" native="true">
+                <layout class="QFormLayout" name="formLayout_3">
+                 <property name="fieldGrowthPolicy">
+                  <enum>QFormLayout::FieldsStayAtSizeHint</enum>
+                 </property>
+                 <property name="leftMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="topMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="rightMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="bottomMargin">
+                  <number>0</number>
+                 </property>
+                 <item row="0" column="1">
+                  <widget class="QCheckBox" name="chkElementVisible">
+                   <property name="text">
+                    <string>Visible</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="1">
+                  <spacer name="verticalSpacer_7">
+                   <property name="orientation">
+                    <enum>Qt::Vertical</enum>
+                   </property>
+                   <property name="sizeType">
+                    <enum>QSizePolicy::Fixed</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>20</width>
+                     <height>5</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                 <item row="2" column="0">
+                  <widget class="QLabel" name="labelElementNormalColor">
+                   <property name="text">
+                    <string>Normal color:</string>
+                   </property>
+                   <property name="buddy">
+                    <cstring>btnElementNormalColor</cstring>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="2" column="1">
+                  <widget class="QColorButtonWidget" name="btnElementNormalColor" native="true"/>
+                 </item>
+                 <item row="3" column="0">
+                  <widget class="QLabel" name="labelElementActiveColor">
+                   <property name="text">
+                    <string>Active color:</string>
+                   </property>
+                   <property name="buddy">
+                    <cstring>btnElementActiveColor</cstring>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="3" column="1">
+                  <widget class="QColorButtonWidget" name="btnElementActiveColor" native="true"/>
+                 </item>
+                 <item row="4" column="1">
+                  <spacer name="verticalSpacer_5">
+                   <property name="orientation">
+                    <enum>Qt::Vertical</enum>
+                   </property>
+                   <property name="sizeType">
+                    <enum>QSizePolicy::Fixed</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>20</width>
+                     <height>5</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                 <item row="6" column="0">
+                  <widget class="QLabel" name="labelElementLineThickness">
+                   <property name="text">
+                    <string>Line thickness:</string>
+                   </property>
+                   <property name="buddy">
+                    <cstring>inElementThickness</cstring>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="6" column="1">
+                  <widget class="QDoubleSpinBox" name="inElementThickness">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="9" column="0">
+                  <widget class="QLabel" name="labelElementDashSpacing">
+                   <property name="text">
+                    <string>Dash spacing:</string>
+                   </property>
+                   <property name="buddy">
+                    <cstring>inElementDashSpacing</cstring>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="9" column="1">
+                  <widget class="QSpinBox" name="inElementDashSpacing">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="11" column="1">
+                  <spacer name="verticalSpacer_6">
+                   <property name="orientation">
+                    <enum>Qt::Vertical</enum>
+                   </property>
+                   <property name="sizeType">
+                    <enum>QSizePolicy::Fixed</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>20</width>
+                     <height>5</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                 <item row="12" column="0">
+                  <widget class="QLabel" name="labelElementFontSize">
+                   <property name="text">
+                    <string>Font size:</string>
+                   </property>
+                   <property name="buddy">
+                    <cstring>inElementFontSize</cstring>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="12" column="1">
+                  <widget class="QSpinBox" name="inElementFontSize">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="7" column="1">
+                  <widget class="QCheckBox" name="chkElementAntiAlias">
+                   <property name="text">
+                    <string>Smooth </string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="8" column="1">
+                  <spacer name="verticalSpacer_10">
+                   <property name="orientation">
+                    <enum>Qt::Vertical</enum>
+                   </property>
+                   <property name="sizeType">
+                    <enum>QSizePolicy::Fixed</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>20</width>
+                     <height>5</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item>
+               <widget class="QWidget" name="widget_14" native="true">
+                <layout class="QHBoxLayout" name="horizontalLayout_10">
+                 <item>
+                  <widget class="QPushButton" name="btnElementReset">
+                   <property name="toolTip">
+                    <string>Resets the appearance of the selected visual elements to its default</string>
+                   </property>
+                   <property name="text">
+                    <string>Reset</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QPushButton" name="btnElementResetAll">
+                   <property name="toolTip">
+                    <string>Resets the appearance of all visual elements to their defaults</string>
+                   </property>
+                   <property name="text">
+                    <string>Reset All</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="pageRendering">
+      <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0">
+       <property name="leftMargin">
+        <number>0</number>
+       </property>
+       <property name="topMargin">
+        <number>0</number>
+       </property>
+       <property name="rightMargin">
+        <number>0</number>
+       </property>
+       <property name="bottomMargin">
+        <number>0</number>
+       </property>
+       <item>
+        <widget class="QTabWidget" name="tabWidget_3">
+         <property name="currentIndex">
+          <number>0</number>
+         </property>
+         <widget class="QWidget" name="tab_4">
+          <attribute name="title">
+           <string>Smoothing</string>
+          </attribute>
+          <layout class="QVBoxLayout" name="verticalLayout_2">
+           <property name="spacing">
+            <number>6</number>
+           </property>
+           <item>
+            <widget class="QCheckBox" name="chkGaussianSmooth">
+             <property name="text">
+              <string>Gaussian image smoothing (slow, improves display quality)</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_2">
+             <property name="title">
+              <string/>
+             </property>
+             <layout class="QHBoxLayout" name="horizontalLayout_4">
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="topMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <property name="bottomMargin">
+               <number>0</number>
+              </property>
+              <item>
+               <widget class="QWidget" name="widget" native="true">
+                <layout class="QFormLayout" name="formLayout_4">
+                 <item row="0" column="0">
+                  <widget class="QLabel" name="label_9">
+                   <property name="text">
+                    <string>Standard deviation:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="1">
+                  <widget class="QDoubleSpinBox" name="inGaussianSmoothDeviation">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item>
+               <widget class="QWidget" name="widget_5" native="true">
+                <layout class="QFormLayout" name="formLayout_5">
+                 <item row="0" column="0">
+                  <widget class="QLabel" name="label_15">
+                   <property name="text">
+                    <string>Approximation error max:</string>
+                   </property>
+                   <property name="wordWrap">
+                    <bool>true</bool>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="1">
+                  <widget class="QDoubleSpinBox" name="inGaussianSmoothMaxError">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <spacer name="verticalSpacer_13">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeType">
+              <enum>QSizePolicy::Fixed</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>10</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+           <item>
+            <widget class="QCheckBox" name="chkMeshSmooth">
+             <property name="text">
+              <string>Laplacian mesh smoothing (slow, improves mesh quality)</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_12">
+             <property name="title">
+              <string/>
+             </property>
+             <layout class="QGridLayout" name="gridLayout_3">
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="topMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <property name="bottomMargin">
+               <number>0</number>
+              </property>
+              <property name="spacing">
+               <number>0</number>
+              </property>
+              <item row="0" column="0">
+               <widget class="QWidget" name="widget_6" native="true">
+                <layout class="QFormLayout" name="formLayout_6">
+                 <item row="0" column="0">
+                  <widget class="QLabel" name="label_16">
+                   <property name="text">
+                    <string>Convergence:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="1">
+                  <widget class="QDoubleSpinBox" name="inMeshSmoothConvergence">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="1">
+                  <widget class="QDoubleSpinBox" name="inMeshSmoothIterations">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="0">
+                  <widget class="QLabel" name="label_18">
+                   <property name="text">
+                    <string>Iterations:</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item row="0" column="1">
+               <widget class="QWidget" name="widget_8" native="true">
+                <layout class="QFormLayout" name="formLayout_7">
+                 <item row="0" column="0">
+                  <widget class="QLabel" name="label_17">
+                   <property name="text">
+                    <string>Feature angle:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="1">
+                  <widget class="QDoubleSpinBox" name="inMeshSmoothFeatureAngle">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="1">
+                  <widget class="QDoubleSpinBox" name="inMeshSmoothRelaxation">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="0">
+                  <widget class="QLabel" name="label_19">
+                   <property name="text">
+                    <string>Relaxation:</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item row="1" column="0" colspan="2">
+               <widget class="QWidget" name="widget_10" native="true">
+                <layout class="QHBoxLayout" name="horizontalLayout_7">
+                 <item>
+                  <spacer name="horizontalSpacer_2">
+                   <property name="orientation">
+                    <enum>Qt::Horizontal</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>40</width>
+                     <height>20</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                 <item>
+                  <widget class="QCheckBox" name="chkMeshSmoothFeatureEdgeSmoothing">
+                   <property name="text">
+                    <string>Feature edge smoothing</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QCheckBox" name="chkMeshSmoothBoundarySmoothing">
+                   <property name="text">
+                    <string>Boundary smoothing</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <widget class="QWidget" name="widget_9" native="true">
+             <layout class="QHBoxLayout" name="horizontalLayout_8"/>
+            </widget>
+           </item>
+           <item>
+            <spacer name="verticalSpacer_9">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>40</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
+         <widget class="QWidget" name="tab_5">
+          <attribute name="title">
+           <string>Decimation</string>
+          </attribute>
+          <layout class="QVBoxLayout" name="verticalLayout_3">
+           <item>
+            <widget class="QCheckBox" name="chkDecimate">
+             <property name="text">
+              <string>Decimate mesh (reduces number of polygons)</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_13">
+             <property name="title">
+              <string/>
+             </property>
+             <layout class="QGridLayout" name="gridLayout_5">
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="topMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <property name="bottomMargin">
+               <number>0</number>
+              </property>
+              <property name="spacing">
+               <number>0</number>
+              </property>
+              <item row="0" column="0">
+               <widget class="QWidget" name="widget_11" native="true">
+                <layout class="QFormLayout" name="formLayout_8">
+                 <property name="fieldGrowthPolicy">
+                  <enum>QFormLayout::FieldsStayAtSizeHint</enum>
+                 </property>
+                 <item row="0" column="0">
+                  <widget class="QLabel" name="label_20">
+                   <property name="text">
+                    <string>Target reduction:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="1">
+                  <widget class="QDoubleSpinBox" name="inDecimateTargetReduction">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="0">
+                  <widget class="QLabel" name="label_21">
+                   <property name="text">
+                    <string>Maximum error:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="1">
+                  <widget class="QDoubleSpinBox" name="inDecimateMaxError">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item row="0" column="1">
+               <widget class="QWidget" name="widget_12" native="true">
+                <layout class="QFormLayout" name="formLayout_9">
+                 <property name="fieldGrowthPolicy">
+                  <enum>QFormLayout::FieldsStayAtSizeHint</enum>
+                 </property>
+                 <item row="0" column="0">
+                  <widget class="QLabel" name="label_25">
+                   <property name="text">
+                    <string>Feature angle:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="1">
+                  <widget class="QDoubleSpinBox" name="inDecimateFeatureAngle">
+                   <property name="minimumSize">
+                    <size>
+                     <width>80</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item row="1" column="0" colspan="2">
+               <widget class="QWidget" name="widget_13" native="true">
+                <layout class="QHBoxLayout" name="horizontalLayout_9">
+                 <item>
+                  <spacer name="horizontalSpacer_3">
+                   <property name="orientation">
+                    <enum>Qt::Horizontal</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>40</width>
+                     <height>20</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                 <item>
+                  <widget class="QCheckBox" name="chkDecimatePreserveTopology">
+                   <property name="text">
+                    <string>Preserve topology</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <spacer name="verticalSpacer_14">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>40</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item row="0" column="0" rowspan="2">
+    <widget class="QListWidget" name="listWidget">
+     <property name="minimumSize">
+      <size>
+       <width>140</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>140</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <item>
+      <property name="text">
+       <string>General</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>Slice Views</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>Appearance</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>3D Rendering</string>
+      </property>
+     </item>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QLabel" name="outPage">
+     <property name="styleSheet">
+      <string notr="true">font-size:14px;
+font-weight:bold;</string>
+     </property>
+     <property name="text">
+      <string>General</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QColorButtonWidget</class>
+   <extends>QWidget</extends>
+   <header>QColorButtonWidget.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>listWidget</tabstop>
+  <tabstop>tabWidget_4</tabstop>
+  <tabstop>chkLinkedZoom</tabstop>
+  <tabstop>chkContinuousUpdate</tabstop>
+  <tabstop>chkSynchronize</tabstop>
+  <tabstop>chkSyncCursor</tabstop>
+  <tabstop>chkSyncZoom</tabstop>
+  <tabstop>chkSyncPan</tabstop>
+  <tabstop>chkCheckForUpdates</tabstop>
+  <tabstop>tabWidget</tabstop>
+  <tabstop>btnASC</tabstop>
+  <tabstop>btnSAC</tabstop>
+  <tabstop>btnCAS</tabstop>
+  <tabstop>btnACS</tabstop>
+  <tabstop>btnSCA</tabstop>
+  <tabstop>btnCSA</tabstop>
+  <tabstop>chkLayoutAnteriorSide</tabstop>
+  <tabstop>chkLayoutRightLeft</tabstop>
+  <tabstop>chkShowThumbnail</tabstop>
+  <tabstop>inThumbnailFraction</tabstop>
+  <tabstop>inThumbnailMaxSize</tabstop>
+  <tabstop>inInterpolationMode</tabstop>
+  <tabstop>tabWidget_2</tabstop>
+  <tabstop>treeVisualElements</tabstop>
+  <tabstop>chkElementVisible</tabstop>
+  <tabstop>btnElementNormalColor</tabstop>
+  <tabstop>btnElementActiveColor</tabstop>
+  <tabstop>inElementThickness</tabstop>
+  <tabstop>inElementDashSpacing</tabstop>
+  <tabstop>inElementFontSize</tabstop>
+  <tabstop>tabWidget_3</tabstop>
+  <tabstop>chkGaussianSmooth</tabstop>
+  <tabstop>inGaussianSmoothDeviation</tabstop>
+  <tabstop>inGaussianSmoothMaxError</tabstop>
+  <tabstop>chkMeshSmooth</tabstop>
+  <tabstop>inMeshSmoothConvergence</tabstop>
+  <tabstop>inMeshSmoothFeatureAngle</tabstop>
+  <tabstop>inMeshSmoothIterations</tabstop>
+  <tabstop>inMeshSmoothRelaxation</tabstop>
+  <tabstop>chkMeshSmoothFeatureEdgeSmoothing</tabstop>
+  <tabstop>chkMeshSmoothBoundarySmoothing</tabstop>
+  <tabstop>chkDecimate</tabstop>
+  <tabstop>inDecimateTargetReduction</tabstop>
+  <tabstop>inDecimateFeatureAngle</tabstop>
+  <tabstop>inDecimateMaxError</tabstop>
+  <tabstop>chkDecimatePreserveTopology</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>PreferencesDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>PreferencesDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/GUI/Qt/Windows/QtStyles.cxx b/GUI/Qt/Windows/QtStyles.cxx
new file mode 100644
index 0000000..4ccf80e
--- /dev/null
+++ b/GUI/Qt/Windows/QtStyles.cxx
@@ -0,0 +1,97 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "QtStyles.h"
+#include <QWidget>
+#include <QFile>
+#include <iostream>
+
+void ApplyCSS(QWidget *widget, const char *file)
+{
+  QFile qf(file);
+  if(qf.open(QFile::ReadOnly))
+    {
+    QString qs(qf.readAll());
+    widget->setStyleSheet(qs);
+    }
+  else
+    {
+    std::cerr << "Can not read CSS from " << file << std::endl;
+    }
+}
+
+const char *qstPlastiqueButton =
+  "* {"
+  "  border-image: url(:/root/fltkbutton.png) repeat;"
+  "  border-top-width: 8px;"
+  "  border-bottom-width: 8px;"
+  "  border-left-width: 3px;"
+  "  border-right-width: 3px;"
+  "  background-origin: content;"
+  "  padding-top: -8px;"
+  "  padding-bottom: -8px;"
+  "  padding-left: -3px;"
+  "  padding-right: -3px;"
+  "}"
+  "*:pressed, *:checked {"
+  "  border-image: url(:/root/fltkbutton_pressed.png) repeat;"
+  "}";
+
+const char *qstPlastiquePanel =
+  "* {"
+  "  border-image: url(:/root/fltkpanel.png) repeat;"
+  "  border-top-width: 8px;"
+  "  border-bottom-width: 8px;"
+  "  border-left-width: 2px;"
+  "  border-right-width: 2px;"
+  "  background-origin: content;"
+  "  padding-top: -3px;"
+  "  padding-bottom: -3px;"
+  "  padding-left: 3px;"
+  "  padding-right: 3px;"
+  "}";
+
+const char *qstPlastiqueGroupBox =
+"QGroupBox {"
+"  border-image: url(:/root/fltkpanel.png) repeat;"
+"  border-top-width: 8px;"
+"  border-bottom-width: 8px;"
+"  border-left-width: 2px;"
+"  border-right-width: 2px;"
+"  background-origin: content;"
+"  padding-top: -3px;"
+"  padding-bottom: -3px;"
+"  padding-left: 3px;"
+"  padding-right: 3px;"
+"  margin-top: 15px;"
+"  font-weight: bold;"
+"}"
+"QGroupBox::title {"
+"  subcontrol-origin: 	margin;"
+"  subcontrol-position: top left; "
+"}";
+
+
diff --git a/GUI/Qt/Windows/QtStyles.h b/GUI/Qt/Windows/QtStyles.h
new file mode 100644
index 0000000..544c448
--- /dev/null
+++ b/GUI/Qt/Windows/QtStyles.h
@@ -0,0 +1,38 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef QTSTYLES_H
+#define QTSTYLES_H
+
+class QWidget;
+
+extern const char *qstPlastiqueButton;
+extern const char *qstPlastiquePanel;
+extern const char *qstPlastiqueGroupBox;
+
+extern void ApplyCSS(QWidget *widget, const char *file);
+
+#endif // QTSTYLES_H
diff --git a/GUI/Qt/Windows/ReorientImageDialog.cxx b/GUI/Qt/Windows/ReorientImageDialog.cxx
new file mode 100644
index 0000000..1576d0b
--- /dev/null
+++ b/GUI/Qt/Windows/ReorientImageDialog.cxx
@@ -0,0 +1,105 @@
+#include "ReorientImageDialog.h"
+#include "ui_ReorientImageDialog.h"
+
+#include <ReorientImageModel.h>
+#include <OrientationGraphicRenderer.h>
+#include <QtLineEditCoupling.h>
+#include <QtLabelCoupling.h>
+#include <QtComboBoxCoupling.h>
+#include <QtTableWidgetCoupling.h>
+#include <QtWidgetActivator.h>
+#include <QtSimpleOpenGLBox.h>
+
+#include <QtVTKInteractionDelegateWidget.h>
+#include <vtkGenericRenderWindowInteractor.h>
+#include <vtkInteractorStyleTrackballCamera.h>
+
+Q_DECLARE_METATYPE(ImageCoordinateGeometry::AxisDirection);
+
+ReorientImageDialog::ReorientImageDialog(QWidget *parent) :
+  QDialog(parent),
+  ui(new Ui::ReorientImageDialog)
+{
+  ui->setupUi(this);
+
+  // Create the renderer and attach to the GL box
+  m_CurrentRAIRenderer = OrientationGraphicRenderer::New();
+  ui->iconCurrent->SetRenderer(m_CurrentRAIRenderer);
+
+  m_NewRAIRenderer = OrientationGraphicRenderer::New();
+  ui->iconNew->SetRenderer(m_NewRAIRenderer);
+
+  // Synchronize the cameras between the two renderers
+  m_NewRAIRenderer->SyncronizeCamera(m_CurrentRAIRenderer);
+}
+
+ReorientImageDialog::~ReorientImageDialog()
+{
+  delete ui;
+}
+
+void ReorientImageDialog::SetModel(ReorientImageModel *model)
+{
+  // Set the model
+  m_Model = model;
+
+  // Pass the model to the renderer
+  m_CurrentRAIRenderer->SetModel(m_Model->GetCurrentDirectionMatrixModel());
+  m_NewRAIRenderer->SetModel(m_Model->GetNewDirectionMatrixModel());
+
+  // Couple widgets to the model
+  makeCoupling(ui->outCurrentRAI, m_Model->GetCurrentRAICodeModel());
+  makeCoupling(ui->inNewRAI, m_Model->GetNewRAICodeModel());
+
+
+  // Allow the user to change the direction axis combos even when they are
+  // in a state that is invalid
+  QtCouplingOptions opts(QtCouplingOptions::ALLOW_UPDATES_WHEN_INVALID);
+  makeCoupling(ui->inNewAxisDirX, m_Model->GetNewAxisDirectionModel(0), opts);
+  makeCoupling(ui->inNewAxisDirY, m_Model->GetNewAxisDirectionModel(1), opts);
+  makeCoupling(ui->inNewAxisDirZ, m_Model->GetNewAxisDirectionModel(2), opts);
+
+  makeCoupling(ui->outCurrentAxisDirX, m_Model->GetCurrentAxisDirectionModel(0));
+  makeCoupling(ui->outCurrentAxisDirY, m_Model->GetCurrentAxisDirectionModel(1));
+  makeCoupling(ui->outCurrentAxisDirZ, m_Model->GetCurrentAxisDirectionModel(2));
+
+  makeCoupling(ui->outMatrixCurrent, m_Model->GetCurrentWorldMatrixModel());
+  makeCoupling(ui->outMatrixNew, m_Model->GetNewWorldMatrixModel());
+
+  // Couple status message with a model
+  makeCoupling(ui->outInvalidStatus, m_Model->GetInvalidStatusModel());
+
+  // Set up widget activation
+  activateOnFlag(ui->inNewRAI, m_Model,
+                 ReorientImageModel::UIF_IMAGE_LOADED);
+  activateOnFlag(ui->btnApply, m_Model,
+                 ReorientImageModel::UIF_VALID_NEW_RAI);
+  activateOnFlag(ui->btnReverseX, m_Model,
+                 ReorientImageModel::UIF_VALID_AXIS_DIRECTION_X);
+  activateOnFlag(ui->btnReverseY, m_Model,
+                 ReorientImageModel::UIF_VALID_AXIS_DIRECTION_Y);
+  activateOnFlag(ui->btnReverseZ, m_Model,
+                 ReorientImageModel::UIF_VALID_AXIS_DIRECTION_Z);
+
+}
+
+void ReorientImageDialog::on_btnApply_clicked()
+{
+  // Tell model to apply RAI code
+  m_Model->ApplyCurrentRAI();
+}
+
+void ReorientImageDialog::on_btnReverseX_clicked()
+{
+  m_Model->ReverseAxisDirection(0);
+}
+
+void ReorientImageDialog::on_btnReverseY_clicked()
+{
+  m_Model->ReverseAxisDirection(1);
+}
+
+void ReorientImageDialog::on_btnReverseZ_clicked()
+{
+  m_Model->ReverseAxisDirection(2);
+}
diff --git a/GUI/Qt/Windows/ReorientImageDialog.h b/GUI/Qt/Windows/ReorientImageDialog.h
new file mode 100644
index 0000000..eb37698
--- /dev/null
+++ b/GUI/Qt/Windows/ReorientImageDialog.h
@@ -0,0 +1,46 @@
+#ifndef REORIENTIMAGEDIALOG_H
+#define REORIENTIMAGEDIALOG_H
+
+#include <QDialog>
+#include <SNAPCommon.h>
+
+class ReorientImageModel;
+class OrientationGraphicRenderer;
+
+namespace Ui {
+class ReorientImageDialog;
+}
+
+class ReorientImageDialog : public QDialog
+{
+  Q_OBJECT
+  
+public:
+  explicit ReorientImageDialog(QWidget *parent = 0);
+  ~ReorientImageDialog();
+
+  void SetModel(ReorientImageModel *model);
+
+protected:
+
+  ReorientImageModel *m_Model;
+  
+private slots:
+  void on_btnApply_clicked();
+
+  void on_btnReverseX_clicked();
+
+  void on_btnReverseY_clicked();
+
+  void on_btnReverseZ_clicked();
+
+private:
+  Ui::ReorientImageDialog *ui;
+
+  // TODO: it seems wrong to have the Qt classes own renderer objects,
+  // perhaps this should be owned by the model instead?
+  SmartPtr<OrientationGraphicRenderer> m_CurrentRAIRenderer, m_NewRAIRenderer;
+
+};
+
+#endif // REORIENTIMAGEDIALOG_H
diff --git a/GUI/Qt/Windows/ReorientImageDialog.ui b/GUI/Qt/Windows/ReorientImageDialog.ui
new file mode 100644
index 0000000..ebcd1fc
--- /dev/null
+++ b/GUI/Qt/Windows/ReorientImageDialog.ui
@@ -0,0 +1,634 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ReorientImageDialog</class>
+ <widget class="QDialog" name="ReorientImageDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>623</width>
+    <height>573</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Reorient Image - ITK-SNAP</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QLineEdit:read-only {
+  background-color:rgb(240,240,240);
+}
+QTableWidget {
+  font: 10px fixed;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0,0,0,0,0">
+     <item row="1" column="2">
+      <widget class="QWidget" name="widget_4" native="true">
+       <layout class="QVBoxLayout" name="verticalLayout_2">
+        <property name="spacing">
+         <number>3</number>
+        </property>
+        <property name="margin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QLineEdit" name="inNewRAI">
+          <property name="toolTip">
+           <string><html><head/><body><p>Here you can quicky set the image orientation by entering a three-letter code (RAI code) that describes how the image rows, columns and slices map to the anatomical coordinates.</p><p><br/></p><p>For examle, the code <span style=" font-weight:600;">ASL</span> signifies that image rows (X) run from <span style=" font-weight:600;">A</span>nterior to &lt [...]
+          </property>
+          <property name="maxLength">
+           <number>3</number>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="outInvalidStatus">
+          <property name="styleSheet">
+           <string notr="true">color:rgb(128, 0, 0);
+font: 11px;</string>
+          </property>
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item row="4" column="1">
+      <widget class="QLineEdit" name="outCurrentAxisDirY">
+       <property name="styleSheet">
+        <string notr="true"/>
+       </property>
+       <property name="readOnly">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="2">
+      <widget class="QWidget" name="widget_7" native="true">
+       <layout class="QHBoxLayout" name="horizontalLayout_5">
+        <property name="spacing">
+         <number>4</number>
+        </property>
+        <property name="margin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QComboBox" name="inNewAxisDirY">
+          <property name="toolTip">
+           <string><html><head/><body><p>The direction of the image columns (Y axis) in anatomical space.</p></body></html></string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QToolButton" name="btnReverseY">
+          <property name="toolTip">
+           <string>Reverse the direction of the axis</string>
+          </property>
+          <property name="text">
+           <string>...</string>
+          </property>
+          <property name="icon">
+           <iconset resource="../Resources/SNAPResources.qrc">
+            <normaloff>:/root/revertaxis_16.png</normaloff>:/root/revertaxis_16.png</iconset>
+          </property>
+          <property name="iconSize">
+           <size>
+            <width>16</width>
+            <height>16</height>
+           </size>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item row="5" column="1">
+      <widget class="QLineEdit" name="outCurrentAxisDirZ">
+       <property name="styleSheet">
+        <string notr="true"/>
+       </property>
+       <property name="readOnly">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="5" column="2">
+      <widget class="QWidget" name="widget_8" native="true">
+       <layout class="QHBoxLayout" name="horizontalLayout_6">
+        <property name="spacing">
+         <number>4</number>
+        </property>
+        <property name="margin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QComboBox" name="inNewAxisDirZ">
+          <property name="toolTip">
+           <string><html><head/><body><p>The direction of the image slices (Z axis) in anatomical space.</p></body></html></string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QToolButton" name="btnReverseZ">
+          <property name="toolTip">
+           <string>Reverse the direction of the axis</string>
+          </property>
+          <property name="text">
+           <string>...</string>
+          </property>
+          <property name="icon">
+           <iconset resource="../Resources/SNAPResources.qrc">
+            <normaloff>:/root/revertaxis_16.png</normaloff>:/root/revertaxis_16.png</iconset>
+          </property>
+          <property name="iconSize">
+           <size>
+            <width>16</width>
+            <height>16</height>
+           </size>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item row="3" column="1">
+      <widget class="QLineEdit" name="outCurrentAxisDirX">
+       <property name="styleSheet">
+        <string notr="true"/>
+       </property>
+       <property name="readOnly">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="2">
+      <widget class="QWidget" name="widget_6" native="true">
+       <layout class="QHBoxLayout" name="horizontalLayout_4">
+        <property name="spacing">
+         <number>4</number>
+        </property>
+        <property name="margin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QComboBox" name="inNewAxisDirX">
+          <property name="toolTip">
+           <string><html><head/><body><p>The direction of the image rows (X axis) in anatomical space.</p></body></html></string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QToolButton" name="btnReverseX">
+          <property name="toolTip">
+           <string>Reverse the direction of the axis</string>
+          </property>
+          <property name="text">
+           <string>...</string>
+          </property>
+          <property name="icon">
+           <iconset resource="../Resources/SNAPResources.qrc">
+            <normaloff>:/root/revertaxis_16.png</normaloff>:/root/revertaxis_16.png</iconset>
+          </property>
+          <property name="iconSize">
+           <size>
+            <width>16</width>
+            <height>16</height>
+           </size>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item row="4" column="0">
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>Voxel Y Axis:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="5" column="0">
+      <widget class="QLabel" name="label_4">
+       <property name="text">
+        <string>Voxel Z Axis:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="7" column="2">
+      <widget class="QtVTKRenderWindowBox" name="iconNew" native="true">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>2</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>0</width>
+         <height>160</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>242</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="styleSheet">
+        <string notr="true">background:blue;</string>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="2">
+      <widget class="QWidget" name="widget_2" native="true">
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <property name="margin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QTableWidget" name="outMatrixNew">
+          <property name="minimumSize">
+           <size>
+            <width>242</width>
+            <height>98</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>242</width>
+            <height>98</height>
+           </size>
+          </property>
+          <property name="verticalScrollBarPolicy">
+           <enum>Qt::ScrollBarAlwaysOff</enum>
+          </property>
+          <property name="horizontalScrollBarPolicy">
+           <enum>Qt::ScrollBarAlwaysOff</enum>
+          </property>
+          <property name="editTriggers">
+           <set>QAbstractItemView::NoEditTriggers</set>
+          </property>
+          <attribute name="horizontalHeaderVisible">
+           <bool>false</bool>
+          </attribute>
+          <attribute name="horizontalHeaderDefaultSectionSize">
+           <number>60</number>
+          </attribute>
+          <attribute name="verticalHeaderVisible">
+           <bool>false</bool>
+          </attribute>
+          <attribute name="verticalHeaderDefaultSectionSize">
+           <number>24</number>
+          </attribute>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLabel" name="label_6">
+       <property name="text">
+        <string>Current Orientation:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="label_7">
+       <property name="text">
+        <string>New Orientation:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="7" column="1">
+      <widget class="QtVTKRenderWindowBox" name="iconCurrent" native="true">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>2</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>0</width>
+         <height>160</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>242</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="styleSheet">
+        <string notr="true">background:blue;</string>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="0">
+      <widget class="QLabel" name="label_5">
+       <property name="text">
+        <string><html><head/><body><p>Voxel to World <br/>Matrix (NIFTI):</p></body></html></string>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="0">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>Voxel X Axis:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="1">
+      <widget class="QWidget" name="widget_3" native="true">
+       <layout class="QHBoxLayout" name="horizontalLayout_3">
+        <property name="margin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QTableWidget" name="outMatrixCurrent">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Expanding" vsizetype="Maximum">
+            <horstretch>0</horstretch>
+            <verstretch>1</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="minimumSize">
+           <size>
+            <width>242</width>
+            <height>10</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>242</width>
+            <height>98</height>
+           </size>
+          </property>
+          <property name="verticalScrollBarPolicy">
+           <enum>Qt::ScrollBarAlwaysOff</enum>
+          </property>
+          <property name="horizontalScrollBarPolicy">
+           <enum>Qt::ScrollBarAlwaysOff</enum>
+          </property>
+          <property name="editTriggers">
+           <set>QAbstractItemView::NoEditTriggers</set>
+          </property>
+          <attribute name="horizontalHeaderVisible">
+           <bool>false</bool>
+          </attribute>
+          <attribute name="horizontalHeaderDefaultSectionSize">
+           <number>60</number>
+          </attribute>
+          <attribute name="verticalHeaderVisible">
+           <bool>false</bool>
+          </attribute>
+          <attribute name="verticalHeaderDefaultSectionSize">
+           <number>24</number>
+          </attribute>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QWidget" name="widget_5" native="true">
+       <layout class="QVBoxLayout" name="verticalLayout_3">
+        <property name="spacing">
+         <number>0</number>
+        </property>
+        <property name="margin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QLineEdit" name="outCurrentRAI">
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="verticalSpacer_2">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>0</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QWidget" name="widget_9" native="true">
+       <layout class="QVBoxLayout" name="verticalLayout_4">
+        <property name="spacing">
+         <number>0</number>
+        </property>
+        <property name="margin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QLabel" name="label_8">
+          <property name="text">
+           <string>RAI Code:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="verticalSpacer_3">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>0</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item row="8" column="2">
+      <widget class="QWidget" name="widget_10" native="true">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>99</verstretch>
+        </sizepolicy>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnApply">
+        <property name="text">
+         <string>Apply</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnClose">
+        <property name="text">
+         <string>Close</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QtVTKRenderWindowBox</class>
+   <extends>QWidget</extends>
+   <header location="global">QtVTKRenderWindowBox.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>inNewRAI</tabstop>
+  <tabstop>inNewAxisDirX</tabstop>
+  <tabstop>btnReverseX</tabstop>
+  <tabstop>inNewAxisDirY</tabstop>
+  <tabstop>btnReverseY</tabstop>
+  <tabstop>inNewAxisDirZ</tabstop>
+  <tabstop>btnReverseZ</tabstop>
+  <tabstop>btnApply</tabstop>
+  <tabstop>btnClose</tabstop>
+  <tabstop>outMatrixNew</tabstop>
+  <tabstop>outCurrentRAI</tabstop>
+  <tabstop>outCurrentAxisDirZ</tabstop>
+  <tabstop>outCurrentAxisDirY</tabstop>
+  <tabstop>outCurrentAxisDirX</tabstop>
+  <tabstop>outMatrixCurrent</tabstop>
+ </tabstops>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>btnClose</sender>
+   <signal>clicked()</signal>
+   <receiver>ReorientImageDialog</receiver>
+   <slot>hide()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>536</x>
+     <y>472</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>296</x>
+     <y>252</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/GUI/Qt/Windows/ResampleDialog.cxx b/GUI/Qt/Windows/ResampleDialog.cxx
new file mode 100644
index 0000000..c25d8e1
--- /dev/null
+++ b/GUI/Qt/Windows/ResampleDialog.cxx
@@ -0,0 +1,97 @@
+#include "ResampleDialog.h"
+#include "ui_ResampleDialog.h"
+#include "SnakeROIResampleModel.h"
+#include "QtDoubleSpinBoxCoupling.h"
+#include "QtWidgetArrayCoupling.h"
+#include "QtSpinBoxCoupling.h"
+#include "QtCheckBoxCoupling.h"
+#include "QtComboBoxCoupling.h"
+#include <QMenu>
+
+Q_DECLARE_METATYPE(SNAPSegmentationROISettings::InterpolationMethod)
+
+ResampleDialog::ResampleDialog(QWidget *parent) :
+  QDialog(parent),
+  ui(new Ui::ResampleDialog)
+{
+  ui->setupUi(this);
+
+  QMenu *menu = new QMenu(this);
+  menu->addAction(ui->actionSuper2);
+  menu->addAction(ui->actionSub2);
+  menu->addSeparator();
+  menu->addAction(ui->actionSuperIso);
+  menu->addAction(ui->actionSubIso);
+
+  ui->btnPreset->setMenu(menu);
+}
+
+ResampleDialog::~ResampleDialog()
+{
+  delete ui;
+}
+
+void ResampleDialog::SetModel(SnakeROIResampleModel *model)
+{
+  m_Model = model;
+
+  makeCoupling(ui->outInputXvox, model->GetInputSpacingModel(0));
+  makeCoupling(ui->outInputYvox, model->GetInputSpacingModel(1));
+  makeCoupling(ui->outInputZvox, model->GetInputSpacingModel(2));
+
+  makeCoupling(ui->outInputXsize, model->GetInputDimensionsModel(0));
+  makeCoupling(ui->outInputYsize, model->GetInputDimensionsModel(1));
+  makeCoupling(ui->outInputZsize, model->GetInputDimensionsModel(2));
+
+  makeCoupling(ui->inOutVoxelXvox, model->GetOutputSpacingModel(0));
+  makeCoupling(ui->inOutVoxelYvox, model->GetOutputSpacingModel(1));
+  makeCoupling(ui->inOutVoxelZvox, model->GetOutputSpacingModel(2));
+
+  makeCoupling(ui->inOutVoxelXsize, model->GetOutputDimensionsModel(0));
+  makeCoupling(ui->inOutVoxelYsize, model->GetOutputDimensionsModel(1));
+  makeCoupling(ui->inOutVoxelZsize, model->GetOutputDimensionsModel(2));
+
+  makeCoupling(ui->inInterpolationMode, model->GetInterpolationModeModel());
+
+  makeCoupling(ui->chkAspect, model->GetFixedAspectRatioModel());
+
+}
+
+void ResampleDialog::on_buttonBox_clicked(QAbstractButton *button)
+{
+  switch(ui->buttonBox->standardButton(button))
+    {
+    case QDialogButtonBox::Reset:
+      m_Model->Reset();
+      return;
+    case QDialogButtonBox::Ok:
+      m_Model->Accept();
+      this->accept();
+      return;
+    case QDialogButtonBox::Cancel:
+      this->reject();
+      return;
+    default:
+      return;
+    }
+}
+
+void ResampleDialog::on_actionSuper2_triggered()
+{
+  m_Model->ApplyPreset(SnakeROIResampleModel::SUPER_2);
+}
+
+void ResampleDialog::on_actionSub2_triggered()
+{
+  m_Model->ApplyPreset(SnakeROIResampleModel::SUB_2);
+}
+
+void ResampleDialog::on_actionSuperIso_triggered()
+{
+  m_Model->ApplyPreset(SnakeROIResampleModel::SUPER_ISO);
+}
+
+void ResampleDialog::on_actionSubIso_triggered()
+{
+  m_Model->ApplyPreset(SnakeROIResampleModel::SUB_ISO);
+}
diff --git a/GUI/Qt/Windows/ResampleDialog.h b/GUI/Qt/Windows/ResampleDialog.h
new file mode 100644
index 0000000..3dd67f6
--- /dev/null
+++ b/GUI/Qt/Windows/ResampleDialog.h
@@ -0,0 +1,40 @@
+#ifndef RESAMPLEDIALOG_H
+#define RESAMPLEDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class ResampleDialog;
+}
+
+class QAbstractButton;
+class SnakeROIResampleModel;
+
+class ResampleDialog : public QDialog
+{
+  Q_OBJECT
+  
+public:
+  explicit ResampleDialog(QWidget *parent = 0);
+  ~ResampleDialog();
+
+  void SetModel(SnakeROIResampleModel *model);
+
+private slots:
+  void on_buttonBox_clicked(QAbstractButton *button);
+
+  void on_actionSuper2_triggered();
+
+  void on_actionSub2_triggered();
+
+  void on_actionSuperIso_triggered();
+
+  void on_actionSubIso_triggered();
+
+private:
+  Ui::ResampleDialog *ui;
+
+  SnakeROIResampleModel *m_Model;
+};
+
+#endif // RESAMPLEDIALOG_H
diff --git a/GUI/Qt/Windows/ResampleDialog.ui b/GUI/Qt/Windows/ResampleDialog.ui
new file mode 100644
index 0000000..8935575
--- /dev/null
+++ b/GUI/Qt/Windows/ResampleDialog.ui
@@ -0,0 +1,463 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ResampleDialog</class>
+ <widget class="QDialog" name="ResampleDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>451</width>
+    <height>314</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Resample ROI - ITK-SNAP</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Segmentation ROI Resolution:</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QWidget" name="widget" native="true">
+        <layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0,1,0,1,0,1">
+         <property name="horizontalSpacing">
+          <number>6</number>
+         </property>
+         <property name="verticalSpacing">
+          <number>8</number>
+         </property>
+         <property name="margin">
+          <number>4</number>
+         </property>
+         <item row="4" column="3">
+          <widget class="QDoubleSpinBox" name="outInputZvox">
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+           <property name="readOnly">
+            <bool>true</bool>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="decimals">
+            <number>4</number>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="0">
+          <widget class="QLabel" name="label_4">
+           <property name="text">
+            <string>x:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="0">
+          <widget class="QLabel" name="label_5">
+           <property name="text">
+            <string>y:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="4" column="0">
+          <widget class="QLabel" name="label_6">
+           <property name="text">
+            <string>z:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="7">
+          <widget class="QDoubleSpinBox" name="inOutVoxelYvox">
+           <property name="focusPolicy">
+            <enum>Qt::WheelFocus</enum>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="keyboardTracking">
+            <bool>false</bool>
+           </property>
+           <property name="decimals">
+            <number>4</number>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="5">
+          <widget class="QLabel" name="label_10">
+           <property name="text">
+            <string>voxels</string>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="4" alignment="Qt::AlignHCenter">
+          <widget class="QLabel" name="label">
+           <property name="text">
+            <string/>
+           </property>
+           <property name="pixmap">
+            <pixmap resource="../Resources/SNAPResources.qrc">:/root/media-playback-start-4.png</pixmap>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="3">
+          <widget class="QDoubleSpinBox" name="outInputYvox">
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+           <property name="readOnly">
+            <bool>true</bool>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="decimals">
+            <number>4</number>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1" colspan="3" alignment="Qt::AlignHCenter">
+          <widget class="QLabel" name="label_12">
+           <property name="text">
+            <string>Input ROI</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="7">
+          <widget class="QDoubleSpinBox" name="inOutVoxelXvox">
+           <property name="focusPolicy">
+            <enum>Qt::WheelFocus</enum>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="keyboardTracking">
+            <bool>false</bool>
+           </property>
+           <property name="decimals">
+            <number>4</number>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="7">
+          <widget class="QLabel" name="label_11">
+           <property name="text">
+            <string>mm/voxel</string>
+           </property>
+          </widget>
+         </item>
+         <item row="4" column="7">
+          <widget class="QDoubleSpinBox" name="inOutVoxelZvox">
+           <property name="focusPolicy">
+            <enum>Qt::WheelFocus</enum>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="keyboardTracking">
+            <bool>false</bool>
+           </property>
+           <property name="decimals">
+            <number>4</number>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="2">
+          <widget class="QLabel" name="label_2">
+           <property name="text">
+            <string>*</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="3">
+          <widget class="QLabel" name="label_9">
+           <property name="text">
+            <string>mm/voxel</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QLabel" name="label_8">
+           <property name="text">
+            <string>voxels</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="5" colspan="3" alignment="Qt::AlignHCenter">
+          <widget class="QLabel" name="label_13">
+           <property name="text">
+            <string>Resampled ROI</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="6">
+          <widget class="QLabel" name="label_3">
+           <property name="text">
+            <string>*</string>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="2">
+          <widget class="QLabel" name="label_14">
+           <property name="text">
+            <string>*</string>
+           </property>
+          </widget>
+         </item>
+         <item row="4" column="2">
+          <widget class="QLabel" name="label_15">
+           <property name="text">
+            <string>*</string>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="6">
+          <widget class="QLabel" name="label_16">
+           <property name="text">
+            <string>*</string>
+           </property>
+          </widget>
+         </item>
+         <item row="4" column="6">
+          <widget class="QLabel" name="label_17">
+           <property name="text">
+            <string>*</string>
+           </property>
+          </widget>
+         </item>
+         <item row="5" column="5" colspan="3">
+          <widget class="QCheckBox" name="chkAspect">
+           <property name="text">
+            <string>Fixed voxel aspect ratio</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="1">
+          <widget class="QSpinBox" name="outInputXsize">
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+           <property name="readOnly">
+            <bool>true</bool>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="maximum">
+            <number>99999</number>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="1">
+          <widget class="QSpinBox" name="outInputYsize">
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+           <property name="readOnly">
+            <bool>true</bool>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="maximum">
+            <number>99999</number>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="3">
+          <widget class="QDoubleSpinBox" name="outInputXvox">
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+           <property name="readOnly">
+            <bool>true</bool>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="decimals">
+            <number>4</number>
+           </property>
+          </widget>
+         </item>
+         <item row="4" column="5">
+          <widget class="QSpinBox" name="inOutVoxelZsize">
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="keyboardTracking">
+            <bool>false</bool>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="5">
+          <widget class="QSpinBox" name="inOutVoxelYsize">
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="keyboardTracking">
+            <bool>false</bool>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="5">
+          <widget class="QSpinBox" name="inOutVoxelXsize">
+           <property name="focusPolicy">
+            <enum>Qt::WheelFocus</enum>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="keyboardTracking">
+            <bool>false</bool>
+           </property>
+          </widget>
+         </item>
+         <item row="4" column="1">
+          <widget class="QSpinBox" name="outInputZsize">
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+           <property name="readOnly">
+            <bool>true</bool>
+           </property>
+           <property name="buttonSymbols">
+            <enum>QAbstractSpinBox::NoButtons</enum>
+           </property>
+           <property name="maximum">
+            <number>99999</number>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_3" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="label_18">
+        <property name="text">
+         <string>Interpolation:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QComboBox" name="inInterpolationMode"/>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnPreset">
+        <property name="text">
+         <string>Presets</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_3">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_2" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QDialogButtonBox" name="buttonBox">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="standardButtons">
+         <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset</set>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+  <action name="actionSuper2">
+   <property name="text">
+    <string>Supersample by 2</string>
+   </property>
+  </action>
+  <action name="actionSub2">
+   <property name="text">
+    <string>Subsample by 2</string>
+   </property>
+  </action>
+  <action name="actionSuperIso">
+   <property name="text">
+    <string>Supersample to Isotropic</string>
+   </property>
+  </action>
+  <action name="actionSubIso">
+   <property name="text">
+    <string>Subsample to Isotropic</string>
+   </property>
+  </action>
+ </widget>
+ <tabstops>
+  <tabstop>inOutVoxelXsize</tabstop>
+  <tabstop>inOutVoxelXvox</tabstop>
+  <tabstop>inOutVoxelYsize</tabstop>
+  <tabstop>inOutVoxelYvox</tabstop>
+  <tabstop>inOutVoxelZsize</tabstop>
+  <tabstop>inOutVoxelZvox</tabstop>
+  <tabstop>chkAspect</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/SaveModifiedLayersDialog.cxx b/GUI/Qt/Windows/SaveModifiedLayersDialog.cxx
new file mode 100644
index 0000000..ba2ad1d
--- /dev/null
+++ b/GUI/Qt/Windows/SaveModifiedLayersDialog.cxx
@@ -0,0 +1,247 @@
+#include "SaveModifiedLayersDialog.h"
+#include "ui_SaveModifiedLayersDialog.h"
+#include "LatentITKEventNotifier.h"
+#include <QStandardItemModel>
+#include <QPushButton>
+#include "SaveModifiedLayersModel.h"
+#include "SNAPQtCommon.h"
+#include "ImageIOWizard.h"
+#include "QtAbstractItemViewCoupling.h"
+#include "QtWidgetActivator.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "IRISImageData.h"
+
+class QtSaveModifiedLayersInteractionDelegate
+    : public AbstractSaveModifiedLayersInteractionDelegate
+{
+public:
+
+  virtual bool SaveImageLayer(
+      GlobalUIModel *model, ImageWrapperBase *wrapper, LayerRole role)
+  {
+    return ::SaveImageLayer(model, wrapper, role);
+  }
+
+  virtual bool SaveProject(GlobalUIModel *model)
+  {
+    // TODO: passing NULL here makes this dialog unscriptable!
+    return ::SaveWorkspace(NULL, model, false, NULL);
+  }
+
+};
+
+
+SaveModifiedLayersDialog::SaveModifiedLayersDialog(QWidget *parent) :
+  QDialog(parent),
+  ui(new Ui::SaveModifiedLayersDialog)
+{
+  ui->setupUi(this);
+
+  // Give the dialog a name
+  this->setObjectName("dlgSaveModified");
+
+  // Resize the table to contents
+  ui->tableLayers->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
+  ui->tableLayers->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
+}
+
+SaveModifiedLayersDialog::~SaveModifiedLayersDialog()
+{
+  delete ui;
+}
+
+void SaveModifiedLayersDialog::SetModel(SaveModifiedLayersModel *model)
+{
+  // Save the model
+  m_Model = model;
+
+  // Listen to the events from the model
+  LatentITKEventNotifier::connect(m_Model, ModelUpdateEvent(),
+                                  this, SLOT(onModelUpdate(EventBucket)));
+
+  // Fill out
+  this->UpdateUnsavedTable();
+
+  // Couple the model to the list
+  makeCoupling((QAbstractItemView *) ui->tableLayers, m_Model->GetCurrentItemModel());
+
+  // Activate the save all button
+  activateOnFlag(ui->buttonBox->button(QDialogButtonBox::SaveAll),
+                 m_Model, SaveModifiedLayersModel::UIF_CAN_SAVE_ALL);
+
+  // Activate the save all button
+  activateOnFlag(ui->buttonBox->button(QDialogButtonBox::Save),
+                 m_Model, SaveModifiedLayersModel::UIF_CAN_SAVE_CURRENT);
+}
+
+void SaveModifiedLayersDialog::SetOptions(PromptOptions opts)
+{
+  // Toggle the discard button
+  ui->buttonBox->button(QDialogButtonBox::Discard)->setEnabled(
+        !opts.testFlag(DiscardDisabled));
+}
+
+bool SaveModifiedLayersDialog
+::PromptForUnsavedChanges(GlobalUIModel *model, PromptOptions opts, QWidget *parent)
+{
+  // Call internal method with empty list
+  std::list<ImageWrapperBase *> layerlist;
+  return PromptForUnsavedChangesInternal(model, layerlist, opts, parent);
+}
+
+bool
+SaveModifiedLayersDialog
+::PromptForUnsavedChanges(
+    GlobalUIModel *model, ImageWrapperBase *singleLayer,
+    PromptOptions opts, QWidget *parent)
+{
+  std::list<ImageWrapperBase *> layerlist;
+  layerlist.push_back(singleLayer);
+
+  // Show the dialog
+  return PromptForUnsavedChangesInternal(model, layerlist, opts, parent);
+}
+
+bool SaveModifiedLayersDialog
+::PromptForUnsavedChangesInternal(
+    GlobalUIModel *model,
+    std::list<ImageWrapperBase *> layers,
+    PromptOptions opts,
+    QWidget *parent)
+{
+  // Create a callback delegate
+  QtSaveModifiedLayersInteractionDelegate cb_delegate;
+
+  // Create and configure the model
+  SmartPtr<SaveModifiedLayersModel> saveModel = SaveModifiedLayersModel::New();
+  saveModel->Initialize(model, layers);
+  saveModel->SetUIDelegate(&cb_delegate);
+
+  // Check if there is anything to save
+  if(saveModel->GetUnsavedItems().size() == 0)
+    return true;
+
+  // Configure the dialog
+  SaveModifiedLayersDialog *dialog = new SaveModifiedLayersDialog(parent);
+  dialog->SetModel(saveModel);
+  dialog->setModal(true);
+  dialog->SetOptions(opts);
+
+  // Show the dialog
+  return (dialog->exec() == QDialog::Accepted);
+}
+
+bool SaveModifiedLayersDialog
+::PromptForUnsavedChanges(GlobalUIModel *model, int role_filter, PromptOptions opts, QWidget *parent)
+{
+  LayerIterator it = model->GetDriver()->GetIRISImageData()->GetLayers(role_filter);
+  std::list<ImageWrapperBase *> layers;
+  for(; !it.IsAtEnd(); ++it)
+    layers.push_back(it.GetLayer());
+
+  return PromptForUnsavedChangesInternal(model, layers, opts, parent);
+}
+
+bool
+SaveModifiedLayersDialog
+::PromptForUnsavedSegmentationChanges(GlobalUIModel *model)
+{
+  ImageWrapperBase *layer = model->GetDriver()->GetIRISImageData()->GetSegmentation();
+  return PromptForUnsavedChanges(model, layer);
+}
+
+void SaveModifiedLayersDialog::onModelUpdate(const EventBucket &bucket)
+{
+  // We need to update the table
+  UpdateUnsavedTable();
+}
+
+void SaveModifiedLayersDialog::UpdateUnsavedTable()
+{
+  typedef SaveModifiedLayersModel::SaveableItemPtrArray ItemArray;
+  typedef ItemArray::const_iterator ItemIterator;
+
+  // Make sure the model updates
+  m_Model->Update();
+
+  // Get the items
+  const ItemArray &items = m_Model->GetUnsavedItems();
+
+  // Create a standard item model for unsaved items
+  QStandardItemModel *qsim = new QStandardItemModel(ui->tableLayers);
+  qsim->setColumnCount(2);
+  qsim->setHorizontalHeaderItem(0, new QStandardItem("Unsaved Item"));
+  qsim->setHorizontalHeaderItem(1, new QStandardItem("Filename"));
+
+  // Add entries for all the items
+  for(int i = 0; i < items.size(); i++)
+    {
+    AbstractSaveableItem *unsaved = items[i];
+    if(unsaved->NeedsDecision())
+      {
+      QList<QStandardItem *> row;
+
+      // The first column
+      row.append(new QStandardItem(from_utf8(unsaved->GetDescription())));
+      row.back()->setData(unsaved->GetId(), Qt::UserRole);
+
+      if(unsaved->GetFilename().size())
+        row.append(new QStandardItem(from_utf8(unsaved->GetFilename())));
+      else
+        row.append(new QStandardItem("Not assigned"));
+
+      qsim->appendRow(row);
+      }
+    }
+
+  // If there are no more rows to add, we are done with the dialog
+  if(qsim->rowCount() == 0)
+    this->accept();
+
+  // Before setting the contents, we need to check what's the selected item
+  // because the coupling is going to change that. This is actually a bit of
+  // an issue with the way we are using tables and couplings right now.
+  int item = m_Model->GetCurrentItem();
+
+  // Qt docs say to manually discard the selection model
+  QItemSelectionModel *selm = ui->tableLayers->selectionModel();
+
+  // Set the table contents
+  ui->tableLayers->setModel(qsim);
+
+  // Qt docs say to manually discard the selection model
+  delete selm;
+
+  // Update the current item - might have changed
+  m_Model->SetCurrentItem(item);
+}
+
+
+
+void SaveModifiedLayersDialog::on_buttonBox_clicked(QAbstractButton *button)
+{
+  // Save selected item
+  if(button == ui->buttonBox->button(QDialogButtonBox::Save))
+    {
+    // If the item has a filename, save it as is. If it does not, save it via
+    // its wizard. The trouble is, the wizard needs to know about the item, so
+    // this is not so simple.
+    m_Model->SaveCurrent();
+    }
+  else if(button == ui->buttonBox->button(QDialogButtonBox::Discard))
+    {
+    // Discard the changes to this image.
+    m_Model->DiscardCurrent();
+    }
+  else if(button == ui->buttonBox->button(QDialogButtonBox::SaveAll))
+    {
+    // Cancel out the dialog.
+    m_Model->SaveAll();
+    }
+  else if(button == ui->buttonBox->button(QDialogButtonBox::Cancel))
+    {
+    // Cancel out the dialog.
+    this->reject();
+    }
+}
diff --git a/GUI/Qt/Windows/SaveModifiedLayersDialog.h b/GUI/Qt/Windows/SaveModifiedLayersDialog.h
new file mode 100644
index 0000000..4cb5252
--- /dev/null
+++ b/GUI/Qt/Windows/SaveModifiedLayersDialog.h
@@ -0,0 +1,96 @@
+#ifndef SAVEMODIFIEDLAYERSDIALOG_H
+#define SAVEMODIFIEDLAYERSDIALOG_H
+
+#include <QDialog>
+#include "SNAPCommon.h"
+
+namespace Ui {
+class SaveModifiedLayersDialog;
+}
+
+class SaveModifiedLayersModel;
+class EventBucket;
+class GlobalUIModel;
+class QAbstractButton;
+class ImageWrapperBase;
+
+class SaveModifiedLayersDialog : public QDialog
+{
+  Q_OBJECT
+  
+public:
+  explicit SaveModifiedLayersDialog(QWidget *parent = 0);
+  ~SaveModifiedLayersDialog();
+
+  void SetModel(SaveModifiedLayersModel *model);
+
+  /**
+   * Flags affecting the dialog's behavior
+   */
+  enum PromptOption
+  {
+    NoOption = 0x00,
+    DiscardDisabled = 0x01,
+    ProjectsDisabled = 0x02
+  };
+
+  Q_DECLARE_FLAGS(PromptOptions, PromptOption)
+
+  void SetOptions(PromptOptions opts);
+
+  /**
+   * This static method prompts user to save unsaved changes to all the layers,
+   * and return true if the user indicated that he/she wishes to proceed with
+   * the subsequent operation.
+   *
+   * With only the first parameter passed (the model), the function creates a
+   * dialog appropriate when the main layer is being closed, i.e., when the
+   * user presses quit. It shows all unsaved layers as well as the workspace
+   * if it exists and is unsaved.
+   */
+  static bool PromptForUnsavedChanges(GlobalUIModel *model,
+                                      PromptOptions opts = NoOption,
+                                      QWidget *parent = NULL);
+
+  /**
+   * This version of the method requests changes to a specific set of layers,
+   * e.g., to save all overlays
+   */
+  static bool PromptForUnsavedChanges(GlobalUIModel *model,
+                                      int role_filter,
+                                      PromptOptions opts = NoOption,
+                                      QWidget *parent = NULL);
+
+  /** A version of the method that takes a single specific image layer */
+  static bool PromptForUnsavedChanges(GlobalUIModel *model,
+                                      ImageWrapperBase *singleLayer,
+                                      PromptOptions opts = NoOption,
+                                      QWidget *parent = NULL);
+
+
+  static bool PromptForUnsavedSegmentationChanges(GlobalUIModel *model);
+
+
+
+private slots:
+
+  void onModelUpdate(const EventBucket &bucket);
+  
+  void on_buttonBox_clicked(QAbstractButton *button);
+
+private:
+  Ui::SaveModifiedLayersDialog *ui;
+
+  SaveModifiedLayersModel *m_Model;
+
+  void UpdateUnsavedTable();
+
+  static bool PromptForUnsavedChangesInternal(GlobalUIModel *model,
+                                              std::list<ImageWrapperBase *> layers,
+                                              PromptOptions opts = NoOption,
+                                              QWidget *parent = NULL);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(SaveModifiedLayersDialog::PromptOptions)
+
+#endif // SAVEMODIFIEDLAYERSDIALOG_H
diff --git a/GUI/Qt/Windows/SaveModifiedLayersDialog.ui b/GUI/Qt/Windows/SaveModifiedLayersDialog.ui
new file mode 100644
index 0000000..329df09
--- /dev/null
+++ b/GUI/Qt/Windows/SaveModifiedLayersDialog.ui
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SaveModifiedLayersDialog</class>
+ <widget class="QDialog" name="SaveModifiedLayersDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>499</width>
+    <height>242</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Save Changes - ITK-SNAP</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>The following image layers have unsaved changes:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTableView" name="tableLayers">
+     <property name="editTriggers">
+      <set>QAbstractItemView::NoEditTriggers</set>
+     </property>
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="selectionMode">
+      <enum>QAbstractItemView::SingleSelection</enum>
+     </property>
+     <property name="selectionBehavior">
+      <enum>QAbstractItemView::SelectRows</enum>
+     </property>
+     <attribute name="horizontalHeaderStretchLastSection">
+      <bool>true</bool>
+     </attribute>
+     <attribute name="verticalHeaderVisible">
+      <bool>false</bool>
+     </attribute>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Discard|QDialogButtonBox::Save|QDialogButtonBox::SaveAll</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/SimpleFileDialogWithHistory.cxx b/GUI/Qt/Windows/SimpleFileDialogWithHistory.cxx
new file mode 100644
index 0000000..df5918d
--- /dev/null
+++ b/GUI/Qt/Windows/SimpleFileDialogWithHistory.cxx
@@ -0,0 +1,73 @@
+#include "SimpleFileDialogWithHistory.h"
+#include "ui_SimpleFileDialogWithHistory.h"
+#include "FileChooserPanelWithHistory.h"
+
+#include "SNAPQtCommon.h"
+
+SimpleFileDialogWithHistory::SimpleFileDialogWithHistory(QWidget *parent) :
+  QDialog(parent),
+  ui(new Ui::SimpleFileDialogWithHistory)
+{
+  // Set an object name for scripting
+  this->setObjectName("dlgSimpleFile");
+
+  ui->setupUi(this);
+
+  // Connect up
+  connect(this, SIGNAL(accepted()), ui->filePanel, SLOT(onFilenameAccept()));
+}
+
+SimpleFileDialogWithHistory::~SimpleFileDialogWithHistory()
+{
+  delete ui;
+}
+
+QString
+SimpleFileDialogWithHistory
+::showOpenDialog(QWidget *parent,
+                 GlobalUIModel *model,
+                 QString window_title,
+                 QString file_title,
+                 QString history_name,
+                 QString file_pattern, QString init_file)
+{
+  // Configure the dialog
+  SimpleFileDialogWithHistory *dialog = new SimpleFileDialogWithHistory(parent);
+  dialog->ui->filePanel->initializeForOpenFile(model, file_title, history_name, file_pattern, init_file);
+  dialog->setWindowTitle(window_title);
+
+  // Launch the dialog
+  if(dialog->exec() == QDialog::Accepted)
+    {
+    return dialog->ui->filePanel->absoluteFilename();
+    }
+  else return QString();
+}
+
+#include <QMessageBox>
+
+QString
+SimpleFileDialogWithHistory
+::showSaveDialog(QWidget *parent, GlobalUIModel *model,
+                 QString window_title,
+                 QString file_title,
+                 QString history_name,
+                 QString file_pattern, bool force_extension,
+                 QString init_file)
+{
+  // Configure the dialog
+  SimpleFileDialogWithHistory *dialog = new SimpleFileDialogWithHistory(parent);
+  dialog->setWindowTitle(window_title);
+  dialog->ui->filePanel->initializeForSaveFile(model, file_title, history_name, file_pattern,
+                                               force_extension, init_file);
+
+  // Launch the dialog
+  if(dialog->exec() == QDialog::Accepted)
+    {
+    return dialog->ui->filePanel->absoluteFilename();
+    }
+  else return QString();
+}
+
+
+
diff --git a/GUI/Qt/Windows/SimpleFileDialogWithHistory.h b/GUI/Qt/Windows/SimpleFileDialogWithHistory.h
new file mode 100644
index 0000000..f242ed7
--- /dev/null
+++ b/GUI/Qt/Windows/SimpleFileDialogWithHistory.h
@@ -0,0 +1,47 @@
+#ifndef SIMPLEFILEDIALOGWITHHISTORY_H
+#define SIMPLEFILEDIALOGWITHHISTORY_H
+
+#include <QDialog>
+
+namespace Ui {
+class SimpleFileDialogWithHistory;
+}
+
+class GlobalUIModel;
+
+class SimpleFileDialogWithHistory : public QDialog
+{
+  Q_OBJECT
+  
+public:
+
+  static QString showOpenDialog(
+      QWidget *parent,
+      GlobalUIModel *model,
+      QString window_title,
+      QString file_title,
+      QString history_name,
+      QString file_pattern,
+      QString init_file = QString());
+  
+  static QString showSaveDialog(
+      QWidget *parent,
+      GlobalUIModel *model,
+      QString window_title, QString file_title,
+      QString history_name,
+      QString file_pattern,
+      bool force_extension,
+      QString init_file = QString());
+
+protected:
+
+  // Constructor is protected, use static methods to launch
+  explicit SimpleFileDialogWithHistory(QWidget *parent = 0);
+  ~SimpleFileDialogWithHistory();
+
+private:
+  Ui::SimpleFileDialogWithHistory *ui;
+
+};
+
+#endif // SIMPLEFILEDIALOGWITHHISTORY_H
diff --git a/GUI/Qt/Windows/SimpleFileDialogWithHistory.ui b/GUI/Qt/Windows/SimpleFileDialogWithHistory.ui
new file mode 100644
index 0000000..c1c15d9
--- /dev/null
+++ b/GUI/Qt/Windows/SimpleFileDialogWithHistory.ui
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SimpleFileDialogWithHistory</class>
+ <widget class="QDialog" name="SimpleFileDialogWithHistory">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>208</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QMenu {
+font-size:12px;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="FileChooserPanelWithHistory" name="filePanel" native="true"/>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>FileChooserPanelWithHistory</class>
+   <extends>QWidget</extends>
+   <header>FileChooserPanelWithHistory.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>SimpleFileDialogWithHistory</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>254</x>
+     <y>154</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>SimpleFileDialogWithHistory</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>322</x>
+     <y>154</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/GUI/Qt/Windows/SnakeParameterDialog.cxx b/GUI/Qt/Windows/SnakeParameterDialog.cxx
new file mode 100644
index 0000000..c96ac60
--- /dev/null
+++ b/GUI/Qt/Windows/SnakeParameterDialog.cxx
@@ -0,0 +1,218 @@
+#include "SnakeParameterDialog.h"
+#include "ui_SnakeParameterDialog.h"
+#include "SnakeParameterModel.h"
+#include "QtWidgetCoupling.h"
+#include "QtCheckBoxCoupling.h"
+#include "QtSliderCoupling.h"
+#include "QtSpinBoxCoupling.h"
+#include "QtDoubleSpinBoxCoupling.h"
+#include "SnakeParameterPreviewRenderer.h"
+#include "SnakeParametersPreviewPipeline.h"
+#include "SNAPQtCommon.h"
+#include <QTimer>
+#include <QPushButton>
+
+SnakeParameterDialog::SnakeParameterDialog(QWidget *parent) :
+  QDialog(parent),
+  ui(new Ui::SnakeParameterDialog)
+{
+  ui->setupUi(this);
+
+  // Set up the preview renderers
+  for(int i = 0; i < 4; i++)
+    {
+    m_PreviewRenderer[i] = SnakeParameterPreviewRenderer::New();
+    m_PreviewRenderer[i]->SetForceToDisplay(
+          static_cast<SnakeParameterPreviewRenderer::DisplayMode>(i));
+    }
+
+  ui->boxForceAlpha->SetRenderer(m_PreviewRenderer[0]);
+  ui->boxForceBeta->SetRenderer(m_PreviewRenderer[1]);
+  ui->boxForceGamma->SetRenderer(m_PreviewRenderer[2]);
+  ui->boxForceTotal->SetRenderer(m_PreviewRenderer[3]);
+
+  m_AnimationTimer = new QTimer(this);
+  connect(m_AnimationTimer, SIGNAL(timeout()), SLOT(onAnimationTimer()));
+}
+
+SnakeParameterDialog::~SnakeParameterDialog()
+{
+  delete ui;
+}
+
+void SnakeParameterDialog::SetModel(SnakeParameterModel *model)
+{
+  this->m_Model = model;
+
+
+  // Couple all of the spin boxes
+  makeCoupling(ui->inZhuAlphaSimple, m_Model->GetWeightModel(SnakeParameterModel::ALHPA));
+  makeCoupling(ui->inZhuAlphaSimpleSlider, m_Model->GetWeightModel(SnakeParameterModel::ALHPA));
+  makeCoupling(ui->inZhuBetaSimple, m_Model->GetWeightModel(SnakeParameterModel::BETA));
+  makeCoupling(ui->inZhuBetaSimpleSlider, m_Model->GetWeightModel(SnakeParameterModel::BETA));
+
+  makeCoupling(ui->inCasellesAlphaSimple, m_Model->GetWeightModel(SnakeParameterModel::ALHPA));
+  makeCoupling(ui->inCasellesAlphaSimpleSlider, m_Model->GetWeightModel(SnakeParameterModel::ALHPA));
+  makeCoupling(ui->inCasellesBetaSimple, m_Model->GetWeightModel(SnakeParameterModel::BETA));
+  makeCoupling(ui->inCasellesBetaSimpleSlider, m_Model->GetWeightModel(SnakeParameterModel::BETA));
+  makeCoupling(ui->inCasellesGammaSimple, m_Model->GetWeightModel(SnakeParameterModel::GAMMA));
+  makeCoupling(ui->inCasellesGammaSimpleSlider, m_Model->GetWeightModel(SnakeParameterModel::GAMMA));
+
+  makeCoupling(ui->inAlphaMath, m_Model->GetWeightModel(SnakeParameterModel::ALHPA));
+  makeCoupling(ui->inAlphaMathSlider, m_Model->GetWeightModel(SnakeParameterModel::ALHPA));
+  makeCoupling(ui->inBetaMath, m_Model->GetWeightModel(SnakeParameterModel::BETA));
+  makeCoupling(ui->inBetaMathSlider, m_Model->GetWeightModel(SnakeParameterModel::BETA));
+  makeCoupling(ui->inGammaMath, m_Model->GetWeightModel(SnakeParameterModel::GAMMA));
+  makeCoupling(ui->inGammaMathSlider, m_Model->GetWeightModel(SnakeParameterModel::GAMMA));
+  makeCoupling(ui->inAlphaExp, m_Model->GetExponentModel(SnakeParameterModel::ALHPA));
+  makeCoupling(ui->inBetaExp, m_Model->GetExponentModel(SnakeParameterModel::BETA));
+  makeCoupling(ui->inGammaExp, m_Model->GetExponentModel(SnakeParameterModel::GAMMA));
+
+  makeCoupling(ui->inSpeedup, m_Model->GetSpeedupFactorModel());
+  makeCoupling(ui->inSpeedupSlider, m_Model->GetSpeedupFactorModel());
+
+  // Couple the advanced checkbox
+  makeCoupling(ui->chkAdvanced, m_Model->GetAdvancedEquationModeModel());
+
+  // Couple the animation checkbutton to the corresponding model. In addition
+  // register to receive events from the model, so we can toggle the timer that
+  // does the actual animation
+  makeCoupling(ui->chkAnimate, m_Model->GetAnimateDemoModel());
+  LatentITKEventNotifier::connect(
+        m_Model->GetAnimateDemoModel(), ValueChangedEvent(),
+        this, SLOT(onModelUpdate(EventBucket)));
+
+  // Fix the visibility of the widgets that depend on what snake mode we're in
+  makeWidgetVisibilityCoupling(ui->inAlphaExp, m_Model->GetAdvancedEquationModeModel());
+  makeWidgetVisibilityCoupling(ui->inBetaExp, m_Model->GetAdvancedEquationModeModel());
+  makeWidgetVisibilityCoupling(ui->lblAlphaExp, m_Model->GetAdvancedEquationModeModel());
+  makeWidgetVisibilityCoupling(ui->lblBetaExp, m_Model->GetAdvancedEquationModeModel());
+  makeWidgetVisibilityCoupling(ui->inGammaExp, m_Model->GetAdvancedEquationModeModel());
+  makeWidgetVisibilityCoupling(ui->lblGammaExp, m_Model->GetAdvancedEquationModeModel());
+
+  makeWidgetVisibilityCoupling(ui->inGammaMath, m_Model->GetCasellesOrAdvancedModeModel());
+  makeWidgetVisibilityCoupling(ui->inGammaMathSlider, m_Model->GetCasellesOrAdvancedModeModel());
+  makeWidgetVisibilityCoupling(ui->lblGammaMath, m_Model->GetCasellesOrAdvancedModeModel());
+
+  makeWidgetVisibilityCoupling(ui->boxForceGamma, m_Model->GetCasellesOrAdvancedModeModel());
+
+  // Set up the preview renderers
+  for(int i = 0; i < 4; i++)
+    {
+    m_PreviewRenderer[i]->SetModel(m_Model);
+    }
+
+  // React to parameter update events
+  LatentITKEventNotifier::connect(m_Model, ModelUpdateEvent(),
+                                  this, SLOT(onModelUpdate(const EventBucket &)));
+}
+
+void SnakeParameterDialog::onModelUpdate(const EventBucket &bucket)
+{
+  // Handle updates from the model
+  if(bucket.HasEvent(ModelUpdateEvent()))
+    {
+    // Advanced mode
+    bool advanced = m_Model->GetAdvancedEquationModeModel()->GetValue();
+
+    // Update the state of the GUI not handled by the couplings
+    if(m_Model->IsRegionSnake())
+      {
+      ui->stackIntuitive->setCurrentWidget(ui->pageZhu);
+      if(!advanced)
+        {
+        ui->stackEqn->setCurrentWidget(ui->pageEqnZhu);
+        }
+      ui->lblForceAlpha->setText("Region Competition");
+      }
+    else
+      {
+      ui->stackIntuitive->setCurrentWidget(ui->pageCaselles);
+      if(!advanced)
+        {
+        ui->stackEqn->setCurrentWidget(ui->pageEqnCaselles);
+        }
+      ui->lblForceAlpha->setText("Balloon Force");
+      }
+
+    // Update the formula
+    if(advanced)
+      {
+      ui->stackEqn->setCurrentWidget(ui->pageEqnAdvanced);
+      }
+    }
+
+  // Handle animation state changes
+  if(bucket.HasEvent(ValueChangedEvent(), m_Model->GetAnimateDemoModel()))
+    {
+    bool animate = m_Model->GetAnimateDemo();
+    if(animate && !m_AnimationTimer->isActive())
+      {
+      m_AnimationTimer->start(100);
+      }
+    else if(!animate && m_AnimationTimer->isActive())
+      {
+      m_Model->ResetAnimation();
+      m_AnimationTimer->stop();
+      }
+    }
+}
+
+void SnakeParameterDialog::onAnimationTimer()
+{
+  m_Model->PerformAnimationStep();
+}
+
+void SnakeParameterDialog::on_btnRestore_clicked()
+{
+  m_Model->RestoreDefaults();
+}
+
+void SnakeParameterDialog::on_btnOpen_clicked()
+{
+  // Ask for a filename
+  QString selection = ShowSimpleOpenDialogWithHistory(
+        this, m_Model->GetParentModel(), "SnakeParameters",
+        "Open Active Contour Evolution Parameters - ITK-SNAP",
+        "Parameter File",
+        "Text Files (*.txt)");
+
+  // Open the labels from the selection
+  if(selection.length())
+    {
+    try
+      {
+      m_Model->LoadParameters(to_utf8(selection));
+      }
+    catch(std::exception &exc)
+      {
+      ReportNonLethalException(this, exc, "Parameter File IO Error",
+                               QString("Failed to load parameters"));
+      }
+    }
+}
+
+void SnakeParameterDialog::on_btnSave_clicked()
+{
+  // Ask for a filename
+  QString selection = ShowSimpleSaveDialogWithHistory(
+        this, m_Model->GetParentModel(), "SnakeParameters",
+        "Save Active Contour Evolution Parameters - ITK-SNAP",
+        "Parameter File",
+        "Text Files (*.txt)",
+        true);
+
+  // Open the labels from the selection
+  if(selection.length())
+    {
+    try
+      {
+      m_Model->SaveParameters(to_utf8(selection));
+      }
+    catch(std::exception &exc)
+      {
+      ReportNonLethalException(this, exc, "Parameter File IO Error",
+                               QString("Failed to save parameters"));
+      }
+    }
+}
diff --git a/GUI/Qt/Windows/SnakeParameterDialog.h b/GUI/Qt/Windows/SnakeParameterDialog.h
new file mode 100644
index 0000000..de355c2
--- /dev/null
+++ b/GUI/Qt/Windows/SnakeParameterDialog.h
@@ -0,0 +1,46 @@
+#ifndef SNAKEPARAMETERDIALOG_H
+#define SNAKEPARAMETERDIALOG_H
+
+#include <QDialog>
+#include <SNAPCommon.h>
+
+namespace Ui {
+class SnakeParameterDialog;
+}
+
+class SnakeParameterModel;
+class EventBucket;
+class SnakeParameterPreviewRenderer;
+class QTimer;
+
+class SnakeParameterDialog : public QDialog
+{
+  Q_OBJECT
+  
+public:
+  explicit SnakeParameterDialog(QWidget *parent = 0);
+  ~SnakeParameterDialog();
+
+  void SetModel(SnakeParameterModel *model);
+  
+public slots:
+
+  void onModelUpdate(const EventBucket &bucket);
+  void onAnimationTimer();
+
+private slots:
+
+  void on_btnRestore_clicked();
+  void on_btnOpen_clicked();
+  void on_btnSave_clicked();
+
+private:
+  Ui::SnakeParameterDialog *ui;
+
+  SnakeParameterModel *m_Model;
+  SmartPtr<SnakeParameterPreviewRenderer> m_PreviewRenderer[4];
+
+  QTimer *m_AnimationTimer;
+};
+
+#endif // SNAKEPARAMETERDIALOG_H
diff --git a/GUI/Qt/Windows/SnakeParameterDialog.ui b/GUI/Qt/Windows/SnakeParameterDialog.ui
new file mode 100644
index 0000000..9eef3a6
--- /dev/null
+++ b/GUI/Qt/Windows/SnakeParameterDialog.ui
@@ -0,0 +1,1019 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SnakeParameterDialog</class>
+ <widget class="QDialog" name="SnakeParameterDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>717</width>
+    <height>451</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Active Contour Evolution Parameters - ITK-SNAP</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <property name="bottomMargin">
+    <number>8</number>
+   </property>
+   <property name="verticalSpacing">
+    <number>8</number>
+   </property>
+   <item row="0" column="1">
+    <widget class="QGroupBox" name="groupBox">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>320</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">font-size:11px;</string>
+     </property>
+     <property name="title">
+      <string>Conceptual Illustration of Forces in 2D</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_10" rowstretch="0,1,0,0,1,0">
+      <property name="margin">
+       <number>4</number>
+      </property>
+      <property name="spacing">
+       <number>4</number>
+      </property>
+      <item row="0" column="0" alignment="Qt::AlignHCenter">
+       <widget class="QLabel" name="lblForceAlpha">
+        <property name="text">
+         <string>Region Competition</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1" alignment="Qt::AlignHCenter">
+       <widget class="QLabel" name="lblForceBeta">
+        <property name="text">
+         <string>Smoothing</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="0" alignment="Qt::AlignHCenter">
+       <widget class="QLabel" name="label_9">
+        <property name="text">
+         <string>Edge Attraction</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="1" alignment="Qt::AlignHCenter">
+       <widget class="QLabel" name="label_11">
+        <property name="text">
+         <string>Combined Force</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QFrame" name="frame">
+        <property name="frameShape">
+         <enum>QFrame::Box</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Plain</enum>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_9">
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QtSimpleOpenGLBox" name="boxForceAlpha" native="true">
+           <property name="styleSheet">
+            <string notr="true">border:1px black solid;</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QFrame" name="frame_2">
+        <property name="frameShape">
+         <enum>QFrame::Box</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Plain</enum>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_10">
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QtSimpleOpenGLBox" name="boxForceBeta" native="true">
+           <property name="styleSheet">
+            <string notr="true">border:1px black solid;</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item row="4" column="0">
+       <widget class="QFrame" name="frame_3">
+        <property name="frameShape">
+         <enum>QFrame::Box</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Plain</enum>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_11">
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QtSimpleOpenGLBox" name="boxForceGamma" native="true">
+           <property name="styleSheet">
+            <string notr="true">border:1px black solid;</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item row="4" column="1">
+       <widget class="QFrame" name="frame_4">
+        <property name="frameShape">
+         <enum>QFrame::Box</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Plain</enum>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_12">
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QtSimpleOpenGLBox" name="boxForceTotal" native="true">
+           <property name="styleSheet">
+            <string notr="true">border:1px black solid;</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item row="5" column="0" colspan="2" alignment="Qt::AlignRight">
+       <widget class="QWidget" name="widget" native="true">
+        <property name="minimumSize">
+         <size>
+          <width>0</width>
+          <height>20</height>
+         </size>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <property name="margin">
+          <number>2</number>
+         </property>
+         <item>
+          <widget class="QCheckBox" name="chkAnimate">
+           <property name="text">
+            <string>Animate</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="0" column="0">
+    <widget class="QTabWidget" name="tabWidget">
+     <property name="maximumSize">
+      <size>
+       <width>357</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="tab">
+      <attribute name="title">
+       <string>Intuitive Mode</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_4">
+       <property name="leftMargin">
+        <number>4</number>
+       </property>
+       <property name="topMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>4</number>
+       </property>
+       <property name="bottomMargin">
+        <number>4</number>
+       </property>
+       <item>
+        <widget class="QStackedWidget" name="stackIntuitive">
+         <property name="currentIndex">
+          <number>0</number>
+         </property>
+         <widget class="QWidget" name="pageZhu">
+          <layout class="QVBoxLayout" name="verticalLayout_6">
+           <property name="margin">
+            <number>0</number>
+           </property>
+           <item>
+            <widget class="QGroupBox" name="groupBox_2">
+             <property name="title">
+              <string>Region competition force:</string>
+             </property>
+             <layout class="QGridLayout" name="gridLayout_2">
+              <property name="leftMargin">
+               <number>4</number>
+              </property>
+              <property name="topMargin">
+               <number>6</number>
+              </property>
+              <property name="rightMargin">
+               <number>4</number>
+              </property>
+              <property name="bottomMargin">
+               <number>4</number>
+              </property>
+              <item row="0" column="0" colspan="2">
+               <widget class="QLabel" name="label">
+                <property name="styleSheet">
+                 <string notr="true">font-size:11px;</string>
+                </property>
+                <property name="text">
+                 <string>Pushes the contour inwards or outwards, modulated by the sign and value of the speed image.</string>
+                </property>
+                <property name="wordWrap">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="0">
+               <widget class="QDoubleSpinBox" name="inZhuAlphaSimple"/>
+              </item>
+              <item row="1" column="1">
+               <widget class="QDoubleSlider" name="inZhuAlphaSimpleSlider">
+                <property name="maximum">
+                 <number>100</number>
+                </property>
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="tickPosition">
+                 <enum>QSlider::TicksBelow</enum>
+                </property>
+                <property name="tickInterval">
+                 <number>25</number>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_3">
+             <property name="title">
+              <string>Smoothing (curvature) force:</string>
+             </property>
+             <layout class="QGridLayout" name="gridLayout_3">
+              <property name="leftMargin">
+               <number>4</number>
+              </property>
+              <property name="topMargin">
+               <number>6</number>
+              </property>
+              <property name="rightMargin">
+               <number>4</number>
+              </property>
+              <property name="bottomMargin">
+               <number>4</number>
+              </property>
+              <item row="0" column="0" colspan="2">
+               <widget class="QLabel" name="label_2">
+                <property name="styleSheet">
+                 <string notr="true">font-size:11px;</string>
+                </property>
+                <property name="text">
+                 <string>Makes the contour boundary smoother and can prevent the contour from leaking into narrow objects such as vessels.</string>
+                </property>
+                <property name="wordWrap">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="0">
+               <widget class="QDoubleSpinBox" name="inZhuBetaSimple"/>
+              </item>
+              <item row="1" column="1">
+               <widget class="QDoubleSlider" name="inZhuBetaSimpleSlider">
+                <property name="maximum">
+                 <number>100</number>
+                </property>
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="tickPosition">
+                 <enum>QSlider::TicksBelow</enum>
+                </property>
+                <property name="tickInterval">
+                 <number>25</number>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <spacer name="verticalSpacer">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>40</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
+         <widget class="QWidget" name="pageCaselles">
+          <layout class="QVBoxLayout" name="verticalLayout_7">
+           <property name="margin">
+            <number>0</number>
+           </property>
+           <item>
+            <widget class="QGroupBox" name="groupBox_5">
+             <property name="title">
+              <string>Expansion (baloon) force</string>
+             </property>
+             <layout class="QGridLayout" name="gridLayout_4">
+              <property name="leftMargin">
+               <number>4</number>
+              </property>
+              <property name="topMargin">
+               <number>6</number>
+              </property>
+              <property name="rightMargin">
+               <number>4</number>
+              </property>
+              <property name="bottomMargin">
+               <number>4</number>
+              </property>
+              <item row="0" column="0" colspan="2">
+               <widget class="QLabel" name="label_3">
+                <property name="styleSheet">
+                 <string notr="true">font-size:11px;</string>
+                </property>
+                <property name="text">
+                 <string>A force pushing outwards (or inwards if the weight below is negative) on the contour boundary proportionally to the speed image.</string>
+                </property>
+                <property name="wordWrap">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="0">
+               <widget class="QDoubleSpinBox" name="inCasellesAlphaSimple"/>
+              </item>
+              <item row="1" column="1">
+               <widget class="QDoubleSlider" name="inCasellesAlphaSimpleSlider">
+                <property name="maximum">
+                 <number>100</number>
+                </property>
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="tickPosition">
+                 <enum>QSlider::TicksBelow</enum>
+                </property>
+                <property name="tickInterval">
+                 <number>25</number>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_6">
+             <property name="title">
+              <string>Smoothing (curvature) force:</string>
+             </property>
+             <layout class="QGridLayout" name="gridLayout_5">
+              <property name="leftMargin">
+               <number>4</number>
+              </property>
+              <property name="topMargin">
+               <number>6</number>
+              </property>
+              <property name="rightMargin">
+               <number>4</number>
+              </property>
+              <property name="bottomMargin">
+               <number>4</number>
+              </property>
+              <item row="0" column="0" colspan="2">
+               <widget class="QLabel" name="label_4">
+                <property name="styleSheet">
+                 <string notr="true">font-size:11px;</string>
+                </property>
+                <property name="text">
+                 <string>Makes the contour boundary smoother and can prevent the contour from leaking into narrow objects such as vessels.</string>
+                </property>
+                <property name="wordWrap">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="0">
+               <widget class="QDoubleSpinBox" name="inCasellesBetaSimple"/>
+              </item>
+              <item row="1" column="1">
+               <widget class="QDoubleSlider" name="inCasellesBetaSimpleSlider">
+                <property name="maximum">
+                 <number>100</number>
+                </property>
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="tickPosition">
+                 <enum>QSlider::TicksBelow</enum>
+                </property>
+                <property name="tickInterval">
+                 <number>25</number>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_7">
+             <property name="title">
+              <string>Edge attraction (advection) force:</string>
+             </property>
+             <layout class="QGridLayout" name="gridLayout_6">
+              <property name="leftMargin">
+               <number>4</number>
+              </property>
+              <property name="topMargin">
+               <number>6</number>
+              </property>
+              <property name="rightMargin">
+               <number>4</number>
+              </property>
+              <property name="bottomMargin">
+               <number>4</number>
+              </property>
+              <item row="0" column="0" colspan="2">
+               <widget class="QLabel" name="label_5">
+                <property name="styleSheet">
+                 <string notr="true">font-size:11px;</string>
+                </property>
+                <property name="text">
+                 <string>Attracts the boundary of the contour to nearby edges and can prevent the contour from leaking past edges.</string>
+                </property>
+                <property name="wordWrap">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="0">
+               <widget class="QDoubleSpinBox" name="inCasellesGammaSimple"/>
+              </item>
+              <item row="1" column="1">
+               <widget class="QDoubleSlider" name="inCasellesGammaSimpleSlider">
+                <property name="maximum">
+                 <number>100</number>
+                </property>
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="tickPosition">
+                 <enum>QSlider::TicksBelow</enum>
+                </property>
+                <property name="tickInterval">
+                 <number>10</number>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tabMath">
+      <attribute name="title">
+       <string>Math Mode</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,0,1">
+       <property name="leftMargin">
+        <number>4</number>
+       </property>
+       <property name="topMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>4</number>
+       </property>
+       <property name="bottomMargin">
+        <number>4</number>
+       </property>
+       <item>
+        <widget class="QGroupBox" name="groupBox_8">
+         <property name="title">
+          <string>Contour evolution equation:</string>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_8" columnstretch="0,0">
+          <property name="leftMargin">
+           <number>2</number>
+          </property>
+          <property name="topMargin">
+           <number>6</number>
+          </property>
+          <property name="rightMargin">
+           <number>2</number>
+          </property>
+          <property name="bottomMargin">
+           <number>8</number>
+          </property>
+          <item row="2" column="1" alignment="Qt::AlignRight">
+           <widget class="QCheckBox" name="chkAdvanced">
+            <property name="toolTip">
+             <string>The advanced expression provides additional flexibility by allowing the exponent of the speed image to be changed in each of the terms.</string>
+            </property>
+            <property name="text">
+             <string>Use advanced expression</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="QStackedWidget" name="stackEqn">
+            <property name="currentIndex">
+             <number>0</number>
+            </property>
+            <widget class="QWidget" name="pageEqnZhu">
+             <layout class="QVBoxLayout" name="verticalLayout">
+              <property name="margin">
+               <number>0</number>
+              </property>
+              <item alignment="Qt::AlignHCenter">
+               <widget class="QLabel" name="outFormula_2">
+                <property name="text">
+                 <string/>
+                </property>
+                <property name="pixmap">
+                 <pixmap resource="../Resources/SNAPResources.qrc">:/root/formula02.gif</pixmap>
+                </property>
+                <property name="scaledContents">
+                 <bool>false</bool>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+            <widget class="QWidget" name="pageEqnCaselles">
+             <layout class="QVBoxLayout" name="verticalLayout_2">
+              <property name="margin">
+               <number>0</number>
+              </property>
+              <item alignment="Qt::AlignHCenter">
+               <widget class="QLabel" name="outFormula">
+                <property name="text">
+                 <string/>
+                </property>
+                <property name="pixmap">
+                 <pixmap resource="../Resources/SNAPResources.qrc">:/root/formula01.gif</pixmap>
+                </property>
+                <property name="scaledContents">
+                 <bool>false</bool>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+            <widget class="QWidget" name="pageEqnAdvanced">
+             <layout class="QVBoxLayout" name="verticalLayout_8">
+              <property name="spacing">
+               <number>0</number>
+              </property>
+              <property name="margin">
+               <number>0</number>
+              </property>
+              <item>
+               <spacer name="verticalSpacer_6">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>1</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <widget class="QLabel" name="outFormula_3">
+                <property name="text">
+                 <string/>
+                </property>
+                <property name="pixmap">
+                 <pixmap resource="../Resources/SNAPResources.qrc">:/root/formula03.gif</pixmap>
+                </property>
+                <property name="scaledContents">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <spacer name="verticalSpacer_5">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>0</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </widget>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox_4">
+         <property name="title">
+          <string>Parameters:</string>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_7">
+          <property name="leftMargin">
+           <number>4</number>
+          </property>
+          <property name="topMargin">
+           <number>6</number>
+          </property>
+          <property name="rightMargin">
+           <number>4</number>
+          </property>
+          <property name="bottomMargin">
+           <number>4</number>
+          </property>
+          <property name="verticalSpacing">
+           <number>16</number>
+          </property>
+          <item row="1" column="2">
+           <widget class="QDoubleSlider" name="inBetaMathSlider">
+            <property name="maximum">
+             <number>100</number>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="tickPosition">
+             <enum>QSlider::TicksBelow</enum>
+            </property>
+            <property name="tickInterval">
+             <number>25</number>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="3">
+           <widget class="QLabel" name="lblBetaExp">
+            <property name="text">
+             <string><html><head/><body><p>r<span style=" vertical-align:sub;">β</span>:</p></body></html></string>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="1">
+           <widget class="QDoubleSpinBox" name="inAlphaMath"/>
+          </item>
+          <item row="0" column="2">
+           <widget class="QDoubleSlider" name="inAlphaMathSlider">
+            <property name="maximum">
+             <number>100</number>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="tickPosition">
+             <enum>QSlider::TicksBelow</enum>
+            </property>
+            <property name="tickInterval">
+             <number>25</number>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QLabel" name="label_10">
+            <property name="text">
+             <string>β:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="QDoubleSpinBox" name="inBetaMath"/>
+          </item>
+          <item row="0" column="0">
+           <widget class="QLabel" name="label_6">
+            <property name="text">
+             <string>α:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="3">
+           <widget class="QLabel" name="lblAlphaExp">
+            <property name="text">
+             <string><html><head/><body><p>r<span style=" vertical-align:sub;">α</span>:</p></body></html></string>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="1">
+           <widget class="QDoubleSpinBox" name="inGammaMath"/>
+          </item>
+          <item row="2" column="2">
+           <widget class="QDoubleSlider" name="inGammaMathSlider">
+            <property name="maximum">
+             <number>100</number>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="tickPosition">
+             <enum>QSlider::TicksBelow</enum>
+            </property>
+            <property name="tickInterval">
+             <number>25</number>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="3">
+           <widget class="QLabel" name="lblGammaExp">
+            <property name="text">
+             <string><html><head/><body><p>r<span style=" vertical-align:sub;">γ</span>:</p></body></html></string>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="0">
+           <widget class="QLabel" name="lblGammaMath">
+            <property name="text">
+             <string>γ:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="4">
+           <widget class="QSpinBox" name="inAlphaExp"/>
+          </item>
+          <item row="1" column="4">
+           <widget class="QSpinBox" name="inBetaExp"/>
+          </item>
+          <item row="2" column="4">
+           <widget class="QSpinBox" name="inGammaExp"/>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer_3">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tabAdvanced">
+      <attribute name="title">
+       <string>Advanced</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_5">
+       <property name="leftMargin">
+        <number>4</number>
+       </property>
+       <property name="topMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>4</number>
+       </property>
+       <property name="bottomMargin">
+        <number>4</number>
+       </property>
+       <item>
+        <widget class="QGroupBox" name="groupBox_9">
+         <property name="title">
+          <string>Speed-up factor</string>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_9">
+          <property name="leftMargin">
+           <number>4</number>
+          </property>
+          <property name="topMargin">
+           <number>6</number>
+          </property>
+          <property name="rightMargin">
+           <number>4</number>
+          </property>
+          <property name="bottomMargin">
+           <number>4</number>
+          </property>
+          <item row="1" column="0">
+           <widget class="QDoubleSpinBox" name="inSpeedup"/>
+          </item>
+          <item row="1" column="1">
+           <widget class="QDoubleSlider" name="inSpeedupSlider">
+            <property name="maximum">
+             <number>100</number>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="tickPosition">
+             <enum>QSlider::TicksBelow</enum>
+            </property>
+            <property name="tickInterval">
+             <number>25</number>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="0" colspan="2">
+           <widget class="QLabel" name="label_13">
+            <property name="styleSheet">
+             <string notr="true">font-size:11px;</string>
+            </property>
+            <property name="text">
+             <string>It is possible to speed up active contour evolution by increasing the step size over the theoretically optimal value. However, this can result in numerical instability.</string>
+            </property>
+            <property name="wordWrap">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer_4">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item row="1" column="0" colspan="2">
+    <widget class="QWidget" name="widget_2" native="true">
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>20</height>
+      </size>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="spacing">
+       <number>6</number>
+      </property>
+      <property name="margin">
+       <number>2</number>
+      </property>
+      <item>
+       <widget class="QPushButton" name="btnRestore">
+        <property name="text">
+         <string>Restore Defaults</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnOpen">
+        <property name="text">
+         <string>Open...</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnSave">
+        <property name="text">
+         <string>Save...</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnClose">
+        <property name="text">
+         <string>Close</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QDoubleSlider</class>
+   <extends>QSlider</extends>
+   <header location="global">QDoubleSlider.h</header>
+  </customwidget>
+  <customwidget>
+   <class>QtSimpleOpenGLBox</class>
+   <extends>QWidget</extends>
+   <header location="global">QtSimpleOpenGLBox.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>tabWidget</tabstop>
+  <tabstop>inZhuAlphaSimple</tabstop>
+  <tabstop>inZhuAlphaSimpleSlider</tabstop>
+  <tabstop>inZhuBetaSimple</tabstop>
+  <tabstop>inZhuBetaSimpleSlider</tabstop>
+  <tabstop>inCasellesAlphaSimple</tabstop>
+  <tabstop>inCasellesAlphaSimpleSlider</tabstop>
+  <tabstop>inCasellesBetaSimple</tabstop>
+  <tabstop>inCasellesBetaSimpleSlider</tabstop>
+  <tabstop>inCasellesGammaSimple</tabstop>
+  <tabstop>inCasellesGammaSimpleSlider</tabstop>
+  <tabstop>chkAdvanced</tabstop>
+  <tabstop>inAlphaMath</tabstop>
+  <tabstop>inAlphaMathSlider</tabstop>
+  <tabstop>inAlphaExp</tabstop>
+  <tabstop>inBetaMath</tabstop>
+  <tabstop>inBetaMathSlider</tabstop>
+  <tabstop>inBetaExp</tabstop>
+  <tabstop>inGammaMath</tabstop>
+  <tabstop>inGammaMathSlider</tabstop>
+  <tabstop>inGammaExp</tabstop>
+  <tabstop>inSpeedup</tabstop>
+  <tabstop>inSpeedupSlider</tabstop>
+  <tabstop>chkAnimate</tabstop>
+ </tabstops>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>btnClose</sender>
+   <signal>clicked()</signal>
+   <receiver>SnakeParameterDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>657</x>
+     <y>431</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>529</x>
+     <y>447</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/GUI/Qt/Windows/SpeedImageDialog.cxx b/GUI/Qt/Windows/SpeedImageDialog.cxx
new file mode 100644
index 0000000..c7cce33
--- /dev/null
+++ b/GUI/Qt/Windows/SpeedImageDialog.cxx
@@ -0,0 +1,158 @@
+#include "SpeedImageDialog.h"
+#include "ui_SpeedImageDialog.h"
+#include "QtSliderCoupling.h"
+#include "QtRadioButtonCoupling.h"
+#include "QtAbstractButtonCoupling.h"
+#include "QtComboBoxCoupling.h"
+#include "SnakeWizardModel.h"
+#include "QtWidgetActivator.h"
+#include "ThresholdSettingsRenderer.h"
+#include "EdgePreprocessingSettingsRenderer.h"
+#include "QtCheckBoxCoupling.h"
+#include "QtSpinBoxCoupling.h"
+#include "QtDoubleSpinBoxCoupling.h"
+#include "QtComboBoxCoupling.h"
+#include <QCloseEvent>
+#include <QTreeView>
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "UnsupervisedClustering.h"
+#include "GaussianMixtureModel.h"
+#include "ImageWrapperBase.h"
+#include "SNAPQtCommon.h"
+#include "GMMTableModel.h"
+#include "GMMRenderer.h"
+#include "QtDoubleSliderWithEditorCoupling.h"
+#include "QtPagedWidgetCoupling.h"
+
+Q_DECLARE_METATYPE(SnakeWizardModel::LayerScalarRepIndex)
+
+SpeedImageDialog::SpeedImageDialog(QWidget *parent) :
+  QDialog(parent),
+  ui(new Ui::SpeedImageDialog)
+{
+  ui->setupUi(this);
+
+  // Set up the GMM table
+  m_GMMTableModel = new GMMTableModel(this);
+  ui->tblClusters->setModel(m_GMMTableModel);
+  ui->tblClusters->setItemDelegate(new GMMItemDelegate(this));
+
+  // Create the renderer and attach it to its GL box
+  m_ThresholdRenderer = ThresholdSettingsRenderer::New();
+  ui->viewThreshold->SetRenderer(m_ThresholdRenderer);
+
+  // Same for the edge preprocessing
+  m_EdgeSettingsRenderer = EdgePreprocessingSettingsRenderer::New();
+  ui->viewEdgeMapping->SetRenderer(m_EdgeSettingsRenderer);
+
+  m_GMMRenderer = GMMRenderer::New();
+  ui->viewClustering->SetRenderer(m_GMMRenderer);
+}
+
+SpeedImageDialog::~SpeedImageDialog()
+{
+  delete ui;
+}
+
+void SpeedImageDialog::SetModel(SnakeWizardModel *model)
+{
+  // Store the model
+  m_Model = model;
+
+  // Pass the model to the renderers
+  m_ThresholdRenderer->SetModel(model);
+  m_EdgeSettingsRenderer->SetModel(model);
+  m_GMMRenderer->SetModel(model);
+
+  // Pass the model to the sub-models
+  m_GMMTableModel->SetParentModel(model);
+
+  // Couple the preview checkbox
+  makeCoupling(ui->chkPreview, model->GetPreviewModel());
+  makeCoupling((QAbstractButton *) ui->btnSpeedBlue, model->GetBlueWhiteSpeedModeModel());
+  makeCoupling((QAbstractButton *) ui->btnSpeedOverlay, model->GetRedTransparentSpeedModeModel());
+
+  // Couple the thresholding widgets
+  makeCoupling(ui->inLowerThreshold, model->GetThresholdLowerModel());
+  makeCoupling(ui->inLowerThresholdSpinner, model->GetThresholdLowerModel());
+  makeCoupling(ui->inUpperThreshold, model->GetThresholdUpperModel());
+  makeCoupling(ui->inUpperThresholdSpinner, model->GetThresholdUpperModel());
+  makeCoupling(ui->inThresholdSmoothness, model->GetThresholdSmoothnessModel());
+  makeCoupling(ui->inThresholdSmoothnessSpinner, model->GetThresholdSmoothnessModel());
+
+  makeRadioGroupCoupling(ui->grpThresholdMode, model->GetThresholdModeModel());
+
+  makeCoupling(ui->inThresholdImage, model->GetThresholdActiveLayerModel());
+  makeCoupling(ui->inThresholdComponent, model->GetThresholdActiveScalarRepModel());
+
+  // Couple the edge preprocessing widgets
+  makeCoupling(ui->inEdgeSmoothing, model->GetEdgePreprocessingSigmaModel());
+  makeCoupling(ui->inEdgeKappa, model->GetEdgePreprocessingKappaModel());
+  makeCoupling(ui->inEdgeExponent, model->GetEdgePreprocessingExponentModel());
+
+  // Couple the clustering widgets
+  makeCoupling(ui->inNumClusters, model->GetNumberOfClustersModel());
+  makeCoupling(ui->inNumSamples, model->GetNumberOfGMMSamplesModel());
+  makeCoupling(ui->inClusterXComponent, model->GetClusterPlottedComponentModel());
+
+  // Couple the tab pages to the current mode
+  std::map<PreprocessingMode, QWidget *> preproc_page_map;
+  preproc_page_map[PREPROCESS_THRESHOLD] = ui->tabThreshold;
+  preproc_page_map[PREPROCESS_EDGE] = ui->tabEdgeAttraction;
+  preproc_page_map[PREPROCESS_GMM] = ui->tabCluster;
+  preproc_page_map[PREPROCESS_RF] = ui->tabClassify;
+  makePagedWidgetCoupling(ui->tabMode, m_Model->GetPreprocessingModeModel(),
+                          preproc_page_map);
+
+  // Set up activation
+  activateOnFlag(ui->inLowerThreshold, model, SnakeWizardModel::UIF_LOWER_THRESHOLD_ENABLED);
+  activateOnFlag(ui->inLowerThresholdSpinner, model, SnakeWizardModel::UIF_LOWER_THRESHOLD_ENABLED);
+  activateOnFlag(ui->inUpperThreshold, model, SnakeWizardModel::UIF_UPPER_THRESHOLD_ENABLED);
+  activateOnFlag(ui->inUpperThresholdSpinner, model, SnakeWizardModel::UIF_UPPER_THRESHOLD_ENABLED);
+}
+
+void SpeedImageDialog::on_btnClose_clicked()
+{
+  this->accept();
+}
+
+void SpeedImageDialog::closeEvent(QCloseEvent *event)
+{
+  // Hide speed if there is no valid image
+  this->on_btnClose_clicked();
+
+  // Done with the event
+  event->accept();
+}
+
+void SpeedImageDialog::ShowDialog()
+{
+  this->show();
+  this->activateWindow();
+  this->raise();
+}
+
+void SpeedImageDialog::on_btnReinitialize_clicked()
+{
+  m_Model->ReinitializeClustering();
+}
+
+void SpeedImageDialog::on_btnIterate_clicked()
+{
+  m_Model->PerformClusteringIteration();
+}
+
+
+
+void SpeedImageDialog::on_btnIterateTen_clicked()
+{
+  for(int i = 0; i < 10; i++)
+    m_Model->PerformClusteringIteration();
+}
+
+
+void SpeedImageDialog::on_btnTrain_clicked()
+{
+  m_Model->TrainClassifier();
+}
diff --git a/GUI/Qt/Windows/SpeedImageDialog.h b/GUI/Qt/Windows/SpeedImageDialog.h
new file mode 100644
index 0000000..334e557
--- /dev/null
+++ b/GUI/Qt/Windows/SpeedImageDialog.h
@@ -0,0 +1,69 @@
+#ifndef SPEEDIMAGEDIALOG_H
+#define SPEEDIMAGEDIALOG_H
+
+#include <QDialog>
+#include <QAbstractTableModel>
+#include <SNAPCommon.h>
+
+class SnakeWizardModel;
+class ThresholdSettingsRenderer;
+class EdgePreprocessingSettingsRenderer;
+class GaussianMixtureModel;
+class GMMTableModel;
+class GMMRenderer;
+class ImageLayerSelectionModel;
+
+
+namespace Ui {
+class SpeedImageDialog;
+}
+
+
+
+class SpeedImageDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+  explicit SpeedImageDialog(QWidget *parent = 0);
+  ~SpeedImageDialog();
+
+  void SetModel(SnakeWizardModel *model);
+
+  /** Make the appropriate pages available based on the state of the model
+    and show the dialog */
+  void ShowDialog();
+
+  void closeEvent(QCloseEvent *event);
+
+private slots:
+
+  void on_btnClose_clicked();
+
+  void on_btnReinitialize_clicked();
+
+  void on_btnIterate_clicked();
+
+  void on_btnIterateTen_clicked();
+
+  void on_btnTrain_clicked();
+
+private:
+  Ui::SpeedImageDialog *ui;
+
+  SnakeWizardModel *m_Model;
+
+  // Renderer used in the threshold settings window.
+  // TODO: it seems wrong to have the Qt classes own renderer objects,
+  // perhaps this should be owned by the model instead?
+  SmartPtr<ThresholdSettingsRenderer> m_ThresholdRenderer;
+
+  SmartPtr<EdgePreprocessingSettingsRenderer> m_EdgeSettingsRenderer;
+
+  SmartPtr<GMMRenderer> m_GMMRenderer;
+
+  // Qt table model for the cluster table
+  GMMTableModel *m_GMMTableModel;
+};
+
+#endif // SPEEDIMAGEDIALOG_H
diff --git a/GUI/Qt/Windows/SpeedImageDialog.ui b/GUI/Qt/Windows/SpeedImageDialog.ui
new file mode 100644
index 0000000..40cbea5
--- /dev/null
+++ b/GUI/Qt/Windows/SpeedImageDialog.ui
@@ -0,0 +1,1260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SpeedImageDialog</class>
+ <widget class="QDialog" name="SpeedImageDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>500</width>
+    <height>543</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Speed Image Generation - ITK-SNAP</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">* {
+font-size: 12px;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QTabWidget" name="tabMode">
+     <property name="currentIndex">
+      <number>2</number>
+     </property>
+     <widget class="QWidget" name="tabThreshold">
+      <attribute name="title">
+       <string>Thresholding</string>
+      </attribute>
+      <layout class="QGridLayout" name="gridLayout">
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="topMargin">
+        <number>4</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>4</number>
+       </property>
+       <property name="horizontalSpacing">
+        <number>32</number>
+       </property>
+       <property name="verticalSpacing">
+        <number>2</number>
+       </property>
+       <item row="6" column="1">
+        <widget class="QWidget" name="widget_8" native="true">
+         <layout class="QVBoxLayout" name="verticalLayout_10" stretch="0,1">
+          <property name="spacing">
+           <number>2</number>
+          </property>
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QLabel" name="label_4">
+            <property name="text">
+             <string>Threshold direction:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="grpThresholdMode" native="true">
+            <property name="minimumSize">
+             <size>
+              <width>0</width>
+              <height>100</height>
+             </size>
+            </property>
+            <layout class="QVBoxLayout" name="verticalLayout_2">
+             <property name="spacing">
+              <number>4</number>
+             </property>
+             <property name="leftMargin">
+              <number>16</number>
+             </property>
+             <property name="topMargin">
+              <number>6</number>
+             </property>
+             <property name="rightMargin">
+              <number>6</number>
+             </property>
+             <property name="bottomMargin">
+              <number>8</number>
+             </property>
+             <item>
+              <widget class="QRadioButton" name="btnTwoSidedThreshold">
+               <property name="text">
+                <string>Two-sided</string>
+               </property>
+               <property name="icon">
+                <iconset resource="../Resources/SNAPResources.qrc">
+                 <normaloff>:/root/thresh_both.png</normaloff>:/root/thresh_both.png</iconset>
+               </property>
+               <property name="iconSize">
+                <size>
+                 <width>22</width>
+                 <height>22</height>
+                </size>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QRadioButton" name="btnLowerThreshold">
+               <property name="text">
+                <string>Lower only</string>
+               </property>
+               <property name="icon">
+                <iconset resource="../Resources/SNAPResources.qrc">
+                 <normaloff>:/root/thresh_lower.png</normaloff>:/root/thresh_lower.png</iconset>
+               </property>
+               <property name="iconSize">
+                <size>
+                 <width>22</width>
+                 <height>22</height>
+                </size>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QRadioButton" name="btnUpperThreshold">
+               <property name="text">
+                <string>Upper only</string>
+               </property>
+               <property name="icon">
+                <iconset resource="../Resources/SNAPResources.qrc">
+                 <normaloff>:/root/thresh_upper.png</normaloff>:/root/thresh_upper.png</iconset>
+               </property>
+               <property name="iconSize">
+                <size>
+                 <width>22</width>
+                 <height>22</height>
+                </size>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <spacer name="verticalSpacer_15">
+               <property name="orientation">
+                <enum>Qt::Vertical</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>20</width>
+                 <height>0</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+            </layout>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="13" column="0" colspan="2">
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>0</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="6" column="0">
+        <widget class="QWidget" name="widget_7" native="true">
+         <layout class="QGridLayout" name="gridLayout_4">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <property name="horizontalSpacing">
+           <number>8</number>
+          </property>
+          <property name="verticalSpacing">
+           <number>0</number>
+          </property>
+          <item row="1" column="1">
+           <widget class="QDoubleSlider" name="inLowerThreshold">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item row="7" column="1">
+           <widget class="QDoubleSlider" name="inThresholdSmoothness">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="1">
+           <spacer name="verticalSpacer_4">
+            <property name="orientation">
+             <enum>Qt::Vertical</enum>
+            </property>
+            <property name="sizeType">
+             <enum>QSizePolicy::Fixed</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>20</width>
+              <height>10</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item row="5" column="1">
+           <spacer name="verticalSpacer_5">
+            <property name="orientation">
+             <enum>Qt::Vertical</enum>
+            </property>
+            <property name="sizeType">
+             <enum>QSizePolicy::Fixed</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>20</width>
+              <height>10</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item row="4" column="1">
+           <widget class="QDoubleSlider" name="inUpperThreshold">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="0" colspan="2">
+           <widget class="QLabel" name="label">
+            <property name="text">
+             <string>&Lower threshold:</string>
+            </property>
+            <property name="buddy">
+             <cstring>inLowerThreshold</cstring>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QDoubleSpinBox" name="inLowerThresholdSpinner">
+            <property name="keyboardTracking">
+             <bool>false</bool>
+            </property>
+           </widget>
+          </item>
+          <item row="3" column="0" colspan="2">
+           <widget class="QLabel" name="label_2">
+            <property name="text">
+             <string>&Upper threshold:</string>
+            </property>
+            <property name="buddy">
+             <cstring>inUpperThreshold</cstring>
+            </property>
+           </widget>
+          </item>
+          <item row="4" column="0">
+           <widget class="QDoubleSpinBox" name="inUpperThresholdSpinner">
+            <property name="keyboardTracking">
+             <bool>false</bool>
+            </property>
+           </widget>
+          </item>
+          <item row="6" column="0" colspan="2">
+           <widget class="QLabel" name="label_3">
+            <property name="text">
+             <string>&Smoothness:</string>
+            </property>
+            <property name="buddy">
+             <cstring>inThresholdSmoothness</cstring>
+            </property>
+           </widget>
+          </item>
+          <item row="7" column="0">
+           <widget class="QDoubleSpinBox" name="inThresholdSmoothnessSpinner">
+            <property name="keyboardTracking">
+             <bool>false</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="1" column="0" colspan="2">
+        <widget class="QWidget" name="grpThresholdComponent" native="true">
+         <layout class="QGridLayout" name="gridLayout_2">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <property name="horizontalSpacing">
+           <number>12</number>
+          </property>
+          <property name="verticalSpacing">
+           <number>2</number>
+          </property>
+          <item row="0" column="0">
+           <widget class="QLabel" name="label_16">
+            <property name="text">
+             <string>Image to threshold:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QComboBox" name="inThresholdImage"/>
+          </item>
+          <item row="0" column="1">
+           <widget class="QLabel" name="label_17">
+            <property name="text">
+             <string>Component:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="QComboBox" name="inThresholdComponent"/>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="4" column="0" colspan="2">
+        <widget class="QFrame" name="frame">
+         <property name="frameShape">
+          <enum>QFrame::StyledPanel</enum>
+         </property>
+         <property name="frameShadow">
+          <enum>QFrame::Raised</enum>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_4">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QtVTKRenderWindowBox" name="viewThreshold" native="true">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="minimumSize">
+             <size>
+              <width>0</width>
+              <height>160</height>
+             </size>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">background-color:white;</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="3" column="0">
+        <widget class="QLabel" name="label_5">
+         <property name="text">
+          <string>Thresholding function:</string>
+         </property>
+         <property name="buddy">
+          <cstring>inLowerThreshold</cstring>
+         </property>
+        </widget>
+       </item>
+       <item row="5" column="0" colspan="2">
+        <spacer name="verticalSpacer_2">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Fixed</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>12</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="2" column="0" colspan="2">
+        <spacer name="verticalSpacer_11">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Fixed</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>12</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="0" column="0" colspan="2">
+        <spacer name="verticalSpacer_3">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Fixed</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>12</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tabCluster">
+      <attribute name="title">
+       <string>Clustering</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_8">
+       <property name="spacing">
+        <number>2</number>
+       </property>
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="topMargin">
+        <number>4</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>4</number>
+       </property>
+       <item>
+        <widget class="QWidget" name="widget_6" native="true">
+         <layout class="QHBoxLayout" name="horizontalLayout_6">
+          <property name="spacing">
+           <number>4</number>
+          </property>
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QLabel" name="label_10">
+            <property name="text">
+             <string>Number of clusters:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QSpinBox" name="inNumClusters">
+            <property name="minimumSize">
+             <size>
+              <width>80</width>
+              <height>0</height>
+             </size>
+            </property>
+            <property name="maximumSize">
+             <size>
+              <width>80</width>
+              <height>16777215</height>
+             </size>
+            </property>
+            <property name="keyboardTracking">
+             <bool>false</bool>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_3">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_12">
+            <property name="text">
+             <string>Samples:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QSpinBox" name="inNumSamples">
+            <property name="minimumSize">
+             <size>
+              <width>80</width>
+              <height>0</height>
+             </size>
+            </property>
+            <property name="maximumSize">
+             <size>
+              <width>80</width>
+              <height>16777215</height>
+             </size>
+            </property>
+            <property name="correctionMode">
+             <enum>QAbstractSpinBox::CorrectToNearestValue</enum>
+            </property>
+            <property name="keyboardTracking">
+             <bool>false</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer_12">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Fixed</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>12</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QLabel" name="label_11">
+         <property name="text">
+          <string>Table of clusters:</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QTableView" name="tblClusters">
+         <property name="maximumSize">
+          <size>
+           <width>16777215</width>
+           <height>140</height>
+          </size>
+         </property>
+         <property name="styleSheet">
+          <string notr="true">font-size:11px;</string>
+         </property>
+         <property name="selectionMode">
+          <enum>QAbstractItemView::SingleSelection</enum>
+         </property>
+         <property name="selectionBehavior">
+          <enum>QAbstractItemView::SelectRows</enum>
+         </property>
+         <attribute name="horizontalHeaderDefaultSectionSize">
+          <number>75</number>
+         </attribute>
+         <attribute name="verticalHeaderDefaultSectionSize">
+          <number>24</number>
+         </attribute>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer_14">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>12</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QWidget" name="widget_2" native="true">
+         <layout class="QHBoxLayout" name="horizontalLayout_3">
+          <property name="spacing">
+           <number>8</number>
+          </property>
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QPushButton" name="btnReinitialize">
+            <property name="text">
+             <string>Reinitialize</string>
+            </property>
+            <property name="icon">
+             <iconset resource="../Resources/SNAPResources.qrc">
+              <normaloff>:/root/view-refresh-4.png</normaloff>:/root/view-refresh-4.png</iconset>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="btnIterate">
+            <property name="text">
+             <string>Iterate x1</string>
+            </property>
+            <property name="icon">
+             <iconset resource="../Resources/SNAPResources.qrc">
+              <normaloff>:/root/media-playback-start-1x-4.png</normaloff>:/root/media-playback-start-1x-4.png</iconset>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="btnIterateTen">
+            <property name="text">
+             <string>Iterate x10</string>
+            </property>
+            <property name="icon">
+             <iconset resource="../Resources/SNAPResources.qrc">
+              <normaloff>:/root/media-playback-start-10x-4.png</normaloff>:/root/media-playback-start-10x-4.png</iconset>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_2">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer_13">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Fixed</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>12</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QLabel" name="label_15">
+         <property name="text">
+          <string>Cluster probability density plot:</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QFrame" name="frame_2">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>1</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="frameShape">
+          <enum>QFrame::StyledPanel</enum>
+         </property>
+         <property name="frameShadow">
+          <enum>QFrame::Raised</enum>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_5">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QtVTKRenderWindowBox" name="viewClustering" native="true">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+              <horstretch>0</horstretch>
+              <verstretch>2</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="minimumSize">
+             <size>
+              <width>40</width>
+              <height>120</height>
+             </size>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">background-color:white;</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QWidget" name="widget_5" native="true">
+         <property name="styleSheet">
+          <string notr="true">font-size:10px;</string>
+         </property>
+         <layout class="QHBoxLayout" name="horizontalLayout_5">
+          <property name="spacing">
+           <number>8</number>
+          </property>
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <spacer name="horizontalSpacer_6">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>5</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_13">
+            <property name="text">
+             <string>X axis:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QComboBox" name="inClusterXComponent">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+              <horstretch>1</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="maximumSize">
+             <size>
+              <width>150</width>
+              <height>16777215</height>
+             </size>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_5">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeType">
+             <enum>QSizePolicy::Fixed</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>10</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_14">
+            <property name="enabled">
+             <bool>false</bool>
+            </property>
+            <property name="text">
+             <string>Y axis:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QComboBox" name="inClusterYComponent">
+            <property name="enabled">
+             <bool>false</bool>
+            </property>
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+              <horstretch>1</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="maximumSize">
+             <size>
+              <width>150</width>
+              <height>16777215</height>
+             </size>
+            </property>
+            <property name="baseSize">
+             <size>
+              <width>0</width>
+              <height>0</height>
+             </size>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tabClassify">
+      <attribute name="title">
+       <string>Classification</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_9">
+       <item>
+        <widget class="QLabel" name="label_18">
+         <property name="text">
+          <string>Table of tissue classes:</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QTableView" name="tableClasses"/>
+       </item>
+       <item>
+        <widget class="QWidget" name="widget_9" native="true">
+         <layout class="QHBoxLayout" name="horizontalLayout_4">
+          <item>
+           <spacer name="horizontalSpacer_4">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QPushButton" name="btnTrain">
+            <property name="text">
+             <string>Train</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLabel" name="label_19">
+         <property name="text">
+          <string><html><head/><body><p>To use supervised classification, define two or more classes. For each class, use the paintbrush tool to provide examples of that class in the image.</p></body></html></string>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tabEdgeAttraction">
+      <attribute name="title">
+       <string>Edge Attraction</string>
+      </attribute>
+      <layout class="QGridLayout" name="gridLayout_5">
+       <property name="topMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>20</number>
+       </property>
+       <property name="horizontalSpacing">
+        <number>32</number>
+       </property>
+       <property name="verticalSpacing">
+        <number>2</number>
+       </property>
+       <item row="2" column="0">
+        <spacer name="verticalSpacer_8">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Fixed</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>427</width>
+           <height>13</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="7" column="0">
+        <widget class="QDoubleSliderWithEditor" name="inEdgeKappa">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+        </widget>
+       </item>
+       <item row="8" column="0">
+        <spacer name="verticalSpacer_10">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Fixed</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>427</width>
+           <height>13</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="3" column="0">
+        <widget class="QLabel" name="label_7">
+         <property name="text">
+          <string>Scale of Gaussian blurring:</string>
+         </property>
+        </widget>
+       </item>
+       <item row="9" column="0">
+        <widget class="QLabel" name="label_9">
+         <property name="text">
+          <string>Edge transformation exponent:</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QtSimpleOpenGLBox" name="viewEdgeMapping" native="true">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>160</height>
+          </size>
+         </property>
+         <property name="styleSheet">
+          <string notr="true">background-color:white;</string>
+         </property>
+        </widget>
+       </item>
+       <item row="11" column="0">
+        <spacer name="verticalSpacer_6">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>427</width>
+           <height>68</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="10" column="0">
+        <widget class="QDoubleSliderWithEditor" name="inEdgeExponent">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+        </widget>
+       </item>
+       <item row="5" column="0">
+        <spacer name="verticalSpacer_9">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Fixed</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>12</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="6" column="0">
+        <widget class="QLabel" name="label_8">
+         <property name="text">
+          <string>Edge transformation contrast:</string>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="0">
+        <widget class="QDoubleSliderWithEditor" name="inEdgeSmoothing">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0">
+        <widget class="QLabel" name="label_6">
+         <property name="text">
+          <string>Transformation from edge strength to speed value</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_3" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="leftMargin">
+       <number>18</number>
+      </property>
+      <property name="topMargin">
+       <number>6</number>
+      </property>
+      <property name="rightMargin">
+       <number>6</number>
+      </property>
+      <property name="bottomMargin">
+       <number>6</number>
+      </property>
+      <item>
+       <widget class="QWidget" name="widget_4" native="true">
+        <layout class="QVBoxLayout" name="verticalLayout_3">
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QCheckBox" name="chkPreview">
+           <property name="toolTip">
+            <string><html><head/><body><p>When selected, the speed image is computed on the fly</p></body></html></string>
+           </property>
+           <property name="text">
+            <string>Live Preview</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <property name="spacing">
+          <number>4</number>
+         </property>
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QToolButton" name="btnSpeedBlue">
+           <property name="toolTip">
+            <string><html><head/><body><p>Display the speed image as a non-transparent image with negative values in blue and positive values in white.</p></body></html></string>
+           </property>
+           <property name="text">
+            <string>...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../Resources/SNAPResources.qrc">
+             <normaloff>:/root/speed_bluegray.png</normaloff>:/root/speed_bluegray.png</iconset>
+           </property>
+           <property name="iconSize">
+            <size>
+             <width>16</width>
+             <height>16</height>
+            </size>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QToolButton" name="btnSpeedOverlay">
+           <property name="toolTip">
+            <string><html><head/><body><p>Display the speed image as a semi-transparent overlay, with positive values in red, negative values transparent.</p></body></html></string>
+           </property>
+           <property name="text">
+            <string>...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../Resources/SNAPResources.qrc">
+             <normaloff>:/root/speed_redoverlay.png</normaloff>:/root/speed_redoverlay.png</iconset>
+           </property>
+           <property name="iconSize">
+            <size>
+             <width>16</width>
+             <height>16</height>
+            </size>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <property name="checked">
+            <bool>false</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnClose">
+        <property name="minimumSize">
+         <size>
+          <width>64</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>64</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Close</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QDoubleSliderWithEditor</class>
+   <extends>QSlider</extends>
+   <header location="global">QDoubleSliderWithEditor.h</header>
+  </customwidget>
+  <customwidget>
+   <class>QDoubleSlider</class>
+   <extends>QSlider</extends>
+   <header location="global">QDoubleSlider.h</header>
+  </customwidget>
+  <customwidget>
+   <class>QtSimpleOpenGLBox</class>
+   <extends>QWidget</extends>
+   <header location="global">QtSimpleOpenGLBox.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>QtVTKRenderWindowBox</class>
+   <extends>QWidget</extends>
+   <header location="global">QtVTKRenderWindowBox.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources>
+  <include location="../Resources/SNAPResources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/SplashPanel.cxx b/GUI/Qt/Windows/SplashPanel.cxx
new file mode 100644
index 0000000..7c4348d
--- /dev/null
+++ b/GUI/Qt/Windows/SplashPanel.cxx
@@ -0,0 +1,16 @@
+#include "SplashPanel.h"
+#include "ui_SplashPanel.h"
+#include "SNAPCommon.h"
+
+SplashPanel::SplashPanel(QWidget *parent) :
+  QWidget(parent),
+  ui(new Ui::SplashPanel)
+{
+  ui->setupUi(this);
+  ui->outVersion->setText(SNAPUISoftVersion);
+}
+
+SplashPanel::~SplashPanel()
+{
+  delete ui;
+}
diff --git a/GUI/Qt/Windows/SplashPanel.h b/GUI/Qt/Windows/SplashPanel.h
new file mode 100644
index 0000000..0f013b3
--- /dev/null
+++ b/GUI/Qt/Windows/SplashPanel.h
@@ -0,0 +1,22 @@
+#ifndef SPLASHPANEL_H
+#define SPLASHPANEL_H
+
+#include <QWidget>
+
+namespace Ui {
+class SplashPanel;
+}
+
+class SplashPanel : public QWidget
+{
+  Q_OBJECT
+  
+public:
+  explicit SplashPanel(QWidget *parent = 0);
+  ~SplashPanel();
+
+private:
+  Ui::SplashPanel *ui;
+};
+
+#endif // SPLASHPANEL_H
diff --git a/GUI/Qt/Windows/SplashPanel.ui b/GUI/Qt/Windows/SplashPanel.ui
new file mode 100644
index 0000000..c8578e4
--- /dev/null
+++ b/GUI/Qt/Windows/SplashPanel.ui
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SplashPanel</class>
+ <widget class="QWidget" name="SplashPanel">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>184</width>
+    <height>581</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout" stretch="1,0,1,0,1,0,12,0">
+   <property name="leftMargin">
+    <number>5</number>
+   </property>
+   <property name="topMargin">
+    <number>5</number>
+   </property>
+   <property name="rightMargin">
+    <number>6</number>
+   </property>
+   <property name="bottomMargin">
+    <number>6</number>
+   </property>
+   <item>
+    <spacer name="verticalSpacer_3">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Expanding</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>4</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item alignment="Qt::AlignHCenter">
+    <widget class="QLabel" name="label_2">
+     <property name="styleSheet">
+      <string notr="true">font-size:24px;
+</string>
+     </property>
+     <property name="text">
+      <string>ITK-SNAP</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_4">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Expanding</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>4</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item alignment="Qt::AlignHCenter">
+    <widget class="QLabel" name="outVersion">
+     <property name="styleSheet">
+      <string notr="true">font-size:11px;
+color:rgb(109, 109, 109);</string>
+     </property>
+     <property name="text">
+      <string>Version X.X.X
+Jan 12, 2013</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_5">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Expanding</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>4</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item alignment="Qt::AlignHCenter">
+    <widget class="QLabel" name="label_4">
+     <property name="styleSheet">
+      <string notr="true">font-size:11px;
+color:rgb(109, 109, 109);</string>
+     </property>
+     <property name="text">
+      <string>Copyright (C) 1998-2014
+Paul A. Yushkevich 
+Guido Gerig</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>4</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_5">
+     <property name="styleSheet">
+      <string notr="true">font-size:10px;
+color:rgb(109, 109, 109);</string>
+     </property>
+     <property name="text">
+      <string>This project is supported by grants R01 EB014346, R03 EB008200, and PO 467-MZ-202446-1 from the 
+US National Insitutes of Health</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Qt/Windows/StatisticsDialog.cxx b/GUI/Qt/Windows/StatisticsDialog.cxx
new file mode 100644
index 0000000..847d61f
--- /dev/null
+++ b/GUI/Qt/Windows/StatisticsDialog.cxx
@@ -0,0 +1,163 @@
+#include "StatisticsDialog.h"
+#include "ui_StatisticsDialog.h"
+
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "SegmentationStatistics.h"
+#include "HistoryManager.h"
+#include <QStandardItemModel>
+#include <QTableView>
+#include <QHeaderView>
+#include <QMimeData>
+#include <QClipboard>
+#include <SNAPQtCommon.h>
+#include <QtCursorOverride.h>
+#include <SimpleFileDialogWithHistory.h>
+
+StatisticsDialog::StatisticsDialog(QWidget *parent) :
+  QDialog(parent),
+  ui(new Ui::StatisticsDialog)
+{
+  ui->setupUi(this);
+  this->setObjectName("dlgStatistics");
+  m_ItemModel = new QStandardItemModel(this);
+  ui->tvVolumes->setModel(m_ItemModel);
+  m_Stats = new SegmentationStatistics();
+}
+
+StatisticsDialog::~StatisticsDialog()
+{
+  delete ui;
+  delete m_Stats;
+}
+
+void StatisticsDialog::SetModel(GlobalUIModel *model)
+{
+  m_Model = model;
+}
+
+void StatisticsDialog::Activate()
+{
+  QtCursorOverride cursy(Qt::WaitCursor);
+  this->FillTable();
+  this->show();
+  this->raise();
+  this->activateWindow();
+}
+
+void StatisticsDialog::FillTable()
+{
+  // Compute the segmentation statistics
+  m_Stats->Compute(m_Model->GetDriver()->GetCurrentImageData());
+
+  // Fill out the item model
+  m_ItemModel->clear();
+
+  // Set the column names
+  QStringList header;
+  header << "Label Name" << "Voxel Count" << "Volume (mm3)";
+  m_ItemModel->setHorizontalHeaderLabels(header);
+
+  const std::vector<std::string> &cols = m_Stats->GetImageStatisticsColumns();
+  for(int j = 0; j < cols.size(); j++)
+    {
+    QString label = QString("Intensity Mean %1 SD\n(%2)").arg(QChar(0x00B1)).arg(from_utf8(cols[j]));
+
+    QStandardItem *item = new QStandardItem();
+    item->setText(label);
+    item->setToolTip(
+          QString("Mean intensity and standard deviation for layer %1").arg(from_utf8(cols[j])));
+
+    m_ItemModel->setHorizontalHeaderItem(j+3, item);
+    }
+
+  // Add all the rows
+  for(SegmentationStatistics::EntryMap::const_iterator it = m_Stats->GetStats().begin();
+      it != m_Stats->GetStats().end(); ++it)
+    {
+    LabelType i = it->first;
+    const SegmentationStatistics::Entry &row = it->second;
+    const ColorLabel &cl = m_Model->GetDriver()->GetColorLabelTable()->GetColorLabel(i);
+    if(row.count)
+      {
+      QList<QStandardItem *> qsi;
+      QIcon icon = CreateColorBoxIcon(16,16, QColor(cl.GetRGB(0), cl.GetRGB(1), cl.GetRGB(2)));
+      qsi.append(new QStandardItem(icon, cl.GetLabel()));
+      qsi.append(new QStandardItem(QString("%1").arg(row.count)));
+      qsi.append(new QStandardItem(QString("%1").arg(row.volume_mm3,0,'g',4)));
+      for(int j = 0; j < row.mean.size(); j++)
+        {
+        QString text = QString("%1%2%3")
+            .arg(row.mean[j],0,'f',4)
+            .arg(QChar(0x00B1))
+            .arg(row.stdev[j],0,'f',4);
+        qsi.append(new QStandardItem(text));
+        }
+      m_ItemModel->appendRow(qsi);
+      m_ItemModel->setVerticalHeaderItem(m_ItemModel->rowCount()-1,
+                                         new QStandardItem(QString("%1").arg(i)));
+      }
+    }
+
+  // Perform a smart resize of the column widts
+  ui->tvVolumes->resizeColumnsToContents();
+  for(int col = 0; col < ui->tvVolumes->horizontalHeader()->count(); col++)
+    {
+    if(ui->tvVolumes->horizontalHeader()->sectionSize(col) > 150)
+      ui->tvVolumes->horizontalHeader()->resizeSection(col, 150);
+    }
+}
+
+void StatisticsDialog::on_btnUpdate_clicked()
+{
+  QtCursorOverride cursy(Qt::WaitCursor);
+  this->FillTable();
+}
+
+
+void StatisticsDialog::on_btnCopy_clicked()
+{
+  std::ostringstream oss;
+  m_Stats->Export(oss, "\t", *m_Model->GetDriver()->GetColorLabelTable());
+  QString tsv = QString::fromStdString(oss.str());
+
+  QClipboard *clipboard = QApplication::clipboard();
+  clipboard->setText(tsv);
+}
+
+#include <fstream>
+
+void StatisticsDialog::on_btnExport_clicked()
+{
+  // Ask for a filename
+  QString selection = ShowSimpleSaveDialogWithHistory(
+        this, m_Model, "Statistics",
+        "Export Volumes and Statistics - ITK-SNAP",
+        "Volumes and Statistics File",
+        "Text Files (*.txt);; Comma Separated Value Files (*.csv)",
+        true);
+
+  // Open the labels from the selection
+  if(selection.length())
+    {
+    try
+      {
+      std::ofstream fout(selection.toUtf8());
+      if(selection.endsWith(".csv", Qt::CaseInsensitive))
+        {
+        m_Stats->Export(fout, ",", *m_Model->GetDriver()->GetColorLabelTable());
+        }
+      else
+        {
+        m_Stats->Export(fout, "\t", *m_Model->GetDriver()->GetColorLabelTable());
+        }
+      m_Model->GetSystemInterface()->GetHistoryManager()->
+          UpdateHistory("Statistics", to_utf8(selection), true);
+      }
+    catch(std::exception &exc)
+      {
+      ReportNonLethalException(this, exc, "Volume and Statistics IO Error",
+                               QString("Failed to export volumes and statistics"));
+      }
+    }
+}
diff --git a/GUI/Qt/Windows/StatisticsDialog.h b/GUI/Qt/Windows/StatisticsDialog.h
new file mode 100644
index 0000000..f94c7e6
--- /dev/null
+++ b/GUI/Qt/Windows/StatisticsDialog.h
@@ -0,0 +1,44 @@
+#ifndef STATISTICSDIALOG_H
+#define STATISTICSDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class StatisticsDialog;
+}
+
+class GlobalUIModel;
+class QStandardItemModel;
+class SegmentationStatistics;
+
+class StatisticsDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+
+  void SetModel(GlobalUIModel *model);
+  void Activate();
+  
+public:
+  explicit StatisticsDialog(QWidget *parent = 0);
+  ~StatisticsDialog();
+  
+private slots:
+  void on_btnUpdate_clicked();
+
+  void on_btnCopy_clicked();
+
+  void on_btnExport_clicked();
+
+private:
+  Ui::StatisticsDialog *ui;
+
+  GlobalUIModel *m_Model;
+  QStandardItemModel *m_ItemModel;
+  SegmentationStatistics *m_Stats;
+
+  void FillTable();
+};
+
+#endif // STATISTICSDIALOG_H
diff --git a/GUI/Qt/Windows/StatisticsDialog.ui b/GUI/Qt/Windows/StatisticsDialog.ui
new file mode 100644
index 0000000..ec942d1
--- /dev/null
+++ b/GUI/Qt/Windows/StatisticsDialog.ui
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>StatisticsDialog</class>
+ <widget class="QDialog" name="StatisticsDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>801</width>
+    <height>433</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Volumes and Statistics - ITK-SNAP</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QTableView" name="tvVolumes">
+     <property name="styleSheet">
+      <string notr="true">font-size:11px;</string>
+     </property>
+     <property name="gridStyle">
+      <enum>Qt::DotLine</enum>
+     </property>
+     <attribute name="horizontalHeaderStretchLastSection">
+      <bool>false</bool>
+     </attribute>
+     <attribute name="verticalHeaderDefaultSectionSize">
+      <number>24</number>
+     </attribute>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <widget class="QPushButton" name="btnUpdate">
+        <property name="minimumSize">
+         <size>
+          <width>120</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Update</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnCopy">
+        <property name="minimumSize">
+         <size>
+          <width>120</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Copy</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnExport">
+        <property name="minimumSize">
+         <size>
+          <width>120</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Export...</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="btnCLose">
+        <property name="minimumSize">
+         <size>
+          <width>120</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Close</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>btnCLose</sender>
+   <signal>clicked()</signal>
+   <receiver>StatisticsDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>728</x>
+     <y>404</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>625</x>
+     <y>428</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/GUI/Qt/main.cxx b/GUI/Qt/main.cxx
new file mode 100644
index 0000000..c667d3c
--- /dev/null
+++ b/GUI/Qt/main.cxx
@@ -0,0 +1,698 @@
+#include <QApplication>
+#include <QSettings>
+#include "MainImageWindow.h"
+#include "SliceViewPanel.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "SNAPAppearanceSettings.h"
+#include "CommandLineArgumentParser.h"
+#include "SliceWindowCoordinator.h"
+#include "SnakeWizardPanel.h"
+#include "QtRendererPlatformSupport.h"
+#include "QtIPCManager.h"
+#include "QtCursorOverride.h"
+#include "SNAPQtCommon.h"
+
+#include "GenericSliceView.h"
+#include "GenericSliceModel.h"
+#include "GlobalUIModel.h"
+#include "IRISImageData.h"
+
+#include "itkEventObject.h"
+#include "itkObject.h"
+#include "itkCommand.h"
+#include "vtkObject.h"
+
+#include <QStyleFactory>
+#include <QAction>
+#include <QUrl>
+
+#include "ImageIODelegates.h"
+
+#include <iostream>
+#include "SNAPTestQt.h"
+
+using namespace std;
+
+// Interrupt handler. This will attempt to clean up
+
+// Setup printing of stack trace on segmentation faults. This only
+// works on POSIX systems
+#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
+
+#include <signal.h>
+#include <execinfo.h>
+
+void SegmentationFaultHandler(int sig)
+{
+  cerr << "*************************************" << endl;
+  cerr << "ITK-SNAP: " << sys_siglist[sig] << endl;
+  cerr << "BACKTRACE: " << endl;
+  void *array[50];
+  int nsize = backtrace(array, 50);
+  backtrace_symbols_fd(array, nsize, 2);
+  cerr << "*************************************" << endl;
+  exit(-1);
+}
+
+void SetupSignalHandlers()
+{
+  signal(SIGSEGV, SegmentationFaultHandler);
+}
+
+#else
+
+void SetupSignalHandlers()
+{
+  // Nothing to do!
+}
+
+#endif
+
+
+/*
+ * Code to handle forking the application on startup. Forking is desirable
+ * because many users execute SNAP from command line, and it is annoying to
+ * have SNAP blocking the command line. Also, this reduced the frequency
+ * of users interrupting SNAP or killing it by closing the terminal.
+ */
+
+#include <QFileOpenEvent>
+#include <QTime>
+#include <QMessageBox>
+
+/** Class to handle exceptions in Qt callbacks */
+class SNAPQApplication : public QApplication
+{
+public:
+  SNAPQApplication(int &argc, char **argv) :
+    QApplication(argc, argv)
+    {
+    this->setApplicationName("ITK-SNAP");
+    this->setOrganizationName("itksnap.org");
+    m_MainWindow = NULL;
+
+    // Store the command-line arguments
+    for(int i = 1; i < argc; i++)
+      m_Args.push_back(QString::fromUtf8(argv[i]));
+  }
+
+  void setMainWindow(MainImageWindow *mainwin)
+  {
+    m_MainWindow = mainwin;
+    m_StartupTime = QTime::currentTime();
+  }
+
+  bool notify(QObject *object, QEvent *event)
+  {
+    try { return QApplication::notify(object, event); }
+    catch(std::exception &exc)
+    {
+      // Crash!
+      ReportNonLethalException(NULL, exc, "Unexpected Error",
+                               "ITK-SNAP has crashed due to an unexpected error");
+
+      // Exit the application
+      QApplication::exit(-1);
+
+      return false;
+    }
+  }
+
+
+  virtual bool event(QEvent *event)
+  {
+    if (event->type() == QEvent::FileOpen && m_MainWindow)
+      {
+      QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
+      QString file = openEvent->url().path();
+
+      // MacOS bug - we get these open document events automatically generated
+      // from command-line parameters, and I have no idea why. To avoid this,
+      // if the event occurs at startup (within a second), we will check if
+      // the passed in URL matches the command-line arguments, and ignore it
+      // if it does
+      if(m_StartupTime.secsTo(QTime::currentTime()) < 1)
+        {
+        foreach(const QString &arg, m_Args)
+          {
+          if(arg == file)
+            return true;
+          }
+        }
+
+      // Ok, we passed the check, now it's safe to actually open the file
+      m_MainWindow->raise();
+      m_MainWindow->LoadDroppedFile(file);
+      return true;
+      }
+    else return QApplication::event(event);
+  }
+
+private:
+  MainImageWindow *m_MainWindow;
+  QStringList m_Args;
+  QTime m_StartupTime;
+};
+
+
+#ifdef SNAP_DEBUG_EVENTS
+bool flag_snap_debug_events = false;
+#endif
+
+void usage()
+{
+  // Print usage info and exit
+  cout << "ITK-SnAP Command Line Usage:" << endl;
+  cout << "   snap [options] [main_image]" << endl;
+  cout << "Image Options:" << endl;
+  cout << "   -g FILE              : Load the greyscale image from FILE" << endl;
+  cout << "   -s FILE              : Load the segmentation image from FILE" << endl;
+  cout << "   -l FILE              : Load label descriptions from FILE" << endl;
+  cout << "   -o FILE              : Load overlay image from FILE" << endl;
+  cout << "                        :   (-o option can be repeated multiple times)" << endl;
+  cout << "   -w FILE              : Load workspace from FILE" << endl;
+  cout << "                        :   (-w cannot be mixed with -g,-s,-l,-o options)" << endl;
+  cout << "Additional Options:" << endl;
+  cout << "   -z FACTOR            : Specify initial zoom in screen pixels/mm" << endl;
+  cout << "Debugging/Testing Options" << endl;
+#ifdef SNAP_DEBUG_EVENTS
+  cout << "   --debug-events       : Dump information regarding UI events" << endl;
+#endif // SNAP_DEBUG_EVENTS
+  cout << "   --test list          : List available tests. " << endl;
+  cout << "   --test TESTID        : Execute a test. " << endl;
+  cout << "   --testdir DIR        : Set the root directory for tests. " << endl;
+  cout << "   --testacc factor     : Adjust the interval between test commands by factor (e.g., 0.5). " << endl;
+}
+
+void setupParser(CommandLineArgumentParser &parser)
+{
+}
+
+/**
+ * This class describes the command-line options parsed from the command line.
+ */
+struct CommandLineRequest
+{
+public:
+  std::string fnMain;
+  std::vector<std::string> fnOverlay;
+  std::string fnSegmentation;
+  std::string fnLabelDesc;
+  std::string fnWorkspace;
+  double xZoomFactor;
+  bool flagDebugEvents;
+
+  // Whether the console-based application should not fork
+  bool flagNoFork;
+
+  // Whether the application is being launched from the console
+  bool flagConsole;
+
+  // Test-related stuff
+  std::string xTestId;
+  std::string fnTestDir;
+  double xTestAccel;
+
+  CommandLineRequest()
+    : flagDebugEvents(false), flagNoFork(false), flagConsole(false), xZoomFactor(0.0) {}
+};
+
+/**
+ This function decodes filenames in "SHORT" DOS format. It does nothing
+ on non-Windows platforms
+*/
+std::string DecodeFilename(const std::string &in_string)
+{
+#ifdef WIN32
+  int bufsize = GetLongPathName(in_string.c_str(), NULL, 0);
+  if (bufsize == 0)
+    throw IRISException("Unable to decode parameter %s", in_string.c_str());
+
+  char *buffer = new char[bufsize];
+  int rc = GetLongPathName(in_string.c_str(), buffer, bufsize);
+  
+  if (rc == 0)
+    throw IRISException("Unable to decode parameter %s", in_string.c_str());
+
+  return std::string(buffer);
+
+#else
+  return in_string;
+
+#endif
+
+}
+
+
+/**
+ * This function takes the command-line arguments and parses them into the
+ * CommandLineRequest structure. If it returns with a non-zero error code,
+ * the program should exit with that code.
+ */
+int parse(int argc, char *argv[], CommandLineRequest &argdata)
+{
+
+  // Parse command line arguments
+  CommandLineArgumentParser parser;
+
+  // These are all the recognized arguments
+  parser.AddOption("--grey",1);
+  parser.AddSynonim("--grey","-g");
+
+  parser.AddOption("--segmentation",1);
+  parser.AddSynonim("--segmentation","-s");
+  parser.AddSynonim("--segmentation","-seg");
+
+  parser.AddOption("--overlay", -1);
+  parser.AddSynonim("--overlay", "-o");
+
+  parser.AddOption("--labels",1);
+  parser.AddSynonim("--labels","--label");
+  parser.AddSynonim("--labels","-l");
+
+  parser.AddOption("--workspace", 1);
+  parser.AddSynonim("--workspace", "-w");
+
+  parser.AddOption("--zoom", 1);
+  parser.AddSynonim("--zoom", "-z");
+
+  // TO BE ADDED
+  // parser.AddOption("--compact", 1);
+  // parser.AddSynonim("--compact", "-c");
+
+  parser.AddOption("--help", 0);
+  parser.AddSynonim("--help", "-h");
+
+  parser.AddOption("--debug-events", 0);
+
+  parser.AddOption("--no-fork", 0);
+  parser.AddOption("--console", 0);
+
+  parser.AddOption("--test", 1);
+  parser.AddOption("--testdir", 1);
+  parser.AddOption("--testacc", 1);
+
+  // This dummy option is actually used internally. It's a work-around for
+  // a buggy behavior on MacOS, when execvp actually causes a file
+  // open event to be fired, which causes the drop dialog to open
+  parser.AddOption("--dummy", 1);
+
+  // Obtain the result
+  CommandLineArgumentParseResult parseResult;
+
+  // Number of trailing arguments
+  int iTrailing = 0;
+
+  // Set up the command line parser with all the options
+  if(!parser.TryParseCommandLine(argc, argv, parseResult, false, iTrailing))
+    {
+    cerr << "Unable to parse command line. Run " << argv[0] << " -h for help" << endl;
+    return -1;
+    }
+
+  // Need help?
+  if(parseResult.IsOptionPresent("--help"))
+    {
+    usage();
+    return 1;
+    }
+
+  // Parse this option before anything else!
+  if(parseResult.IsOptionPresent("--debug-events"))
+    {
+#ifdef SNAP_DEBUG_EVENTS
+    argdata.flagDebugEvents = true;
+#else
+    cerr << "Option --debug-events ignored because ITK-SNAP was compiled "
+            "without the SNAP_DEBUG_EVENTS option. Please recompile." << endl;
+#endif
+    }
+
+  // Check if a workspace is being loaded
+  if(parseResult.IsOptionPresent("--workspace"))
+    {
+    // Check for incompatible options
+    if(parseResult.IsOptionPresent("--grey")
+       || parseResult.IsOptionPresent("--overlay")
+       || parseResult.IsOptionPresent("--labels")
+       || parseResult.IsOptionPresent("--segmentation"))
+      {
+      cerr << "Error: Option -w may not be used with -g, -o, -l or -s options." << endl;
+      return -1;
+      }
+
+    // Get the workspace filename
+    argdata.fnWorkspace = DecodeFilename(parseResult.GetOptionParameter("--workspace"));
+    }
+
+  // No workspace, just images
+  else
+    {
+    // The following situations are possible for main image
+    // itksnap file                       <- load as main image, detect file type
+    // itksnap --gray file                <- load as main image, force gray
+    // itksnap --gray file1 file2         <- ignore file2
+
+    // Check if a main image file is specified
+    bool have_main = false;
+    if(parseResult.IsOptionPresent("--grey"))
+      {
+      argdata.fnMain = DecodeFilename(parseResult.GetOptionParameter("--grey"));
+      have_main = true;
+      }
+    else if(iTrailing < argc)
+      {
+      argdata.fnMain = DecodeFilename(argv[iTrailing]);
+      have_main = true;
+      }
+
+    // If no main, there should be no overlays, segmentation
+    if(!have_main && parseResult.IsOptionPresent("--segmentation"))
+      {
+      cerr << "Error: Option -s must be used together with option -g" << endl;
+      return -1;
+      }
+
+    if(!have_main && parseResult.IsOptionPresent("--overlay"))
+      {
+      cerr << "Error: Option -p must be used together with option -g" << endl;
+      return -1;
+      }
+
+    // Load main image file
+    if(have_main)
+      {
+      // Load the segmentation if supplied
+      if(parseResult.IsOptionPresent("--segmentation"))
+        {
+        // Get the filename
+        argdata.fnSegmentation = DecodeFilename(parseResult.GetOptionParameter("--segmentation"));
+        }
+
+      // Load overlay fs supplied
+      if(parseResult.IsOptionPresent("--overlay"))
+        {
+        for(int i = 0; i < parseResult.GetNumberOfOptionParameters("--overlay"); i++)
+          {
+          // Get the filename
+          argdata.fnOverlay.push_back(DecodeFilename(parseResult.GetOptionParameter("--overlay", i)));
+          }
+        }
+      } // if main image filename supplied
+
+    // Load labels if supplied
+    if(parseResult.IsOptionPresent("--labels"))
+      {
+      // Get the filename
+      argdata.fnLabelDesc = DecodeFilename(parseResult.GetOptionParameter("--labels"));
+      }
+    } // Not loading workspace
+
+  // Set initial zoom if specified
+  if(parseResult.IsOptionPresent("--zoom"))
+    {
+    argdata.xZoomFactor = atof(parseResult.GetOptionParameter("--zoom"));
+    if(argdata.xZoomFactor <= 0.0)
+      {
+      cerr << "Invalid zoom level (" << argdata.xZoomFactor << ") specified" << endl;
+      }
+    }
+
+  // Console flag. On non-Apple UNIX, the console flag is ignored and default
+  // behavior is to fork. On Win/Apple, default behavior is not to fork (assume
+  // launch from OS GUI, ability to respond to open document event on Apple
+#if defined(__UNIX__) && !defined(__APPLE__)
+  argdata.flagConsole = true;
+#else
+  argdata.flagConsole = parseResult.IsOptionPresent("--console");
+#endif
+
+  // Forking behavior.
+  argdata.flagNoFork = parseResult.IsOptionPresent("--no-fork");
+
+  // Testing
+  if(parseResult.IsOptionPresent("--test"))
+    {
+    argdata.xTestId = parseResult.GetOptionParameter("--test");
+    if(parseResult.IsOptionPresent("--testdir"))
+      argdata.fnTestDir = DecodeFilename(parseResult.GetOptionParameter("--testdir"));
+    else
+      argdata.fnTestDir = ".";
+
+    if(parseResult.IsOptionPresent("--testacc"))
+      argdata.xTestAccel = atof(parseResult.GetOptionParameter("--testacc"));
+    else
+      argdata.xTestAccel = 1.0;
+
+    }
+
+  return 0;
+}
+
+
+int main(int argc, char *argv[])
+{  
+  // Test object, which only is allocated if tests are requested. The
+  // reason we declare it here is that the test object allocates a
+  // script engine, which must be deleted at the very end
+  SNAPTestQt *testingEngine = NULL;
+
+  // Parse the command line
+  CommandLineRequest argdata;
+  int exitcode = parse(argc, argv, argdata);
+  if(exitcode != 0)
+    return exitcode;
+
+  // If the program is executed from the console, we would like it to
+  // background and outlive the console. At this point, we can ditch the
+  // connection with the parent shell, i.e., fork the program.
+  if(argdata.flagConsole && !argdata.flagNoFork)
+    SystemInterface::LaunchChildSNAP(argc, argv, true);
+
+  // Debugging mechanism: if no-fork is on, sleep for 60 secs
+  // if(argdata.flagNoFork)
+  //  sleep(60);
+
+  // Turn off event debugging if needed
+#ifdef SNAP_DEBUG_EVENTS
+  flag_snap_debug_events = argdata.flagDebugEvents;
+#endif
+
+  // Setup crash signal handlers
+  SetupSignalHandlers();
+
+  // Turn off ITK and VTK warning windows
+  itk::Object::GlobalWarningDisplayOff();
+  vtkObject::GlobalWarningDisplayOff();
+
+  // Connect Qt to the Renderer subsystem
+  AbstractRenderer::SetPlatformSupport(new QtRendererPlatformSupport());
+
+  // Create an application
+  SNAPQApplication app(argc, argv);
+  Q_INIT_RESOURCE(SNAPResources);
+  Q_INIT_RESOURCE(TestingScripts);
+
+  // Set the application style
+  app.setStyle(QStyleFactory::create("fusion"));
+
+  // Before we can create any of the framework classes, we need to get some
+  // platform-specific functionality to the SystemInterface
+  QtSystemInfoDelegate siDelegate;
+  SystemInterface::SetSystemInfoDelegate(&siDelegate);
+
+  // Create the global UI
+  try 
+    {
+    SmartPtr<GlobalUIModel> gui = GlobalUIModel::New();
+    IRISApplication *driver = gui->GetDriver();
+
+    // Load the user preferences
+    gui->LoadUserPreferences();
+
+    // Create the main window
+    MainImageWindow *mainwin = new MainImageWindow();
+    mainwin->Initialize(gui);
+
+    // Start parsing options
+    IRISWarningList warnings;
+
+    // Check if a workspace is being loaded
+    if(argdata.fnWorkspace.size())
+      {
+      // Put a waiting cursor
+      QtCursorOverride curse(Qt::WaitCursor);
+
+      // Load the workspace
+      try
+        {
+        driver->OpenProject(argdata.fnWorkspace, warnings);
+        }
+      catch(std::exception &exc)
+        {
+        ReportNonLethalException(mainwin, exc, "Workspace Error",
+                                 QString("Failed to load workspace %1").arg(
+                                   from_utf8(argdata.fnWorkspace)));
+        }
+      }
+    else
+      {
+      // Load main image file
+      if(argdata.fnMain.size())
+        {
+        // Put a waiting cursor
+        QtCursorOverride curse(Qt::WaitCursor);
+
+        // Try loading the image
+        try
+          {
+          // Load the main image. If that fails, all else should fail too
+          driver->LoadImage(argdata.fnMain.c_str(), MAIN_ROLE, warnings);
+
+          // Load the segmentation
+          if(argdata.fnSegmentation.size())
+            {
+            try
+              {
+              driver->LoadImage(argdata.fnSegmentation.c_str(), LABEL_ROLE, warnings);
+              }
+            catch(std::exception &exc)
+              {
+              ReportNonLethalException(mainwin, exc, "Image IO Error",
+                                       QString("Failed to load segmentation %1").arg(
+                                         from_utf8(argdata.fnSegmentation)));
+              }
+            }
+
+          // Load the overlays
+          if(argdata.fnOverlay.size())
+            {
+            std::string current_overlay;
+            try
+            {
+              for(int i = 0; i < argdata.fnOverlay.size(); i++)
+                {
+                current_overlay = argdata.fnOverlay[i];
+                driver->LoadImage(current_overlay.c_str(), OVERLAY_ROLE, warnings);
+                }
+            }
+            catch(std::exception &exc)
+              {
+              ReportNonLethalException(mainwin, exc, "Overlay IO Error",
+                                       QString("Failed to load overlay %1").arg(
+                                         from_utf8(current_overlay)));
+              }
+            }
+          }
+        catch(std::exception &exc)
+          {
+          ReportNonLethalException(mainwin, exc, "Image IO Error",
+                                   QString("Failed to load image %1").arg(
+                                     from_utf8(argdata.fnMain)));
+          }
+        } // if main image filename supplied
+
+      if(argdata.fnLabelDesc.size())
+        {
+        try
+          {
+          // Load the label file
+          driver->LoadLabelDescriptions(argdata.fnLabelDesc.c_str());
+          }
+        catch(std::exception &exc)
+          {
+          ReportNonLethalException(mainwin, exc, "Label Description IO Error",
+                                   QString("Failed to load labels from %1").arg(
+                                     from_utf8(argdata.fnLabelDesc)));
+          }
+        }
+      } // Not loading workspace
+
+    // Zoom level
+    if(argdata.xZoomFactor > 0)
+      {
+      gui->GetSliceCoordinator()->SetLinkedZoom(true);
+      gui->GetSliceCoordinator()->SetZoomLevelAllWindows(argdata.xZoomFactor);
+      }
+
+    /*
+     * ADD THIS LATER!
+
+    if(parseResult.IsOptionPresent("--compact"))
+      {
+      string slice = parseResult.GetOptionParameter("--compact");
+      if(slice.length() == 0 || !(slice[0] == 'a' || slice[0] == 'c' || slice[0] == 's'))
+        cerr << "Wrong parameter passed for '--compact', ignoring" << endl;
+      else
+        {
+        DisplayLayout dl = ui->GetDisplayLayout();
+        dl.show_main_ui = false;
+        ui->SetDisplayLayout(dl);
+        dl.show_panel_ui = false;
+        ui->SetDisplayLayout(dl);
+        dl.size = HALF_SIZE;
+        ui->SetDisplayLayout(dl);
+        dl.slice_config = slice[0] == 'a' ? AXIAL : (slice[0] == 'c' ? CORONAL : SAGITTAL);
+        ui->SetDisplayLayout(dl);
+        }
+      }
+      */
+
+    // Configure the IPC communications (as a hidden widget)
+    QtIPCManager *ipcman = new QtIPCManager(mainwin);
+    ipcman->hide();
+    ipcman->SetModel(gui->GetSynchronizationModel());
+
+    // Start in cross-hairs mode
+    gui->GetGlobalState()->SetToolbarMode(CROSSHAIRS_MODE);
+
+    // Show the panel
+    mainwin->ShowFirstTime();
+
+    // Check for updates?
+    mainwin->UpdateAutoCheck();
+
+    // Assign the main window to the application. We do this right before
+    // starting the event loop.
+    app.setMainWindow(mainwin);
+
+    // Do the test
+    if(argdata.xTestId.size())
+      {
+      testingEngine = new SNAPTestQt(mainwin, argdata.fnTestDir, argdata.xTestAccel);
+      testingEngine->LaunchTest(argdata.xTestId);
+      }
+
+    // Run application
+    int rc = app.exec();
+
+    // If everything cool, save the preferences
+    if(!rc)
+      gui->SaveUserPreferences();
+
+    // Unload the main image before all the destructors start firing
+    driver->UnloadMainImage();
+
+    // Get rid of the main window while the model is still alive
+    delete mainwin;
+
+    // Destroy the model after the GUI is destroyed
+    gui = NULL;
+
+    // Destory the test engine
+    if(testingEngine)
+      delete testingEngine;
+
+    // Exit with the return code
+    std::cerr << "Return code : " << rc << std::endl;
+    return rc;
+    }
+  catch(std::exception &exc)
+    {
+    ReportNonLethalException(NULL, exc, "ITK-SNAP failed to start", "Exception occurred during ITK-SNAP startup");
+    exit(-1);
+    }
+
+}
+
diff --git a/GUI/Renderer/AbstractRenderer.cxx b/GUI/Renderer/AbstractRenderer.cxx
new file mode 100644
index 0000000..0c9a0f4
--- /dev/null
+++ b/GUI/Renderer/AbstractRenderer.cxx
@@ -0,0 +1,13 @@
+#include "AbstractRenderer.h"
+
+// The platform support initializes to NULL
+AbstractRendererPlatformSupport *AbstractRenderer::m_PlatformSupport = NULL;
+
+AbstractRenderer::AbstractRenderer()
+{
+}
+
+void AbstractRenderer::SaveAsPNG(std::string filename)
+{
+
+}
diff --git a/GUI/Renderer/AbstractRenderer.h b/GUI/Renderer/AbstractRenderer.h
new file mode 100644
index 0000000..cf75f5a
--- /dev/null
+++ b/GUI/Renderer/AbstractRenderer.h
@@ -0,0 +1,62 @@
+#ifndef ABSTRACTRENDERER_H
+#define ABSTRACTRENDERER_H
+
+#include "AbstractModel.h"
+
+/**
+ * @brief The RendererPlatformSupport class
+ * This class holds various methods that renderers require from the underlying
+ * GUI platform. These include drawing text, for example. Before any renderers
+ * can be used, the renderer platform support must be assigned to the abstract
+ * renderer using the static method AbstractRenderer::SetPlatformSupport()
+ */
+class AbstractRendererPlatformSupport
+{
+public:
+
+  enum FontType { SANS, SERIF, TYPEWRITER };
+  enum HAlign { LEFT=-1, HCENTER=0, RIGHT=1 };
+  enum VAlign { BOTTOM=-1, VCENTER=0, TOP=1 };
+
+  struct FontInfo {
+    FontType type;
+    int pixel_size;
+    bool bold;
+  };
+
+  virtual void RenderTextInOpenGL(
+      const char *text,
+      int x, int y, int w, int h,
+      FontInfo font,
+      int align_horiz, int align_vert,
+      const Vector3d &rgbf) = 0;
+
+  virtual int MeasureTextWidth(const char *text, FontInfo font) = 0;
+};
+
+
+/**
+  A parent class for ITK-SNAP renderers. A renderer implements all the OpenGL
+  drawing code independently of the widget system (Qt).
+  */
+class AbstractRenderer : public AbstractModel
+{
+public:
+
+  virtual void initializeGL() {}
+  virtual void resizeGL(int w, int h) {}
+  virtual void paintGL() = 0;
+
+  static void SetPlatformSupport(AbstractRendererPlatformSupport *support)
+  { m_PlatformSupport = support; }
+
+  virtual void SaveAsPNG(std::string filename);
+
+protected:
+  AbstractRenderer();
+  virtual ~AbstractRenderer() {}
+
+  static AbstractRendererPlatformSupport *m_PlatformSupport;
+};
+
+#endif // ABSTRACTRENDERER_H
diff --git a/GUI/Renderer/AbstractVTKRenderer.cxx b/GUI/Renderer/AbstractVTKRenderer.cxx
new file mode 100644
index 0000000..b74bbce
--- /dev/null
+++ b/GUI/Renderer/AbstractVTKRenderer.cxx
@@ -0,0 +1,127 @@
+#include "AbstractVTKRenderer.h"
+
+#include <vtkGenericOpenGLRenderWindow.h>
+#include <vtkGenericRenderWindowInteractor.h>
+#include <vtkInteractorStyleTrackballCamera.h>
+#include <vtkInteractorStyleTrackballActor.h>
+#include <vtkRenderer.h>
+#include <vtkCommand.h>
+#include <vtkObjectFactory.h>
+
+class QtRenderWindowInteractor : public vtkRenderWindowInteractor
+{
+public:
+  static QtRenderWindowInteractor *New();
+
+  vtkTypeMacro(QtRenderWindowInteractor, vtkRenderWindowInteractor);
+
+  virtual void Initialize() { this->Initialized = 1; this->Enable(); }
+  // virtual void Start() { }
+  // virtual void TerminateApp() { }
+
+
+protected:
+
+  QtRenderWindowInteractor() {}
+  virtual ~QtRenderWindowInteractor() {}
+
+};
+
+vtkStandardNewMacro(QtRenderWindowInteractor);
+
+
+
+AbstractVTKRenderer::AbstractVTKRenderer()
+{
+  // Create a VTK renderer
+  m_Renderer = vtkSmartPointer<vtkRenderer>::New();
+
+  // Set up a render window that uses GL commands to paint
+  m_RenderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
+
+  // Add the renderer to the window
+  m_RenderWindow->AddRenderer(m_Renderer);
+
+  // Set up the interactor
+  m_Interactor = vtkSmartPointer<QtRenderWindowInteractor>::New();
+  m_Interactor->SetRenderWindow(m_RenderWindow);
+  m_Interactor->SetInteractorStyle(NULL);
+}
+
+void AbstractVTKRenderer::paintGL()
+{
+  // Update the scene
+  this->Update();
+
+  // Make sure the interactor is enabled
+  if(!m_Interactor->GetInitialized())
+    {
+    m_Interactor->Initialize();
+    m_Interactor->Enable();
+    }
+
+  // Clear the screen
+  glClearColor(0.0, 0.0, 0.0, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  // Do the rendering but only when interactor is enabled (from QVTKWidget2)
+  m_RenderWindow->Render();
+}
+
+void AbstractVTKRenderer::initializeGL()
+{
+  // Is this what we should be calling?
+  m_RenderWindow->OpenGLInit();
+}
+
+vtkRenderWindow *AbstractVTKRenderer::GetRenderWindow()
+{
+  return m_RenderWindow;
+}
+
+vtkRenderWindowInteractor *AbstractVTKRenderer::GetRenderWindowInteractor()
+{
+  return m_Interactor;
+}
+
+void AbstractVTKRenderer::SetInteractionStyle(AbstractVTKRenderer::InteractionStyle style)
+{
+  vtkSmartPointer<vtkInteractorObserver> stylePtr = NULL;
+  switch(style)
+    {
+    case AbstractVTKRenderer::NO_INTERACTION:
+      stylePtr = NULL;
+      break;
+    case AbstractVTKRenderer::TRACKBALL_CAMERA:
+      stylePtr = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
+      break;
+    case AbstractVTKRenderer::TRACKBALL_ACTOR:
+      stylePtr = vtkSmartPointer<vtkInteractorStyleTrackballActor>::New();
+      break;
+    case AbstractVTKRenderer::PICKER:
+      stylePtr = vtkSmartPointer<vtkInteractorStyleTrackballActor>::New();
+      break;
+    }
+  m_Interactor->SetInteractorStyle(stylePtr);
+}
+
+void AbstractVTKRenderer::SyncronizeCamera(Self *reference)
+{
+  // Make a copy of the camera
+  m_Renderer->SetActiveCamera(reference->m_Renderer->GetActiveCamera());
+
+  // Respond to modified events from the source interactor
+  Rebroadcast(reference->m_Interactor,
+              vtkCommand::ModifiedEvent, ModelUpdateEvent());
+
+  // And vice versa
+  reference->Rebroadcast(m_Interactor,
+                         vtkCommand::ModifiedEvent, ModelUpdateEvent());
+}
+
+void AbstractVTKRenderer::resizeGL(int w, int h)
+{
+  // Pass the size to VTK
+  m_RenderWindow->SetSize(w, h);
+  m_Interactor->UpdateSize(w, h);
+}
diff --git a/GUI/Renderer/AbstractVTKRenderer.h b/GUI/Renderer/AbstractVTKRenderer.h
new file mode 100644
index 0000000..3369ef2
--- /dev/null
+++ b/GUI/Renderer/AbstractVTKRenderer.h
@@ -0,0 +1,65 @@
+#ifndef ABSTRACTVTKRENDERER_H
+#define ABSTRACTVTKRENDERER_H
+
+#include "AbstractRenderer.h"
+#include <vtkSmartPointer.h>
+
+class vtkRenderer;
+class vtkRenderWindow;
+class vtkGenericOpenGLRenderWindow;
+class vtkRenderWindowInteractor;
+
+/**
+ * @brief The child of AbstractRenderer that holds a VTK render window
+ * and can render VTK objects such as polydata. This class also holds an
+ * interactor, which can be connected to a widget's events. However, by
+ * default, interaction is disabled, and must be enabled by calling
+ * SetInteractionStyle
+ */
+class AbstractVTKRenderer : public AbstractRenderer
+{
+public:
+
+  irisITKObjectMacro(AbstractVTKRenderer, AbstractRenderer)
+
+  /**
+   * @brief Enums corresponding to different VTK interaction styles
+   */
+  enum InteractionStyle {
+    NO_INTERACTION = 0, TRACKBALL_CAMERA, TRACKBALL_ACTOR, PICKER
+  };
+
+  virtual void paintGL();
+  virtual void resizeGL(int w, int h);
+  virtual void initializeGL();
+
+  vtkRenderWindow *GetRenderWindow();
+  vtkRenderWindowInteractor *GetRenderWindowInteractor();
+
+  void SetInteractionStyle(InteractionStyle style);
+
+  /**
+   * Synchronizes camera with another instance of this class. Internally,
+   * this copies the camera pointer from the reference object.
+   */
+  void SyncronizeCamera(Self *reference);
+
+  irisGetSetMacro(BackgroundColor, Vector3d)
+
+protected:
+
+  // Render window object used to render VTK stuff
+  vtkSmartPointer<vtkGenericOpenGLRenderWindow> m_RenderWindow;
+  vtkSmartPointer<vtkRenderer> m_Renderer;
+
+  // The interactor
+  vtkSmartPointer<vtkRenderWindowInteractor> m_Interactor;
+
+  // Background color
+  Vector3d m_BackgroundColor;
+
+  AbstractVTKRenderer();
+  virtual ~AbstractVTKRenderer() {}
+};
+
+#endif // ABSTRACTVTKRENDERER_H
diff --git a/GUI/Renderer/AbstractVTKSceneRenderer.cxx b/GUI/Renderer/AbstractVTKSceneRenderer.cxx
new file mode 100644
index 0000000..3b39ab3
--- /dev/null
+++ b/GUI/Renderer/AbstractVTKSceneRenderer.cxx
@@ -0,0 +1,29 @@
+#include "AbstractVTKSceneRenderer.h"
+
+#include <vtkGenericOpenGLRenderWindow.h>
+#include <vtkRenderer.h>
+#include <vtkContextView.h>
+
+AbstractVTKSceneRenderer::AbstractVTKSceneRenderer()
+  : AbstractVTKRenderer()
+{
+  // Initialize some properties of the renderer
+  this->m_RenderWindow->SwapBuffersOff();
+  this->m_RenderWindow->SetMultiSamples(0);
+
+  // Set up the context view
+  m_ContextView = vtkSmartPointer<vtkContextView>::New();
+  m_ContextView->SetRenderWindow(m_RenderWindow);
+
+  // Set the background to black
+  m_BackgroundColor.fill(0.0);
+}
+
+void AbstractVTKSceneRenderer::paintGL()
+{
+  // Set renderer background
+  m_ContextView->GetRenderer()->SetBackground(m_BackgroundColor.data_block());
+
+  // Update the scene
+  AbstractVTKRenderer::paintGL();
+}
diff --git a/GUI/Renderer/AbstractVTKSceneRenderer.h b/GUI/Renderer/AbstractVTKSceneRenderer.h
new file mode 100644
index 0000000..6501659
--- /dev/null
+++ b/GUI/Renderer/AbstractVTKSceneRenderer.h
@@ -0,0 +1,49 @@
+#ifndef ABSTRACTVTKSCENERENDERER_H
+#define ABSTRACTVTKSCENERENDERER_H
+
+#include "AbstractVTKRenderer.h"
+#include <vtkSmartPointer.h>
+
+class vtkRenderer;
+class vtkRenderWindow;
+class vtkGenericOpenGLRenderWindow;
+class vtkContextView;
+
+/**
+  This class provides support for rendering a VTK scene in OpenGL. It sets
+  up the basic infrastructure, but the child class is the one responsible
+  for maintaining and updating the scene.
+
+  This class should be used for rendering 2D scenes (charts, etc), not 3D
+  data such as vtkPolyData. For that, @see AbstractVTKRenderer
+
+  The child class should initialize the scene (vtkProps) in its constructor
+  and add these props to the m_Renderer.
+
+  The child class should override the OnUpdate() method inherited from
+  AbstractModel(), and in that method, ensure that the scene is up to date,
+  based on the events currently present in the EventBucket
+  */
+class AbstractVTKSceneRenderer : public AbstractVTKRenderer
+{
+public:
+
+  irisITKObjectMacro(AbstractVTKSceneRenderer, AbstractVTKRenderer)
+
+  virtual void paintGL();
+
+  irisGetSetMacro(BackgroundColor, Vector3d)
+
+protected:
+
+  // Render window object used to render VTK stuff
+  vtkSmartPointer<vtkContextView> m_ContextView;
+
+  // Background color
+  Vector3d m_BackgroundColor;
+
+  AbstractVTKSceneRenderer();
+  virtual ~AbstractVTKSceneRenderer() {}
+};
+
+#endif // ABSTRACTVTKSCENERENDERER_H
diff --git a/GUI/Renderer/ColorMapRenderer.cxx b/GUI/Renderer/ColorMapRenderer.cxx
new file mode 100644
index 0000000..0f8e8ba
--- /dev/null
+++ b/GUI/Renderer/ColorMapRenderer.cxx
@@ -0,0 +1,223 @@
+#include "ColorMapRenderer.h"
+#include "ColorMapModel.h"
+#include "SNAPOpenGL.h"
+
+using namespace std;
+
+ColorMapRenderer::ColorMapRenderer()
+{
+  m_TextureId = 0xffffffff;
+  m_Width = 0;
+  m_Height = 0;
+}
+
+ColorMapRenderer::~ColorMapRenderer()
+{
+
+}
+
+void
+ColorMapRenderer
+::SetModel(ColorMapModel *model)
+{
+  this->m_Model = model;
+}
+
+void ColorMapRenderer::paintGL()
+{
+  // Clear the viewport
+  glClearColor(1.0, 1.0, 1.0, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  // Push the related attributes
+  glPushAttrib(GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT | GL_LINE_BIT | GL_TEXTURE_BIT);
+
+  // Disable lighting
+  glEnable(GL_TEXTURE_2D);
+
+  // Generate the texture for the background
+  const GLsizei boxw = 16;
+  if(m_TextureId == 0xffffffff)
+    {
+    // Create a checkerboard
+    unsigned char *boxarr = new unsigned char[boxw * boxw], *p = boxarr;
+    for(GLsizei i = 0; i < boxw; i++)
+      for(GLsizei j = 0; j < boxw; j++)
+        if((i < boxw / 2 && j < boxw / 2) || (i > boxw / 2 && j > boxw / 2))
+          *p++ = 0xef;
+        else
+          *p++ = 0xff;
+
+    glGenTextures(1, &m_TextureId);
+    glBindTexture(GL_TEXTURE_2D, m_TextureId);
+
+    // Properties for the texture
+    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+    // Turn off modulo-4 rounding in GL
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, boxw, boxw, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, boxarr);
+    delete boxarr;
+    }
+
+  // Draw the background pattern
+  glBindTexture(GL_TEXTURE_2D, m_TextureId);
+
+  glColor3ub(0xff,0xff,0xff);
+
+  glBegin(GL_QUADS);
+  double tx = m_Width * 1.0 / boxw;
+  double ty = m_Height * 1.0 / boxw;
+  glTexCoord2d(0.0, 0.0); glVertex2d(-0.1, -0.1);
+  glTexCoord2d(tx, 0.0); glVertex2d(1.1, -0.1);
+  glTexCoord2d(tx, ty); glVertex2d(1.1, 1.1);
+  glTexCoord2d(0.0, ty); glVertex2d(-0.1, 1.1);
+  glEnd();
+
+  glDisable(GL_LIGHTING);
+  glDisable(GL_TEXTURE_2D);
+
+
+  if(m_Model->GetLayer() != NULL && m_Model->GetColorMap() != NULL)
+    {
+    // Turn on alpha blending
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+
+    // Get the starting and ending color values
+    ColorMap *cmap = m_Model->GetColorMap();
+    ColorMap::RGBAType v0 = cmap->MapIndexToRGBA(-0.1);
+    ColorMap::RGBAType v1 = cmap->MapIndexToRGBA(1.1);
+
+    // Draw the actual texture
+    glBegin(GL_QUADS);
+
+    // Draw the color before 0.0
+    glColor4ub(v0[0], v0[1], v0[2], 0x00); glVertex2d(-0.1,0.0);
+    glColor4ub(v0[0], v0[1], v0[2], 0xff); glVertex2d(-0.1,1.0);
+
+    // Render the colormap
+    for(size_t i = 0; i < 512; i++)
+      {
+      double t = i / 511.0;
+      ColorMap::RGBAType rgba = cmap->MapIndexToRGBA(t);
+
+      glColor4ub(rgba[0], rgba[1], rgba[2], 0xff);
+      glVertex2d(t, 1.0);
+      glColor4ub(rgba[0], rgba[1], rgba[2], 0x00);
+      glVertex2d(t, 0.0);
+      glColor4ub(rgba[0], rgba[1], rgba[2], 0x00);
+      glVertex2d(t, 0.0);
+      glColor4ub(rgba[0], rgba[1], rgba[2], 0xff);
+      glVertex2d(t, 1.0);
+      }
+
+    // Draw the color after 1.0
+    glColor4ub(v1[0], v1[1], v1[2], 0xff); glVertex2d(1.1,1.0);
+    glColor4ub(v1[0], v1[1], v1[2], 0x00); glVertex2d(1.1,0.0);
+
+    // Done drawing
+    glEnd();
+
+    // Draw the gridlines
+    glBegin(GL_LINES);
+    glColor4ub(0x80, 0x80, 0x80, 0xff);
+
+    // Horizontal gridlines
+    glVertex2d(-0.1, 0.0); glVertex2d( 1.1, 0.0);
+    glVertex2d(-0.1, 0.5); glVertex2d( 1.1, 0.5);
+    glVertex2d(-0.1, 1.0); glVertex2d( 1.1, 1.0);
+
+    // Vertical gridlines
+    glVertex2d(0.0, -0.1); glVertex2d(0.0, 1.1);
+    glVertex2d(0.25, -0.1); glVertex2d(0.25, 1.1);
+    glVertex2d(0.5, -0.1); glVertex2d(0.5, 1.1);
+    glVertex2d(0.75, -0.1); glVertex2d(0.75, 1.1);
+    glVertex2d(1.0, -0.1); glVertex2d(1.0, 1.1);
+
+    glEnd();
+
+    // Draw the Alpha curve
+    glEnable(GL_LINE_SMOOTH);
+    glLineWidth(3.0);
+
+    glBegin(GL_LINE_STRIP);
+    glColor4ub(0x00,0x00,0x00,0xff);
+    glVertex2d(-0.1, v0[3] / 255.0);
+
+    for(size_t i = 0; i < cmap->GetNumberOfCMPoints(); i++)
+      {
+      ColorMap::CMPoint p = cmap->GetCMPoint(i);
+      glVertex2d(p.m_Index, p.m_RGBA[0][3] / 255.0);
+      glVertex2d(p.m_Index, p.m_RGBA[1][3] / 255.0);
+      }
+
+    glVertex2d(1.1, v1[3] / 255.0);
+    glEnd();
+
+    // Define select and non-select colors
+    Vector3ui clrBorderSelect(0xff, 0x00, 0xff);
+    Vector3ui clrBorderPlain(0x00, 0x00, 0x00);
+
+    // Draw circles around the points
+    glDisable(GL_LIGHTING);
+
+    glLineWidth(1.0);
+    for(size_t i = 0; i < cmap->GetNumberOfCMPoints(); i++)
+      {
+      ColorMap::CMPoint p = cmap->GetCMPoint(i);
+
+
+      glColor3ub(p.m_RGBA[0][0],p.m_RGBA[0][1],p.m_RGBA[0][2]);
+      bool select = m_Model->IsControlSelected(i, ColorMapLayerProperties::LEFT);
+      gl_draw_circle_with_border(p.m_Index, p.m_RGBA[0][3] / 255.0, 5.0,
+                                 m_Width, m_Height,
+                                 select ? clrBorderSelect : clrBorderPlain);
+
+      if(p.m_RGBA[0][3] != p.m_RGBA[1][3])
+        {
+        glColor3ub(p.m_RGBA[1][0],p.m_RGBA[1][1],p.m_RGBA[1][2]);
+        bool select = m_Model->IsControlSelected(i, ColorMapLayerProperties::RIGHT);
+        gl_draw_circle_with_border(p.m_Index, p.m_RGBA[1][3] / 255.0, 5.0,
+                                   m_Width, m_Height,
+                                   select ? clrBorderSelect : clrBorderPlain);
+        }
+      }
+    }
+
+  // Pop the attributes
+  glPopAttrib();
+
+  // Done
+  glFlush();
+
+}
+
+void ColorMapRenderer::resizeGL(int w, int h)
+{
+  // Instead of using the w/h passed in here, which are in physical pixel units,
+  // we will use 'logical' pixel units on Retina-type displays. This makes the
+  // sizes of all circles and such consistent between Retina and normal displays
+
+  if(!m_Model) return;
+
+  Vector2ui vpl = m_Model->GetViewportReporter()->GetLogicalViewportSize();
+
+  // Set up the basic projection with a small margin
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  gluOrtho2D(-0.1,1.1,-0.1,1.1);
+  glViewport(0,0,vpl[0],vpl[1]);
+
+  // Establish the model view matrix
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+
+  // Store the dimensions
+  m_Width = vpl[0];
+  m_Height = vpl[1];
+}
diff --git a/GUI/Renderer/ColorMapRenderer.h b/GUI/Renderer/ColorMapRenderer.h
new file mode 100644
index 0000000..a8970df
--- /dev/null
+++ b/GUI/Renderer/ColorMapRenderer.h
@@ -0,0 +1,33 @@
+#ifndef COLORMAPRENDERER_H
+#define COLORMAPRENDERER_H
+
+#include "AbstractRenderer.h"
+
+class ColorMapModel;
+
+class ColorMapRenderer : public AbstractRenderer
+{
+public:
+  irisITKObjectMacro(ColorMapRenderer, AbstractRenderer)
+
+
+  void SetModel(ColorMapModel *model);
+
+  void resizeGL(int w, int h);
+  void paintGL();
+
+protected:
+
+  ColorMapRenderer();
+  virtual ~ColorMapRenderer();
+
+  ColorMapModel *m_Model;
+
+
+  unsigned int m_TextureId;
+  unsigned int m_Width, m_Height;
+};
+
+
+
+#endif // COLORMAPRENDERER_H
diff --git a/GUI/Renderer/CrosshairsRenderer.cxx b/GUI/Renderer/CrosshairsRenderer.cxx
new file mode 100644
index 0000000..d504980
--- /dev/null
+++ b/GUI/Renderer/CrosshairsRenderer.cxx
@@ -0,0 +1,95 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "CrosshairsRenderer.h"
+#include "OrthogonalSliceCursorNavigationModel.h"
+#include "GenericSliceModel.h"
+#include "SNAPAppearanceSettings.h"
+#include "GlobalUIModel.h"
+#include "GenericSliceRenderer.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+
+CrosshairsRenderer::CrosshairsRenderer()
+{
+  m_Model = NULL;
+}
+
+void CrosshairsRenderer::paintGL()
+{
+  assert(m_Model);
+
+  GenericSliceModel *parentModel = this->GetParentRenderer()->GetModel();
+  SNAPAppearanceSettings *as =
+      parentModel->GetParentUI()->GetAppearanceSettings();
+
+  // Get the line color, thickness and dash spacing for the crosshairs
+  OpenGLAppearanceElement *elt =
+    this->GetParentRenderer()->IsThumbnailDrawing()
+    ? as->GetUIElement(SNAPAppearanceSettings::CROSSHAIRS_THUMB)
+    : as->GetUIElement(SNAPAppearanceSettings::CROSSHAIRS);
+
+  // Exit if the crosshars are not drawn
+  if(!elt->GetVisible()) return;
+
+  // Get the current cursor position
+  Vector3ui xCursorInteger = parentModel->GetDriver()->GetCursorPosition();
+
+  // Shift the cursor position by by 0.5 in order to have it appear
+  // between voxels
+  Vector3f xCursorImage = to_float(xCursorInteger) + Vector3f(0.5f);
+
+  // Get the cursor position on the slice
+  Vector3f xCursorSlice = parentModel->MapImageToSlice(xCursorImage);
+
+  // Upper and lober bounds to which the crosshairs are drawn
+  Vector2i lower(0);
+  Vector2i upper = parentModel->GetSliceSize().extract(2);
+
+  // Set line properties
+  glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
+
+  // Apply the line properties; thick line is only applied in zoom thumbnail (?)
+  elt->ApplyLineSettings();
+
+  // Apply the color
+  glColor3dv(elt->GetNormalColor().data_block());
+
+  // Refit matrix so that the lines are centered on the current pixel
+  glPushMatrix();
+  glTranslated( xCursorSlice(0), xCursorSlice(1), 0.0 );
+
+  // Paint the cross-hairs
+  glBegin(GL_LINES);
+  glVertex2f(0, 0); glVertex2f(lower(0) - xCursorSlice(0), 0);
+  glVertex2f(0, 0); glVertex2f(upper(0) - xCursorSlice(0), 0);
+  glVertex2f(0, 0); glVertex2f(0, lower(1) - xCursorSlice(1));
+  glVertex2f(0, 0); glVertex2f(0, upper(1) - xCursorSlice(1));
+  glEnd();
+
+  glPopMatrix();
+  glPopAttrib();
+}
diff --git a/GUI/Renderer/CrosshairsRenderer.h b/GUI/Renderer/CrosshairsRenderer.h
new file mode 100644
index 0000000..8528e5d
--- /dev/null
+++ b/GUI/Renderer/CrosshairsRenderer.h
@@ -0,0 +1,55 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef CROSSHAIRSRENDERER_H
+#define CROSSHAIRSRENDERER_H
+
+#include "SNAPCommon.h"
+#include "GenericSliceRenderer.h"
+
+class OrthogonalSliceCursorNavigationModel;
+class GenericSliceRenderer;
+
+class CrosshairsRenderer : public SliceRendererDelegate
+{
+public:
+
+  irisITKObjectMacro(CrosshairsRenderer, SliceRendererDelegate)
+
+  irisSetMacro(Model, OrthogonalSliceCursorNavigationModel *)
+  irisGetMacro(Model, OrthogonalSliceCursorNavigationModel *)
+
+  void paintGL();
+
+protected:
+
+  CrosshairsRenderer();
+  virtual ~CrosshairsRenderer() {}
+
+  OrthogonalSliceCursorNavigationModel *m_Model;
+};
+
+#endif // CROSSHAIRSRENDERER_H
diff --git a/GUI/Renderer/EdgePreprocessingSettingsRenderer.cxx b/GUI/Renderer/EdgePreprocessingSettingsRenderer.cxx
new file mode 100644
index 0000000..80c6c5a
--- /dev/null
+++ b/GUI/Renderer/EdgePreprocessingSettingsRenderer.cxx
@@ -0,0 +1,87 @@
+#include "EdgePreprocessingSettingsRenderer.h"
+
+#include <vtkChartXY.h>
+#include <vtkPlot.h>
+#include <vtkFloatArray.h>
+#include <vtkTable.h>
+#include <vtkContextView.h>
+#include <vtkContextScene.h>
+#include <vtkAxis.h>
+#include <SnakeWizardModel.h>
+
+#include <vtkRenderWindow.h>
+#include <vtkRenderWindowInteractor.h>
+
+const unsigned int EdgePreprocessingSettingsRenderer::NUM_POINTS = 256;
+
+EdgePreprocessingSettingsRenderer::EdgePreprocessingSettingsRenderer()
+{
+  m_Model = NULL;
+
+  // Set up the scene for rendering
+  m_Chart = vtkSmartPointer<vtkChartXY>::New();
+
+  // Add the chart to the renderer
+  m_ContextView->GetScene()->AddItem(m_Chart);
+
+  // Set up the data
+  m_DataX = vtkSmartPointer<vtkFloatArray>::New();
+  m_DataX->SetName("Edge Strength (Gradient Mangitude)");
+  m_DataY = vtkSmartPointer<vtkFloatArray>::New();
+  m_DataY->SetName("Speed Image Value");
+
+  // Set up the table
+  m_PlotTable = vtkSmartPointer<vtkTable>::New();
+  m_PlotTable->AddColumn(m_DataX);
+  m_PlotTable->AddColumn(m_DataY);
+  m_PlotTable->SetNumberOfRows(NUM_POINTS);
+
+  // Set up the plot
+  vtkPlot *plot = m_Chart->AddPlot(vtkChart::LINE);
+  plot->SetInputData(m_PlotTable, 0, 1);
+  plot->SetColor(1, 0, 0);
+  plot->SetWidth(1.0);
+  plot->GetYAxis()->SetBehavior(vtkAxis::FIXED);
+  plot->GetYAxis()->SetMinimum(-0.05);
+  plot->GetYAxis()->SetMaximum(1.05);
+  plot->GetXAxis()->SetTitle("Edge Strength (Gradient Mangitude)");
+  plot->GetYAxis()->SetTitle("Speed Value");
+  plot->GetXAxis()->SetBehavior(vtkAxis::AUTO);
+
+  // TODO: we could also render a histogram here
+
+  // Set the background to white
+  m_BackgroundColor.fill(1.0);
+
+}
+
+void EdgePreprocessingSettingsRenderer::SetModel(SnakeWizardModel *model)
+{
+  this->m_Model = model;
+
+  // Rebroadcast the relevant events from the model in order for the
+  // widget that uses this renderer to cause an update
+  Rebroadcast(model, SnakeWizardModel::EdgePreprocessingSettingsUpdateEvent(),
+              ModelUpdateEvent());
+}
+
+void EdgePreprocessingSettingsRenderer::UpdatePlotValues()
+{
+  if(m_Model->CheckState(SnakeWizardModel::UIF_EDGEPROCESSING_ENABLED))
+    {
+    // Compute the preprocessing function
+    m_Model->EvaluateEdgePreprocessingFunction(NUM_POINTS,
+                                               m_DataX->GetPointer(0),
+                                               m_DataY->GetPointer(0));
+    m_PlotTable->Modified();
+    m_Chart->RecalculateBounds();
+    }
+}
+
+
+void EdgePreprocessingSettingsRenderer::OnUpdate()
+{
+  // Update if any events took place
+  this->UpdatePlotValues();
+}
+
diff --git a/GUI/Renderer/EdgePreprocessingSettingsRenderer.h b/GUI/Renderer/EdgePreprocessingSettingsRenderer.h
new file mode 100644
index 0000000..0bbf5c9
--- /dev/null
+++ b/GUI/Renderer/EdgePreprocessingSettingsRenderer.h
@@ -0,0 +1,44 @@
+#ifndef EDGEPREPROCESSINGSETTINGSRENDERER_H
+#define EDGEPREPROCESSINGSETTINGSRENDERER_H
+
+#include "AbstractVTKSceneRenderer.h"
+#include "vtkSmartPointer.h"
+
+class vtkActor;
+class vtkPropAssembly;
+class vtkChartXY;
+class vtkFloatArray;
+class vtkPlot;
+class vtkTable;
+
+class SnakeWizardModel;
+
+class EdgePreprocessingSettingsRenderer : public AbstractVTKSceneRenderer
+{
+public:
+  irisITKObjectMacro(EdgePreprocessingSettingsRenderer, AbstractVTKSceneRenderer)
+
+  void SetModel(SnakeWizardModel *model);
+
+  void OnUpdate();
+
+  void UpdatePlotValues();
+
+protected:
+
+  EdgePreprocessingSettingsRenderer();
+  virtual ~EdgePreprocessingSettingsRenderer() {}
+
+  SnakeWizardModel *m_Model;
+
+  // Number of data points
+  static const unsigned int NUM_POINTS;
+
+  // Rendering stuff
+  vtkSmartPointer<vtkChartXY> m_Chart;
+  vtkSmartPointer<vtkTable> m_PlotTable;
+  vtkSmartPointer<vtkPlot> m_Plot;
+  vtkSmartPointer<vtkFloatArray> m_DataX, m_DataY;
+};
+
+#endif // EDGEPREPROCESSINGSETTINGSRENDERER_H
diff --git a/GUI/Renderer/GLToPNG.cxx b/GUI/Renderer/GLToPNG.cxx
new file mode 100644
index 0000000..562fa89
--- /dev/null
+++ b/GUI/Renderer/GLToPNG.cxx
@@ -0,0 +1,92 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: GLToPNG.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/05/01 21:29:32 $
+  Version:   $Revision: 1.4 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#include "GLToPNG.h"
+#include "SNAPOpenGL.h"
+
+#include <iostream>
+using namespace std;
+
+vtkImageData* GLToVTKImageData(unsigned int format, int x, int y, int w, int h) 
+{
+  // Cast the format to GL enum
+  GLenum glformat = (GLenum) format;
+
+  // OSX does double buffer automatically (???)
+  //glReadBuffer(GL_BACK);
+  unsigned int GL_comps = 0;
+  if (glformat == GL_RGBA) 
+    {
+    GL_comps = 4;
+    } 
+  else if (glformat == GL_RGB) 
+    {
+    GL_comps = 3;
+    } 
+  else 
+    {
+    std::cerr << "Invalid GLenum" << endl;
+    exit(1);
+    }
+
+  unsigned char* pixmap = new unsigned char[w*h*GL_comps];
+  glReadPixels(x, y, w, h, format, GL_UNSIGNED_BYTE, pixmap);
+
+  // convert to vtkImageData
+  vtkImageData* img = vtkImageData::New();
+  img->SetDimensions(w, h, 1);
+  img->AllocateScalars(VTK_UNSIGNED_CHAR, GL_comps);
+
+  int rowSize = w*GL_comps;
+  unsigned char* pixmap2 = pixmap;
+  unsigned char* imgPtr = (unsigned char*) img->GetScalarPointer(0, 0, 0);
+  for (int i = 0; i < h; ++i) 
+    {
+    memcpy(imgPtr, pixmap2, rowSize);
+    imgPtr += rowSize;
+    pixmap2 += rowSize;
+    }
+  delete[] pixmap;
+  return img;
+}
+
+void VTKImageDataToPNG(vtkImageData* img, const char* filename)
+{
+  vtkPNGWriter* pngw = vtkPNGWriter::New();
+  pngw->SetInputData(img);
+  pngw->SetFileName(filename);
+  pngw->Write();
+  pngw->Delete();
+}
+
diff --git a/GUI/Renderer/GLToPNG.h b/GUI/Renderer/GLToPNG.h
new file mode 100644
index 0000000..2efedd1
--- /dev/null
+++ b/GUI/Renderer/GLToPNG.h
@@ -0,0 +1,58 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: GLToPNG.h,v $
+  Language:  C++
+  Date:      $Date: 2007/12/30 04:05:28 $
+  Version:   $Revision: 1.2 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#ifndef __GLToPNG_h_
+#define __GLToPNG_h_
+
+/**
+ * 
+ * Simple Functions that convert GL buffer into vtkImageData
+ * and save the vtkImageData as PNG file
+ * 
+ * 01/25/2004
+ * Hui Gary Zhang
+ *
+ */
+
+#include "vtkImageData.h"
+#include "vtkPNGWriter.h"
+
+// convert a GL buffer into vtkImageData
+vtkImageData* GLToVTKImageData(unsigned int format, int x, int y, int w, int h);
+
+// output vtkImageData as PNG
+void VTKImageDataToPNG(vtkImageData* img, const char* filename);
+
+#endif
+
diff --git a/GUI/Renderer/GMMRenderer.cxx b/GUI/Renderer/GMMRenderer.cxx
new file mode 100644
index 0000000..47c9255
--- /dev/null
+++ b/GUI/Renderer/GMMRenderer.cxx
@@ -0,0 +1,177 @@
+#include "GMMRenderer.h"
+
+#include "SnakeWizardModel.h"
+#include "IRISApplication.h"
+#include "GlobalUIModel.h"
+#include "UnsupervisedClustering.h"
+#include "GaussianMixtureModel.h"
+#include "ImageWrapperBase.h"
+#include "LayerHistogramPlotAssembly.h"
+#include "SNAPCommon.h"
+#include "ScalarImageHistogram.h"
+
+#include <vtkChartXY.h>
+#include <vtkPlot.h>
+#include <vtkDoubleArray.h>
+#include <vtkTable.h>
+#include <vtkContextView.h>
+#include <vtkContextMouseEvent.h>
+#include <vtkContextScene.h>
+#include <vtkAxis.h>
+#include "vtkGenericOpenGLRenderWindow.h"
+
+unsigned int GMMRenderer::NUM_POINTS = 200;
+
+GMMRenderer::GMMRenderer()
+{
+  m_Model = NULL;
+
+  // Set up the scene for rendering
+  m_Chart = vtkSmartPointer<vtkChartXY>::New();
+  m_Chart->SetActionToButton(vtkChartXY::PAN, vtkContextMouseEvent::LEFT_BUTTON);
+  m_Chart->SetActionToButton(vtkChartXY::ZOOM, vtkContextMouseEvent::RIGHT_BUTTON);
+  m_Chart->SetShowLegend(true);
+
+  // Create the histogram assembly
+  m_HistogramAssembly = new LayerHistogramPlotAssembly();
+
+  // Add the chart to the renderer
+  m_ContextView->GetScene()->AddItem(m_Chart);
+
+  // Set the background to white
+  m_BackgroundColor.fill(1.0);
+
+  // Customize the render window
+  this->m_RenderWindow->SetMultiSamples(0);
+  this->m_RenderWindow->SetLineSmoothing(1);
+  this->m_RenderWindow->SetPolygonSmoothing(1);
+}
+
+
+void GMMRenderer::SetModel(SnakeWizardModel *model)
+{
+  m_Model = model;
+
+  // Rebroadcast the relevant events from the model in order for the
+  // widget that uses this renderer to cause an update
+  Rebroadcast(model, SnakeWizardModel::GMMModifiedEvent(), ModelUpdateEvent());
+
+  // Also listen to changes in the plotted component
+  Rebroadcast(model->GetClusterPlottedComponentModel(),
+              ValueChangedEvent(), ModelUpdateEvent());
+}
+
+void GMMRenderer::OnUpdate()
+{
+  this->UpdatePlotValues();
+}
+
+void GMMRenderer::UpdatePlotValues()
+{
+  int comp = m_Model->GetClusterPlottedComponentModel()->GetValue();
+
+  // Is clustering support enabled?
+  IRISApplication *app = m_Model->GetParent()->GetDriver();
+  UnsupervisedClustering *uc = app->GetClusteringEngine();
+  if(uc)
+    {
+    // Get the component of interest
+    ScalarImageWrapperBase *cw =
+        m_Model->GetLayerAndIndexForNthComponent(comp).ComponentWrapper;
+
+    // Get the range of the component
+    double cmin = cw->GetImageMinNative(), cmax = cw->GetImageMaxNative();
+
+    // Remove all plots from the chart
+    m_Chart->ClearPlots();
+
+    // Add and set up the histogram plot
+    const ScalarImageHistogram *hist = cw->GetHistogram(0);
+    m_HistogramAssembly->AddToChart(m_Chart);
+    double ymax = m_HistogramAssembly->PlotAsEmpiricalDensity(hist);
+
+    // Get tehe GMM
+    GaussianMixtureModel *gmm = uc->GetMixtureModel();
+    int ng = gmm->GetNumberOfGaussians();
+
+    // Create the plot table
+    vtkSmartPointer<vtkTable> table = vtkSmartPointer<vtkTable>::New();
+
+    // Create the x coordinate array. This is an array of equally sampled
+    // coordinate values, plus the mean of each cluster, which is given its
+    // own sample so we can render clusters that are like delta functions.
+    vtkSmartPointer<vtkDoubleArray> dax = vtkSmartPointer<vtkDoubleArray>::New();
+    dax->SetName("Intensity");
+    table->AddColumn(dax);
+
+    // Create the y arrays
+    std::vector<vtkSmartPointer<vtkDoubleArray> > day(ng);
+    for(int i = 0; i < ng; i++)
+      {
+      std::ostringstream oss; oss << "Cluster " << (i + 1);
+      day[i] = vtkSmartPointer<vtkDoubleArray>::New();
+      day[i]->SetName(oss.str().c_str());
+      table->AddColumn(day[i]);
+      }
+
+    // Use the set mechanism to sort coordinate values
+    vnl_vector<double> xreg = linspace(cmin, cmax, NUM_POINTS);
+    std::set<double> xset;
+    for(int k = 0; k < xreg.size(); k++)
+      xset.insert(xreg[k]);
+    for(int i = 0; i < ng; i++)
+      xset.insert(m_Model->GetClusterNativeMean(i, comp));
+
+    // Set the number of data points
+    unsigned int nsam = xset.size();
+    table->SetNumberOfRows(nsam);
+
+    // Copy the x values to the array
+    std::copy(xset.begin(), xset.end(), dax->GetPointer(0));
+
+    // Plot the Gaussian for each of the clusters. The marginal Gaussian
+    // PDF is just the univariate PDF with the mean and variance of that
+    // component
+    for(int i = 0; i < ng; i++)
+      {
+      // Get the i'th Gaussian as a marginal distribution
+      double mean = m_Model->GetClusterNativeMean(i, comp);
+      double variance = m_Model->GetClusterNativeCovariance(i, comp, comp);
+      Gaussian g_marginal(1);
+      g_marginal.SetMean(vnl_vector<double>(&mean, 1));
+      g_marginal.SetCovariance(vnl_matrix<double>(&variance, 1, 1));
+
+      // Set of plots, one for each mixture in the model
+      vtkPlot *plot = m_Chart->AddPlot(vtkChart::LINE);
+      plot->SetInputData(table, 0, i+1);
+
+      // Compute the mixture's marginal PDF
+      for(int k = 0; k < nsam; k++)
+        {
+        double t = dax->GetTuple1(k);
+        if(t == mean && variance == 0)
+          day[i]->SetTuple1(k, 10 / (cmax - cmin)); // delta function
+        else
+          {
+          double density = g_marginal.EvaluatePDF(&t) * gmm->GetWeight(i);
+          day[i]->SetTuple1(k, density);
+          }
+        }
+
+      // Configure the plot
+      Vector3d rgb = ColorLabelTable::GetDefaultColorLabel(i+1).GetRGBAsDoubleVector();
+      plot->SetColor(rgb[0], rgb[1], rgb[2]);
+      plot->GetXAxis()->SetBehavior(vtkAxis::FIXED);
+      plot->GetXAxis()->SetRange(cmin - hist->GetBinWidth(), cmax + hist->GetBinWidth());
+      plot->GetXAxis()->SetTitle("intensity");
+      plot->GetYAxis()->SetBehavior(vtkAxis::FIXED);
+      plot->GetYAxis()->SetRange(0, ymax);
+      plot->GetYAxis()->SetTitle("probability density");
+
+      if(gmm->IsForeground(i))
+        plot->SetWidth(2.0);
+      else
+        plot->SetWidth(1.0);
+      }
+    }
+}
diff --git a/GUI/Renderer/GMMRenderer.h b/GUI/Renderer/GMMRenderer.h
new file mode 100644
index 0000000..0670cbc
--- /dev/null
+++ b/GUI/Renderer/GMMRenderer.h
@@ -0,0 +1,46 @@
+#ifndef GMMRENDERER_H
+#define GMMRENDERER_H
+
+#include "AbstractVTKSceneRenderer.h"
+#include "vtkSmartPointer.h"
+
+class vtkActor;
+class vtkPropAssembly;
+class vtkChartXY;
+class vtkFloatArray;
+class vtkPlot;
+class vtkTable;
+
+class SnakeWizardModel;
+class LayerHistogramPlotAssembly;
+
+class GMMRenderer : public AbstractVTKSceneRenderer
+{
+public:
+
+  irisITKObjectMacro(GMMRenderer, AbstractVTKSceneRenderer)
+
+  void SetModel(SnakeWizardModel *model);
+
+  void OnUpdate();
+
+  void UpdatePlotValues();
+
+protected:
+
+  GMMRenderer();
+  virtual ~GMMRenderer() {}
+
+
+  SnakeWizardModel *m_Model;
+
+  // Rendering stuff
+  vtkSmartPointer<vtkChartXY> m_Chart;
+
+  // Histogram rendering
+  LayerHistogramPlotAssembly *m_HistogramAssembly;
+
+  static unsigned int NUM_POINTS;
+};
+
+#endif // GMMRENDERER_H
diff --git a/GUI/Renderer/Generic3DRenderer.cxx b/GUI/Renderer/Generic3DRenderer.cxx
new file mode 100644
index 0000000..487fea0
--- /dev/null
+++ b/GUI/Renderer/Generic3DRenderer.cxx
@@ -0,0 +1,796 @@
+#include "Generic3DRenderer.h"
+#include "SNAPOpenGL.h"
+#include "Generic3DModel.h"
+#include "GlobalUIModel.h"
+#include "SNAPAppearanceSettings.h"
+#include "GenericImageData.h"
+
+#include "vtkGenericOpenGLRenderWindow.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkPolyDataMapper.h"
+#include "vtkPolyDataMapper2D.h"
+#include "vtkActor.h"
+#include "vtkActor2D.h"
+#include "vtkProperty.h"
+#include "vtkRenderer.h"
+#include "vtkSphereSource.h"
+#include "vtkCamera.h"
+#include "vtkTransform.h"
+#include "vtkLineSource.h"
+#include "vtkPropAssembly.h"
+#include "vtkMath.h"
+
+
+#include "MeshManager.h"
+
+#include "ColorLabel.h"
+#include "IRISApplication.h"
+#include "vtkCommand.h"
+
+#include "Window3DPicker.h"
+
+#include "vtkUnstructuredGridVolumeRayCastMapper.h"
+#include "vtkDiscreteMarchingCubes.h"
+#include "vtkWindowedSincPolyDataFilter.h"
+#include "vtkThreshold.h"
+#include "vtkDataSetMapper.h"
+#include "vtkTransformFilter.h"
+#include "vtkTransform.h"
+#include "vtkLookupTable.h"
+#include "vtkDataSetSurfaceFilter.h"
+#include "vtkGeometryFilter.h"
+
+#include "vtkGlyph3D.h"
+#include "vtkCubeSource.h"
+#include "vtkSphereSource.h"
+#include "vtkImplicitPlaneWidget.h"
+#include "vtkTransformPolyDataFilter.h"
+#include "vtkCubeSource.h"
+#include "vtkCoordinate.h"
+#include "vtkQuadricLODActor.h"
+
+#include <vnl/vnl_cross.h>
+
+
+bool operator == (const CameraState &c1, const CameraState &c2)
+{
+  return
+      c1.position == c2.position &&
+      c1.focal_point == c2.focal_point &&
+      c1.view_up == c2.view_up &&
+      c1.clipping_range == c2.clipping_range &&
+      c1.view_angle == c2.view_angle &&
+      c1.parallel_scale == c2.parallel_scale &&
+      c1.parallel_projection == c2.parallel_projection;
+}
+
+bool operator != (const CameraState &c1, const CameraState &c2)
+{
+  return !(c1==c2);
+}
+
+
+Generic3DRenderer::Generic3DRenderer()
+{
+  // Why is this necessary?
+  GetRenderWindow()->SetMultiSamples(4);
+  GetRenderWindow()->SetLineSmoothing(1);
+
+  // Create a picker
+  vtkSmartPointer<Window3DPicker> picker = vtkSmartPointer<Window3DPicker>::New();
+  this->GetRenderWindowInteractor()->SetPicker(picker);
+
+  // Coordinate mapper
+  m_CoordinateMapper = vtkSmartPointer<vtkCoordinate>::New();
+  m_CoordinateMapper->SetCoordinateSystemToViewport();
+
+  // ------------------ AXES ----------------------------
+
+  // Initialize the line sources for the axes
+  for(int i = 0; i < 3; i++)
+    {
+    // Create the line source (no point coordinates yet)
+    m_AxisLineSource[i] = vtkSmartPointer<vtkLineSource>::New();
+    m_AxisLineSource[i]->SetResolution(10);
+
+    // Create mapper, actor, etc
+    vtkSmartPointer<vtkPolyDataMapper> mapper =
+        vtkSmartPointer<vtkPolyDataMapper>::New();
+    mapper->SetInputConnection(m_AxisLineSource[i]->GetOutputPort());
+
+    m_AxisActor[i] = vtkSmartPointer<vtkActor>::New();
+    m_AxisActor[i]->SetMapper(mapper);
+
+    this->m_Renderer->AddActor(m_AxisActor[i]);
+    }
+
+
+  // ------------------ SPRAYPAINT ----------------------------
+
+  // Create a glyph filter which handles spray paint
+  vtkSmartPointer<vtkSphereSource> cube = vtkSmartPointer<vtkSphereSource>::New();
+  m_SprayGlyphFilter = vtkSmartPointer<vtkGlyph3D>::New();
+  m_SprayGlyphFilter->SetSourceConnection(cube->GetOutputPort());
+  m_SprayGlyphFilter->SetScaleModeToDataScalingOff();
+  m_SprayGlyphFilter->SetScaleFactor(1.4);
+
+  // Create a transform filter for the glyph filter
+  m_SprayTransform = vtkSmartPointer<vtkTransform>::New();
+  vtkSmartPointer<vtkTransformFilter> tf_glyph = vtkSmartPointer<vtkTransformFilter>::New();
+  tf_glyph->SetTransform(m_SprayTransform.GetPointer());
+  tf_glyph->SetInputConnection(m_SprayGlyphFilter->GetOutputPort());
+
+  // Create the spray paint property
+  m_SprayProperty = vtkSmartPointer<vtkProperty>::New();
+  m_SprayProperty->SetShading(VTK_FLAT);
+
+  // Create a mapper, etc for the glyph filter and add to the renderer
+  vtkSmartPointer<vtkPolyDataMapper> mapper_spray = vtkSmartPointer<vtkPolyDataMapper>::New();
+  mapper_spray->SetInputConnection(tf_glyph->GetOutputPort());
+
+  // Create and add an actor for the spray
+  m_SprayActor = vtkSmartPointer<vtkActor>::New();
+  m_SprayActor->SetMapper(mapper_spray);
+  m_SprayActor->SetProperty(m_SprayProperty);
+
+  // ------------------ SCALPEL ----------------------------
+
+  // Create the line actor for scalpel positioning
+  m_ScalpelLineSource = vtkSmartPointer<vtkLineSource>::New();
+
+  // Create mapper, actor, etc
+  vtkSmartPointer<vtkPolyDataMapper2D> mapper_scalpel =
+      vtkSmartPointer<vtkPolyDataMapper2D>::New();
+  mapper_scalpel->SetInputConnection(m_ScalpelLineSource->GetOutputPort());
+
+  m_ScalpelLineActor = vtkSmartPointer<vtkActor2D>::New();
+  m_ScalpelLineActor->SetMapper(mapper_scalpel);
+
+  this->m_Renderer->AddActor(m_ScalpelLineActor);
+
+  m_ImageCubeSource = vtkSmartPointer<vtkCubeSource>::New();
+  m_ImageCubeTransform = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
+  m_ImageCubeTransform->SetInputConnection(m_ImageCubeSource->GetOutputPort());
+  m_ScalpelPlaneWidget = vtkSmartPointer<vtkImplicitPlaneWidget>::New();
+  m_ScalpelPlaneWidget->SetInputConnection(m_ImageCubeTransform->GetOutputPort());
+
+  m_ScalpelPlaneWidget->SetInteractor(this->GetRenderWindowInteractor());
+  m_ScalpelPlaneWidget->SetPlaceFactor(1.0);
+
+  m_ScalpelPlaneWidget->OutlineTranslationOff();
+  m_ScalpelPlaneWidget->OutsideBoundsOff();
+  m_ScalpelPlaneWidget->ScaleEnabledOff();
+
+  m_ScalpelPlaneWidget->GetPlaneProperty()->SetOpacity(0.5);
+  m_ScalpelPlaneWidget->GetOutlineProperty()->SetOpacity(0.2);
+  m_ScalpelPlaneWidget->SetTubing(1);
+
+
+
+
+  // Rebroadcast Modified event from the camera object as a CameraUpdateEvent
+  Rebroadcast(m_Renderer->GetActiveCamera(), vtkCommand::ModifiedEvent, CameraUpdateEvent());
+}
+
+void Generic3DRenderer::SetModel(Generic3DModel *model)
+{
+  // Save the model
+  m_Model = model;
+
+  // Get a pointer to the application class
+  IRISApplication *app = m_Model->GetParentUI()->GetDriver();
+
+  // Record and rebroadcast changes in the model
+  Rebroadcast(app->GetMeshManager(), itk::ModifiedEvent(), ModelUpdateEvent());
+
+  // Respond to changes in image dimension - these require big updates
+  Rebroadcast(app, MainImageDimensionsChangeEvent(), ModelUpdateEvent());
+
+  // Respond to changes to the segmentation. These are ignored unless we are
+  // in continous update mode, in which case the renderers are rebuilt
+  // Rebroadcast(app, SegmentationChangeEvent(), ModelUpdateEvent());
+  Rebroadcast(app, LevelSetImageChangeEvent(), ModelUpdateEvent());
+  Rebroadcast(m_Model->GetContinuousUpdateModel(), ValueChangedEvent(), ModelUpdateEvent());
+
+  // Respond to cursor events
+  Rebroadcast(m_Model->GetParentUI(), CursorUpdateEvent(), ModelUpdateEvent());
+
+  // Respond to label appearance change events
+  Rebroadcast(app->GetColorLabelTable(),
+              SegmentationLabelChangeEvent(), ModelUpdateEvent());
+
+  // Respond to change in current label
+  Rebroadcast(app->GetGlobalState()->GetDrawingColorLabelModel(),
+              ValueChangedEvent(), ModelUpdateEvent());
+
+  // Respond to spray paint events
+  Rebroadcast(m_Model, Generic3DModel::SprayPaintEvent(), ModelUpdateEvent());
+
+  // Respond to scalpel events
+  Rebroadcast(m_Model, Generic3DModel::ScalpelEvent(), ModelUpdateEvent());
+
+  // Respond to changes in toolbar mode
+  Rebroadcast(m_Model->GetParentUI()->GetGlobalState()->GetToolbarMode3DModel(),
+              ValueChangedEvent(), ModelUpdateEvent());
+
+  // Listen to changes in appearance
+  Rebroadcast(m_Model->GetParentUI()->GetAppearanceSettings(),
+              ChildPropertyChangedEvent(), ModelUpdateEvent());
+
+  // Update the main components
+  this->UpdateAxisRendering();
+  this->UpdateCamera(true);
+
+  // Hook up the spray pipeline
+  m_SprayGlyphFilter->SetInputData(m_Model->GetSprayPoints());
+
+  // Set the model in the picker
+  Window3DPicker::SafeDownCast(this->GetRenderWindowInteractor()->GetPicker())->SetModel(m_Model);
+}
+
+
+void Generic3DRenderer::UpdateSegmentationMeshAssembly()
+{
+  if(m_Model->IsMeshUpdating())
+    return;
+
+  // Get the app driver
+  IRISApplication *driver = m_Model->GetParentUI()->GetDriver();
+
+  // Get the mesh from the parent object
+  MeshManager *mesh = driver->GetMeshManager();
+  MeshManager::MeshCollection meshes = mesh->GetMeshes();
+  typedef MeshManager::MeshCollection::const_iterator MeshIterator;
+
+  // Remove all actors that are no longer in use, and update the ones for which the
+  // mesh has changed
+  for(ActorMapIterator it_actor = m_ActorMap.begin(); it_actor != m_ActorMap.end(); )
+    {
+    // Is there a mesh for this actor?
+    MeshIterator it_mesh = meshes.find(it_actor->first);
+
+    if(it_mesh == meshes.end())
+      {
+      // The actor no longer has a corresponding mesh, and should be removed
+      this->m_Renderer->RemoveActor(it_actor->second);
+
+      // Delete the actor completely (funky iterator++ code that works)
+      m_ActorMap.erase(it_actor++);
+      }
+    else
+      {
+      if(it_mesh->second.GetPointer() != it_actor->second->GetMapper()->GetInput())
+        {
+        // The mesh has changed, and needs to be fed to the mapper
+        vtkPolyDataMapper::SafeDownCast(it_actor->second->GetMapper())
+            ->SetInputData(it_mesh->second);
+        }
+
+      // Increment the iterator
+      it_actor++;
+      }
+    }
+
+  // Now create actors for all the meshes that don't have them yet
+  for(MeshIterator it_mesh = meshes.begin(); it_mesh != meshes.end(); ++it_mesh)
+    {
+    // See if an actor exists for this label
+    if(m_ActorMap.find(it_mesh->first) == m_ActorMap.end())
+      {
+      vtkPolyData *mesh = it_mesh->second;
+
+      // Create a mapper
+      vtkSmartPointer<vtkPolyDataMapper> pdm = vtkSmartPointer<vtkPolyDataMapper>::New();
+      pdm->SetInputData(mesh);
+
+      // Get the label of that mesh
+      const ColorLabel &cl = driver->GetColorLabelTable()->GetColorLabel(it_mesh->first);
+
+      // Create a property
+      vtkSmartPointer<vtkProperty> prop = vtkSmartPointer<vtkProperty>::New();
+      prop->SetColor(cl.GetRGBAsDoubleVector().data_block());
+      prop->SetOpacity(cl.GetAlpha() / 255.0);
+
+      // Create an actor
+      vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
+      actor->SetMapper(pdm);
+      actor->SetProperty(prop);
+
+      // Add the actor to the renderer
+      m_Renderer->AddActor(actor);
+
+      // Keep the actor in the map
+      m_ActorMap.insert(std::make_pair(it_mesh->first, actor));
+      }
+    }
+}
+
+void Generic3DRenderer::ResetSegmentationMeshAssembly()
+{
+  if(m_Model->IsMeshUpdating())
+    return;
+
+  for(ActorMapIterator it_actor = m_ActorMap.begin(); it_actor != m_ActorMap.end(); it_actor++)
+    this->m_Renderer->RemoveActor(it_actor->second);
+
+  m_ActorMap.clear();
+
+  InvokeEvent(ModelUpdateEvent());
+}
+
+
+void Generic3DRenderer::UpdateAxisRendering()
+{
+  // Update the coordinates of the line source
+  IRISApplication *app = m_Model->GetParentUI()->GetDriver();
+
+  if(app->IsMainImageLoaded())
+    {
+    Vector3ui cursor = app->GetCursorPosition();
+    Vector3ui dims = app->GetCurrentImageData()->GetImageRegion().GetSize();
+
+    // Get the axis appearance properties
+    SNAPAppearanceSettings *as = m_Model->GetParentUI()->GetAppearanceSettings();
+    OpenGLAppearanceElement *axisapp =
+        as->GetUIElement(SNAPAppearanceSettings::CROSSHAIRS_3D);
+
+    // Voxel to world transform
+    vtkSmartPointer<vtkTransform> tran = vtkSmartPointer<vtkTransform>::New();
+    tran->SetMatrix(m_Model->GetWorldMatrix().data_block());
+
+    for(int i = 0; i < 3; i++)
+      {
+      // Update the cursor position
+      Vector3d p1 = to_double(cursor), p2 = to_double(cursor);
+      p1[i] = 0; p2[i] = dims[i];
+      m_AxisLineSource[i]->SetPoint1(p1.data_block());
+      m_AxisLineSource[i]->SetPoint2(p2.data_block());
+      m_AxisLineSource[i]->Update();
+
+      // Update the visual appearance
+      vtkProperty *prop = m_AxisActor[i]->GetProperty();
+      prop->SetColor(axisapp->GetNormalColor().data_block());
+      if(axisapp->GetDashSpacing() > 0)
+        {
+        prop->SetLineStipplePattern(0x9999);
+        prop->SetLineStippleRepeatFactor(static_cast<int>(axisapp->GetDashSpacing()));
+        prop->SetLineWidth(axisapp->GetLineThickness());
+        m_AxisActor[i]->SetVisibility(axisapp->GetVisible());
+        }
+
+      // Update the transform
+      m_AxisActor[i]->SetUserTransform(tran);
+      }
+
+    // Also update the image cube
+    m_ImageCubeSource->SetBounds(0, dims[0], 0, dims[1], 0, dims[2]);
+    m_ImageCubeTransform->SetTransform(tran);
+    m_ImageCubeTransform->Update();
+    m_ImageCubeTransform->GetOutput()->ComputeBounds();
+    }
+}
+
+
+void Generic3DRenderer::UpdateScalpelRendering()
+{
+  // If not in scalpel mode, just disable everything
+  if(m_Model->GetParentUI()->GetGlobalState()->GetToolbarMode3D() != SCALPEL_MODE)
+    {
+    m_ScalpelPlaneWidget->SetEnabled(0);
+    m_ScalpelLineActor->SetVisibility(0);
+    return;
+    }
+
+  IRISApplication *app = m_Model->GetParentUI()->GetDriver();
+
+  if(m_Model->GetScalpelStatus() == Generic3DModel::SCALPEL_LINE_STARTED)
+    {
+    m_ScalpelLineActor->SetVisibility(1);
+    m_ScalpelLineSource->SetPoint1(
+          m_Model->GetScalpelStart()[0], m_Model->GetScalpelStart()[1], 0);
+    m_ScalpelLineSource->SetPoint2(
+          m_Model->GetScalpelEnd()[0], m_Model->GetScalpelEnd()[1], 0);
+    m_ScalpelLineSource->Update();
+    }
+  else
+    {
+    m_ScalpelLineActor->SetVisibility(0);
+    }
+
+  if(m_Model->GetScalpelStatus() == Generic3DModel::SCALPEL_LINE_COMPLETED)
+    {
+    // Get the endpoints of the cut the user drew on the viewport
+    Vector2i w0 = m_Model->GetScalpelStart(), w1 = m_Model->GetScalpelEnd();
+
+    // If for some reason the endpoints are the same, we just make the cut
+    // plane vertical on the screen
+    if(w0 == w1)
+      w1[1] = w0[1] + 1;
+
+    // Use the coordinate mapper to map the two points on the viewport to
+    // world coordinates
+    m_CoordinateMapper->SetValue(w0[0], w0[1], 0.0);
+    Vector3d p0(m_CoordinateMapper->GetComputedWorldValue(this->m_Renderer));
+
+    m_CoordinateMapper->SetValue(w1[0], w1[1], 0.0);
+    Vector3d p1(m_CoordinateMapper->GetComputedWorldValue(this->m_Renderer));
+
+    // Vector from start to end in world coords
+    Vector3d v01 = p1 - p0;
+
+    // Vector pointing into the screen
+    m_CoordinateMapper->SetValue(w0[0], w0[1], 1.0);
+    Vector3d w = Vector3d(m_CoordinateMapper->GetComputedWorldValue(this->m_Renderer)) - p0;
+
+    // Compute the plane normal vector as the cross-product of the vector between
+    // the endpoints and the vector pointing out of the viewport
+    Vector3d n = - vnl_cross_3d(v01, w);
+    n.normalize();
+
+    // Compute the intercept of the implicit plane
+    double intercept = dot_product(p0, n);
+
+    // Compute the center of the image volume
+    Vector3d xctr(m_ScalpelPlaneWidget->GetInput()->GetCenter());
+    Vector3d orig = xctr - n * (dot_product(xctr, n) - intercept);
+
+    // m_ImageCubeTransform->Update();
+    // m_ImageCubeTransform->GetOutput()->ComputeBounds();
+    // m_ScalpelPlaneWidget->SetInteractor(this->GetRenderWindowInteractor());
+    // m_ScalpelPlaneWidget->SetPlaceFactor(1.0);
+    m_ScalpelPlaneWidget->PlaceWidget();
+    m_ScalpelPlaneWidget->SetEnabled(1);
+
+    // We will also need to set the origin of the plane
+    m_ScalpelPlaneWidget->SetNormal(n.data_block());
+    m_ScalpelPlaneWidget->SetOrigin(orig.data_block());
+    }
+  else
+    {
+    m_ScalpelPlaneWidget->SetEnabled(0);
+    }
+}
+
+
+void Generic3DRenderer::UpdateScalpelPlaneAppearance()
+{
+  // The color of the normal is the same as the current label
+  IRISApplication *app = m_Model->GetParentUI()->GetDriver();
+  LabelType dl = app->GetGlobalState()->GetDrawingColorLabel();
+  ColorLabel cdl = app->GetColorLabelTable()->GetColorLabel(dl);
+
+  // Get a color and a brighter color
+  // (I'm using http://www.poynton.com/PDFs/ColorFAQ.pdf)
+  Vector3d color = cdl.GetRGBAsDoubleVector();
+
+  // Convert the color to HSV
+  Vector3d hsv, hsv_brighter;
+  vtkMath::RGBToHSV(color.data_block(), hsv.data_block());
+
+  // If the value part is below 0.5 (dark color), use default color for the
+  // normal
+  if(hsv[2] < 0.5)
+    {
+    hsv[1] = 0; hsv[2] = 0.9;
+    hsv_brighter = hsv; hsv_brighter[2] = 1.0;
+    }
+  else
+    {
+    hsv_brighter = hsv; hsv_brighter[2] = 1.1 * hsv[2];
+    }
+
+  Vector3d color_main, color_bright;
+  vtkMath::HSVToRGB(hsv.data_block(), color_main.data_block());
+  vtkMath::HSVToRGB(hsv_brighter.data_block(), color_bright.data_block());
+/*
+  Vector3d color_xyz, color_brighter, color_darker;
+
+  vtkMath::RGBToXYZ(color.data_block(), color_xyz.data_block());
+  color_xyz *= 1.1;
+  vtkMath::XYZToRGB(color_xyz.data_block(), color_brighter.data_block());
+
+  vtkMath::RGBToXYZ(color.data_block(), color_xyz.data_block());
+  color_xyz /= 1.1;
+  vtkMath::XYZToRGB(color_xyz.data_block(), color_darker.data_block());
+*/
+  vtkProperty *p_normal = m_ScalpelPlaneWidget->GetNormalProperty();
+  p_normal->SetColor(color_main.data_block());
+
+  vtkProperty *ps_normal = m_ScalpelPlaneWidget->GetSelectedNormalProperty();
+  ps_normal->SetColor(color_bright.data_block());
+
+  vtkProperty *p_edges = m_ScalpelPlaneWidget->GetEdgesProperty();
+  p_edges->SetColor(color_main.data_block());
+}
+
+void Generic3DRenderer::UpdateSprayGlyphAppearanceAndShape()
+{
+  IRISApplication *app = m_Model->GetParentUI()->GetDriver();
+  if(app->IsMainImageLoaded())
+    {
+    ImageWrapperBase *main = app->GetCurrentImageData()->GetMain();
+
+    // The color of the spray paint is the same as the current label
+    LabelType dl = app->GetGlobalState()->GetDrawingColorLabel();
+    ColorLabel cdl = app->GetColorLabelTable()->GetColorLabel(dl);
+    m_SprayProperty->SetColor(cdl.GetRGBAsDoubleVector().data_block());
+
+    // Set the spray transform
+    vnl_matrix_fixed<double, 4, 4> vox2nii = main->GetNiftiSform();
+    m_SprayTransform->SetMatrix(vox2nii.data_block());
+    }
+}
+
+void Generic3DRenderer::UpdateCamera(bool reset)
+{
+  // Update the coordinates of the line source
+  IRISApplication *app = m_Model->GetParentUI()->GetDriver();
+
+  if(app->IsMainImageLoaded())
+    {
+    Vector3ui cursor = app->GetCursorPosition();
+    Vector3d spacing = app->GetCurrentImageData()->GetImageSpacing();
+    ImageWrapperBase *main = app->GetCurrentImageData()->GetMain();
+    Vector3d dim = element_product(to_double(main->GetSize()), spacing);
+    Vector3d ctr = main->TransformVoxelIndexToNIFTICoordinates(to_double(cursor));
+
+
+    if(reset)
+      {
+      Vector3d x0 = ctr - dim * 0.5, x1 = ctr + dim * 0.5;
+
+      // Center camera on the cursor
+      m_Renderer->GetActiveCamera()->SetFocalPoint(ctr[0], ctr[1], ctr[2]);
+
+      // Place camera along the R-L axis
+      m_Renderer->GetActiveCamera()->SetPosition(x0[0], ctr[1], ctr[2]);
+
+      // Make camera point so that Superior is up
+      m_Renderer->GetActiveCamera()->SetViewUp(0,0,1);
+
+      // Make the camera point at the crosshair. We use the reset camera
+      // method, with the bounding box centered on the current cursor position
+      m_Renderer->ResetCamera(x0[0], x1[0], x0[1], x1[1], x0[2], x1[2]);
+      }
+    else
+      {
+      // Only center the camera, don't change the other view parameters
+      m_Renderer->GetActiveCamera()->SetFocalPoint(ctr.data_block());
+      }
+    }
+}
+
+void Generic3DRenderer::SaveCameraState()
+{
+  m_SavedCameraState = vtkSmartPointer<vtkCamera>::New();
+  m_SavedCameraState->DeepCopy(this->m_Renderer->GetActiveCamera());
+}
+
+void Generic3DRenderer::ClearRendering()
+{
+  this->ResetSegmentationMeshAssembly();
+}
+
+void Generic3DRenderer::RestoreSavedCameraState()
+{
+  if(m_SavedCameraState)
+    this->m_Renderer->GetActiveCamera()->DeepCopy(m_SavedCameraState);
+  InvokeEvent(ModelUpdateEvent());
+  InvokeEvent(CameraUpdateEvent());
+}
+
+void Generic3DRenderer::DeleteSavedCameraState()
+{
+  m_SavedCameraState = NULL;
+}
+
+bool Generic3DRenderer::IsSavedCameraStateAvailable()
+{
+  return m_SavedCameraState != NULL;
+}
+
+CameraState Generic3DRenderer::GetCameraState() const
+{
+  CameraState cs;
+  vtkCamera *camera = m_Renderer->GetActiveCamera();
+
+  cs.position.set(camera->GetPosition());
+  cs.focal_point.set(camera->GetFocalPoint());
+  cs.view_up.set(camera->GetViewUp());
+  cs.view_angle = camera->GetViewAngle();
+  cs.parallel_projection = camera->GetParallelProjection();
+  cs.parallel_scale = camera->GetParallelScale();
+  cs.clipping_range.set(camera->GetClippingRange());
+
+  return cs;
+}
+
+void Generic3DRenderer::SetCameraState(const CameraState &cs)
+{
+  // Update the camera parameters. VTK implementation of the SetXXX methods
+  // will invoke the Modified() event if necessary
+  vtkCamera *camera = m_Renderer->GetActiveCamera();
+
+  // Get the m-time of the camera before updates
+  unsigned long mtime = camera->GetMTime();
+
+  // Update the camera
+  camera->SetPosition(cs.position.data_block());
+  camera->SetFocalPoint(cs.focal_point.data_block());
+  camera->SetViewUp(cs.view_up.data_block());
+  camera->SetViewAngle(cs.view_angle);
+  camera->SetParallelProjection(cs.parallel_projection);
+  camera->SetParallelScale(cs.parallel_scale);
+  camera->SetClippingRange(cs.clipping_range.data_block());
+
+  // If the camera really updated, fire an event
+  if(camera->GetMTime() > mtime)
+    InvokeEvent(ModelUpdateEvent());
+}
+
+void Generic3DRenderer::paintGL()
+{
+  // Get the appearance settings
+  SNAPAppearanceSettings *as =
+      m_Model->GetParentUI()->GetAppearanceSettings();
+
+  // Load the background color
+  Vector3d clrBack =
+      as->GetUIElement(SNAPAppearanceSettings::BACKGROUND_3D)->GetNormalColor();
+
+  // Set renderer background
+  this->m_Renderer->SetBackground(clrBack.data_block());
+
+  // Call the parent's paint method
+  AbstractVTKRenderer::paintGL();
+}
+
+void Generic3DRenderer::UpdateSegmentationMeshAppearance()
+{
+  // Get the app driver
+  IRISApplication *driver = m_Model->GetParentUI()->GetDriver();
+
+  // Get the mesh from the parent object
+  MeshManager *mesh = driver->GetMeshManager();
+
+
+  // For each actor, update the property to reflect current state
+  for(ActorMapIterator it_actor = m_ActorMap.begin(); it_actor != m_ActorMap.end(); ++it_actor)
+    {
+    // Get the next prop
+    vtkActor *actor = it_actor->second;
+
+    // Get the label of that mesh
+    const ColorLabel &cl = driver->GetColorLabelTable()->GetColorLabel(it_actor->first);
+
+    // Get the property
+    vtkProperty *prop = actor->GetProperty();
+
+    // Assign the color and opacity
+    prop->SetColor(cl.GetRGB(0) / 255.0, cl.GetRGB(1) / 255.0, cl.GetRGB(2) / 255.0);
+
+    if(cl.IsVisibleIn3D())
+      prop->SetOpacity(cl.GetAlpha() / 255.0);
+    else
+      prop->SetOpacity(0.0);
+    }
+}
+
+
+void Generic3DRenderer::OnUpdate()
+{
+  // Update the model first
+  m_Model->Update();
+
+  // Access the application
+  IRISApplication *app = m_Model->GetParentUI()->GetDriver();
+  GlobalState *gs = app->GetGlobalState();
+
+  // Get the mode
+  ToolbarMode3DType mode = m_Model->GetParentUI()->GetGlobalState()->GetToolbarMode3D();
+
+  // Define a bunch of local flags to make this code easier to read
+  bool main_changed = m_EventBucket->HasEvent(MainImageDimensionsChangeEvent());
+  bool labels_props_changed = m_EventBucket->HasEvent(SegmentationLabelChangeEvent());
+  bool mesh_updated = m_EventBucket->HasEvent(itk::ModifiedEvent());
+  bool cursor_moved = m_EventBucket->HasEvent(CursorUpdateEvent());
+  bool active_label_changed = m_EventBucket->HasEvent(
+        ValueChangedEvent(), gs->GetDrawingColorLabelModel());
+  bool spray_action = m_EventBucket->HasEvent(Generic3DModel::SprayPaintEvent());
+  bool scalpel_action = m_EventBucket->HasEvent(Generic3DModel::ScalpelEvent());
+  bool mode_changed = m_EventBucket->HasEvent(
+        ValueChangedEvent(),
+        m_Model->GetParentUI()->GetGlobalState()->GetToolbarMode3DModel());
+  bool segmentation_changed =
+      m_EventBucket->HasEvent(SegmentationChangeEvent()) ||
+      m_EventBucket->HasEvent(LevelSetImageChangeEvent());
+
+  bool appearance_changed =
+      m_EventBucket->HasEvent(ChildPropertyChangedEvent(),
+                              m_Model->GetParentUI()->GetAppearanceSettings());
+
+  // Deal with the updates to the mesh state
+  if(mesh_updated || main_changed)
+    {
+    UpdateSegmentationMeshAssembly();
+    }
+  else if(labels_props_changed)
+    {
+    UpdateSegmentationMeshAppearance();
+    }
+
+  // If the segmentation changed
+
+  // Deal with axes
+  if(main_changed || cursor_moved || appearance_changed)
+    {
+    UpdateAxisRendering();
+    }
+
+  // Deal with camera
+  if(main_changed)
+    {
+    UpdateCamera(true);
+    DeleteSavedCameraState();
+    }
+  else if(cursor_moved)
+    {
+    UpdateCamera(false);
+    }
+
+  // Deal with the spray paint appearance and shape
+  if(main_changed || labels_props_changed || active_label_changed)
+    {
+    UpdateSprayGlyphAppearanceAndShape();
+    UpdateScalpelPlaneAppearance();
+    }
+
+  // Deal with spray events
+  if(main_changed || spray_action || mode_changed)
+    {
+    if(m_Model->GetSprayPoints()->GetNumberOfPoints() && mode == SPRAYPAINT_MODE)
+      this->m_Renderer->AddActor(m_SprayActor);
+    else
+      this->m_Renderer->RemoveActor(m_SprayActor);
+    }
+
+  // Deal with scalpel events
+  if(main_changed || scalpel_action || mode_changed)
+    {
+    UpdateScalpelRendering();
+    }
+}
+
+void Generic3DRenderer::ResetView()
+{
+  this->UpdateCamera(true);
+  InvokeEvent(ModelUpdateEvent());
+}
+
+Vector3d Generic3DRenderer::GetScalpelPlaneNormal() const
+{
+  return Vector3d(m_ScalpelPlaneWidget->GetNormal());
+}
+
+Vector3d Generic3DRenderer::GetScalpelPlaneOrigin() const
+{
+  return Vector3d(m_ScalpelPlaneWidget->GetOrigin());
+}
+
+void Generic3DRenderer::FlipScalpelPlaneNormal()
+{
+  Vector3d n = this->GetScalpelPlaneNormal();
+  m_ScalpelPlaneWidget->SetNormal(-n[0], -n[1], -n[2]);
+  InvokeEvent(ModelUpdateEvent());
+}
+
+void Generic3DRenderer::ComputeRayFromClick(int x, int y, Vector3d &m_Point, Vector3d &m_Ray)
+{
+  // Get the position of the click in world coordinates
+  m_CoordinateMapper->SetValue(x, y, 0);
+  m_Point = Vector3d(m_CoordinateMapper->GetComputedWorldValue(this->m_Renderer));
+
+  // Get the normal vector to the viewport
+  m_CoordinateMapper->SetValue(x, y, 1);
+  m_Ray = Vector3d(m_CoordinateMapper->GetComputedWorldValue(this->m_Renderer)) - m_Point;
+}
diff --git a/GUI/Renderer/Generic3DRenderer.h b/GUI/Renderer/Generic3DRenderer.h
new file mode 100644
index 0000000..82d9b98
--- /dev/null
+++ b/GUI/Renderer/Generic3DRenderer.h
@@ -0,0 +1,157 @@
+#ifndef GENERIC3DRENDERER_H
+#define GENERIC3DRENDERER_H
+
+#include "AbstractVTKRenderer.h"
+#include <vtkSmartPointer.h>
+
+class Generic3DModel;
+class vtkGenericOpenGLRenderWindow;
+class vtkRenderer;
+class vtkRenderWindow;
+class vtkLineSource;
+class vtkActor;
+class vtkActor2D;
+class vtkPropAssembly;
+class vtkProperty;
+class vtkTransform;
+class vtkImplicitPlaneWidget;
+class vtkGlyph3D;
+class vtkTransformPolyDataFilter;
+class vtkCubeSource;
+class vtkCoordinate;
+class vtkCamera;
+
+/**
+ * A struct representing the state of the VTK camera. This struct
+ * can be used to communicate camera state between ITK-SNAP sessions
+ */
+struct CameraState
+{
+  Vector3d position, focal_point, view_up;
+  Vector2d clipping_range;
+  double view_angle, parallel_scale;
+  int parallel_projection;
+
+};
+
+bool operator == (const CameraState &c1, const CameraState &c2);
+bool operator != (const CameraState &c1, const CameraState &c2);
+
+
+class Generic3DRenderer : public AbstractVTKRenderer
+{
+public:
+
+  irisITKObjectMacro(Generic3DRenderer, AbstractVTKRenderer)
+
+  /** An event fired when the camera state updates */
+  itkEventMacro(CameraUpdateEvent, IRISEvent)
+
+  FIRES(CameraUpdateEvent)
+
+  void paintGL();
+
+  void SetModel(Generic3DModel *model);
+
+  virtual void OnUpdate();
+
+  void ResetView();
+
+  // Save the camera state
+  void SaveCameraState();
+
+  // Clear the rendering
+  void ClearRendering();
+
+  // Restore the camera state from saved
+  void RestoreSavedCameraState();
+
+  // Restore the camera state from saved
+  void DeleteSavedCameraState();
+
+  // Restore the camera state from saved
+  bool IsSavedCameraStateAvailable();
+
+  /** Access the VTK camera object (used for synchronization) */
+  CameraState GetCameraState() const;
+
+  /** Change the camera state */
+  void SetCameraState(const CameraState &state);
+
+  /** Get the normal to the scalpel plane in world coordinates */
+  Vector3d GetScalpelPlaneNormal() const;
+
+  /** Get the origin of the scalpel plane in world coordinates */
+  Vector3d GetScalpelPlaneOrigin() const;
+
+  /** Flip the direction of the cutplane */
+  void FlipScalpelPlaneNormal();
+
+  /** Compute the world coordinates of a click and a ray pointing inward (not normalized) */
+  void ComputeRayFromClick(int x, int y, Vector3d &m_Point, Vector3d &m_Ray);
+
+protected:
+  Generic3DRenderer();
+  virtual ~Generic3DRenderer() {}
+
+  Generic3DModel *m_Model;
+
+  // Update the actors and mappings for the renderer
+  void UpdateSegmentationMeshAssembly();
+  void UpdateSegmentationMeshAppearance();
+
+  // Clear all the meshes being rendered
+  void ResetSegmentationMeshAssembly();
+
+  // Update the actors representing the axes
+  void UpdateAxisRendering();
+
+  // Update the spray paint glyph properties
+  void UpdateSprayGlyphAppearanceAndShape();
+
+  // Update the scalpel rendering
+  void UpdateScalpelRendering();
+
+  // Update the scalpel plane appearance (color, etc)
+  void UpdateScalpelPlaneAppearance();
+
+  // Update the camera
+  void UpdateCamera(bool reset);
+
+  typedef std::map<LabelType, vtkSmartPointer<vtkActor> > ActorMap;
+  typedef ActorMap::iterator ActorMapIterator;
+
+  // Collection of actors for different color labels in use
+  ActorMap m_ActorMap;
+
+  // Line sources for drawing the crosshairs
+  vtkSmartPointer<vtkLineSource> m_AxisLineSource[3];
+  vtkSmartPointer<vtkActor> m_AxisActor[3];
+
+  // Glyph filter used to render spray paint stuff
+  vtkSmartPointer<vtkGlyph3D> m_SprayGlyphFilter;
+
+  // The property controlling the spray paint
+  vtkSmartPointer<vtkProperty> m_SprayProperty;
+
+  // The transform applied to spray points
+  vtkSmartPointer<vtkTransform> m_SprayTransform;
+  vtkSmartPointer<vtkActor> m_SprayActor;
+
+  // The actors for the scalpel drawing
+  vtkSmartPointer<vtkLineSource> m_ScalpelLineSource;
+  vtkSmartPointer<vtkActor2D> m_ScalpelLineActor;
+
+  // The actors for the scalpel plane
+  vtkSmartPointer<vtkCubeSource> m_ImageCubeSource;
+  vtkSmartPointer<vtkTransformPolyDataFilter> m_ImageCubeTransform;
+  vtkSmartPointer<vtkImplicitPlaneWidget> m_ScalpelPlaneWidget;
+
+  // Coordinate mapper
+  vtkSmartPointer<vtkCoordinate> m_CoordinateMapper;
+
+  // Saved camera state
+  vtkSmartPointer<vtkCamera> m_SavedCameraState;
+};
+
+#endif // GENERIC3DRENDERER_H
diff --git a/GUI/Renderer/GenericSliceRenderer.cxx b/GUI/Renderer/GenericSliceRenderer.cxx
new file mode 100644
index 0000000..fb5baff
--- /dev/null
+++ b/GUI/Renderer/GenericSliceRenderer.cxx
@@ -0,0 +1,594 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#include "SNAPCommon.h"
+#include "GenericSliceRenderer.h"
+#include "GenericSliceModel.h"
+#include "GlobalUIModel.h"
+#include "SNAPAppearanceSettings.h"
+#include "GenericImageData.h"
+#include "ImageWrapper.h"
+#include "IRISApplication.h"
+#include "IntensityCurveModel.h"
+#include "DisplayLayoutModel.h"
+#include "ColorMapModel.h"
+#include "LayerAssociation.txx"
+#include "SliceWindowCoordinator.h"
+#include "PaintbrushSettingsModel.h"
+
+GenericSliceRenderer
+::GenericSliceRenderer()
+{
+  this->m_ThumbnailDrawing = false;
+}
+
+void
+GenericSliceRenderer::SetModel(GenericSliceModel *model)
+{
+  this->m_Model = model;
+
+  // Build the texture map
+  OpenGLTextureAssociationFactory texFactoryDelegate = { this };
+  m_Texture.SetDelegate(texFactoryDelegate);
+  m_Texture.SetSource(model->GetDriver());
+  this->UpdateTextureMap();
+
+  // Record and rebroadcast changes in the model
+  Rebroadcast(m_Model, ModelUpdateEvent(), ModelUpdateEvent());
+
+  // Also listen to events on opacity
+  Rebroadcast(m_Model->GetParentUI()->GetGlobalState()->GetSegmentationAlphaModel(),
+              ValueChangedEvent(), AppearanceUpdateEvent());
+
+  // Listen to changes in the appearance of any of the wrappers
+  Rebroadcast(m_Model->GetDriver(), WrapperChangeEvent(), AppearanceUpdateEvent());
+
+  // Listen to changes to the segmentation
+  Rebroadcast(m_Model->GetDriver(), SegmentationChangeEvent(), AppearanceUpdateEvent());
+
+  // Changes to cell layout also must be rebroadcast
+  DisplayLayoutModel *dlm = m_Model->GetParentUI()->GetDisplayLayoutModel();
+  Rebroadcast(dlm, DisplayLayoutModel::LayerLayoutChangeEvent(),
+              AppearanceUpdateEvent());
+
+  // Listen to changes in appearance
+  Rebroadcast(m_Model->GetParentUI()->GetAppearanceSettings(),
+              ChildPropertyChangedEvent(), AppearanceUpdateEvent());
+
+  // Listen to overall visibility of overlaps
+  Rebroadcast(m_Model->GetParentUI()->GetAppearanceSettings()->GetOverallVisibilityModel(),
+              ValueChangedEvent(), AppearanceUpdateEvent());
+
+  // Paintbrush appearance changes
+  PaintbrushSettingsModel *psm = m_Model->GetParentUI()->GetPaintbrushSettingsModel();
+  Rebroadcast(psm->GetBrushSizeModel(), ValueChangedEvent(), AppearanceUpdateEvent());
+
+}
+
+void GenericSliceRenderer::OnUpdate()
+{
+  // Make sure the model has been updated first
+  m_Model->Update();
+
+  // Also make sure to update the model zoom coordinator (this is confusing)
+  m_Model->GetParentUI()->GetSliceCoordinator()->Update();
+
+  // Also make sure to update the display layout model
+  m_Model->GetParentUI()->GetDisplayLayoutModel()->Update();
+
+  // Only update the texture map in response to "big" events
+  if(m_EventBucket->HasEvent(ModelUpdateEvent(), m_Model))
+    {
+    this->UpdateTextureMap();
+    }
+}
+
+void
+GenericSliceRenderer
+::paintGL()
+{
+  // Number of divisions
+  DisplayLayoutModel *dlm = m_Model->GetParentUI()->GetDisplayLayoutModel();
+  Vector2ui layout = dlm->GetSliceViewLayerTilingModel()->GetValue();
+  int nrows = (int) layout[0];
+  int ncols = (int) layout[1];
+
+  // Get the dimensions of the cells
+  unsigned int cell_w = m_Model->GetSize()[0];
+  unsigned int cell_h = m_Model->GetSize()[1];
+
+  // Get the appearance settings pointer since we use it a lot
+  SNAPAppearanceSettings *as =
+      m_Model->GetParentUI()->GetAppearanceSettings();
+
+  // Get the properties for the background color
+  Vector3d clrBack = as->GetUIElement(
+      SNAPAppearanceSettings::BACKGROUND_2D)->GetNormalColor();
+
+  // Set up lighting attributes
+  glPushAttrib(GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT |
+               GL_PIXEL_MODE_BIT | GL_TEXTURE_BIT );
+
+  glDisable(GL_LIGHTING);
+
+  glClearColor(clrBack[0], clrBack[1], clrBack[2], 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  // Slice should be initialized before display
+  if (m_Model->IsSliceInitialized())
+    {
+    // Draw each cell in the nrows by ncols table of images. Usually, there
+    // will only be one column, but the new SNAP supports side-by-side drawing
+    // of layers for when there are overlays
+    for(int irow = 0; irow < nrows; irow++)
+      for(int icol = 0; icol < ncols; icol++)
+        {
+        // Set up the viewport for the current cell
+        glViewport(icol * cell_w, (nrows - 1 - irow) * cell_h,
+                   cell_w, cell_h);
+
+        // Set up the projection
+        glMatrixMode(GL_PROJECTION);
+        glLoadIdentity();
+        gluOrtho2D(0.0, cell_w, 0.0, cell_h);
+
+        // Establish the model view matrix
+        glMatrixMode(GL_MODELVIEW);
+        glLoadIdentity();
+
+        // Scale to account for multiple rows and columns
+        // glScaled(1.0 / ncols, 1.0 / nrows, 1.0);
+
+        // Prepare for overlay drawing.  The model view is set up to correspond
+        // to pixel coordinates of the slice
+        glPushMatrix();
+
+        // First set of transforms
+        glTranslated(0.5 * cell_w, 0.5 * cell_h, 0.0);
+
+        // Zoom by display zoom
+        glScalef(m_Model->GetViewZoom(), m_Model->GetViewZoom(), 1.0);
+
+        // Panning
+        glTranslated(-m_Model->GetViewPosition()[0],
+                     -m_Model->GetViewPosition()[1],
+                     0.0);
+
+        // Convert from voxel space to physical units
+        glScalef(m_Model->GetSliceSpacing()[0],
+                 m_Model->GetSliceSpacing()[1],
+                 1.0);
+
+        // Draw the main layers for this row/column combination
+        if(this->DrawImageLayers(nrows, ncols, irow, icol))
+          {
+          // We don't want to draw segmentation over the speed image and other
+          // SNAP-mode layers.
+          this->DrawSegmentationTexture();
+
+          // Draw the overlays
+          if(as->GetOverallVisibility())
+            {
+            // Draw all the overlays added to this object
+            this->DrawTiledOverlays();
+
+            }
+          }
+
+        // Clean up the GL state
+        glPopMatrix();
+        }
+
+    // Set the viewport and projection to original dimensions
+    Vector2ui vp = m_Model->GetSizeReporter()->GetViewportSize();
+
+    glViewport(0, 0, vp[0], vp[1]);
+
+    // Set up the projection
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    gluOrtho2D(0.0, vp[0], 0.0, vp[1]);
+
+    // Establish the model view matrix
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    if(as->GetOverallVisibility())
+      {
+      // Draw the zoom locator
+      if(m_Model->IsThumbnailOn())
+        this->DrawThumbnail();
+
+      // Draw the global overlays
+      this->DrawGlobalOverlays();
+      }
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+
+    }
+
+  // Draw the various decorations
+  glPopAttrib();
+
+  // Display!
+  glFlush();
+}
+
+void
+GenericSliceRenderer
+::resizeGL(int w, int h)
+{
+  // Set up projection matrix
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  gluOrtho2D(0.0,w,0.0,h);
+  glViewport(0,0,w,h);
+
+  // Establish the model view matrix
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+}
+
+bool GenericSliceRenderer::DrawImageLayers(int nrows, int ncols, int irow, int icol)
+{
+  // Get the image data
+  GenericImageData *id = m_Model->GetImageData();
+
+  // If drawing the thumbnail, only draw the main layer
+  if(m_ThumbnailDrawing)
+    {
+    DrawTextureForLayer(id->GetMain(), false);
+    return true;
+    }
+
+  // Is the display partitioned into rows and columns?
+  if(nrows == 1 && ncols == 1)
+    {
+    // Draw all the layers that are visible except segmentation, which is handled
+    // separately (last)
+    for(LayerIterator it(id); !it.IsAtEnd(); ++it)
+      {
+      ImageWrapperBase *layer = it.GetLayer();
+      if(it.GetRole() == MAIN_ROLE)
+        {
+        DrawTextureForLayer(layer, false);
+        }
+      else if(it.GetRole() != LABEL_ROLE
+              && layer->IsDrawable() && layer->GetAlpha() > 0)
+        {
+        DrawTextureForLayer(it.GetLayer(), true);
+        }
+      }
+
+    return true;
+    }
+  else
+    {
+    // Geth the n-th layer
+    ImageWrapperBase *layer = GetLayerForNthTile(irow, icol);
+
+    // Check if the layer is in drawable condition. If not, draw nothing.
+    if(!layer)
+      return false;
+
+    // Draw the particular layer
+    DrawTextureForLayer(layer, false);
+
+    // Now draw all the non-sticky layers
+    for(LayerIterator itov(id); !itov.IsAtEnd(); ++itov)
+      {
+      if(itov.GetRole() != MAIN_ROLE
+         && itov.GetLayer()->IsSticky()
+         && itov.GetLayer()->IsDrawable()
+         && itov.GetLayer()->GetAlpha() > 0)
+        {
+        DrawTextureForLayer(itov.GetLayer(), true);
+        }
+      }
+
+    return true;
+    }
+}
+
+
+ImageWrapperBase *GenericSliceRenderer::GetLayerForNthTile(int row, int col)
+{
+  // Number of divisions
+  DisplayLayoutModel *dlm = m_Model->GetParentUI()->GetDisplayLayoutModel();
+  Vector2ui layout = dlm->GetSliceViewLayerTilingModel()->GetValue();
+  int ncols = (int) layout[1];
+
+  // How many layers to go until we get to the one we want to paint?
+  int togo = row * ncols + col;
+
+  // Skip all layers until we get to the sticky layer we want to paint
+  for(LayerIterator it(m_Model->GetImageData()); !it.IsAtEnd(); ++it)
+    {
+    if(it.GetRole() == MAIN_ROLE || !it.GetLayer()->IsSticky())
+      {
+      if(togo == 0)
+        return it.GetLayer()->IsDrawable() ? it.GetLayer() : NULL;
+      togo--;
+      }
+    }
+
+  return NULL;
+}
+
+
+
+void GenericSliceRenderer::DrawMainTexture()
+{
+  // Get the image data
+  GenericImageData *id = m_Model->GetImageData();
+
+  // Draw the main texture
+  if (id->IsMainLoaded())
+    DrawTextureForLayer(id->GetMain(), false);
+
+  // Draw each of the overlays
+  if (!m_ThumbnailDrawing)
+    {
+    for(LayerIterator it(id, OVERLAY_ROLE); !it.IsAtEnd(); ++it)
+      DrawTextureForLayer(it.GetLayer(), true);
+    }
+}
+
+void GenericSliceRenderer::DrawTextureForLayer(
+    ImageWrapperBase *layer, bool use_transparency)
+{
+  // Get the appearance settings pointer since we use it a lot
+  SNAPAppearanceSettings *as =
+      m_Model->GetParentUI()->GetAppearanceSettings();
+
+  // Get the global display settings
+  const GlobalDisplaySettings *gds =
+      m_Model->GetParentUI()->GetGlobalDisplaySettings();
+
+  // Get the interpolation mode
+  GLenum interp =
+      gds->GetGreyInterpolationMode() == GlobalDisplaySettings::LINEAR
+      ? GL_LINEAR : GL_NEAREST;
+
+  // Get the texture
+  Texture *tex = m_Texture[layer];
+
+  // Paint the texture with alpha
+  if(tex)
+    {
+    tex->SetInterpolation(interp);
+    if(use_transparency)
+      {
+      tex->DrawTransparent(layer->GetAlpha());
+      }
+    else
+      {
+      Vector3d clrBackground = m_ThumbnailDrawing
+        ? as->GetUIElement(SNAPAppearanceSettings::ZOOM_THUMBNAIL)->GetNormalColor()
+        : Vector3d(1.0);
+      tex->Draw(clrBackground);
+      }
+    }
+}
+
+
+void GenericSliceRenderer::DrawSegmentationTexture()
+  {
+  GenericImageData *id = m_Model->GetImageData();
+
+  if (id->IsSegmentationLoaded())
+    {
+    Texture *texture = m_Texture[id->GetSegmentation()];
+    double alpha = m_Model->GetParentUI()->GetDriver()->GetGlobalState()->GetSegmentationAlpha();
+    texture->DrawTransparent(alpha);
+    }
+  }
+
+void GenericSliceRenderer::DrawThumbnail()
+  {
+  // Get the thumbnail appearance properties
+  SNAPAppearanceSettings *as = m_Model->GetParentUI()->GetAppearanceSettings();
+  const OpenGLAppearanceElement *elt =
+      as->GetUIElement(SNAPAppearanceSettings::ZOOM_THUMBNAIL);
+
+  // If thumbnail is not to be drawn, exit
+  if(!elt->GetVisible()) return;
+
+  // Tell model to figure out the thumbnail size
+  m_Model->ComputeThumbnailProperties();
+  Vector2i tPos = m_Model->GetThumbnailPosition();
+  double tZoom = m_Model->GetThumbnailZoom();
+
+  // Current display layout
+  DisplayLayoutModel *dlm = m_Model->GetParentUI()->GetDisplayLayoutModel();
+  Vector2ui layout = dlm->GetSliceViewLayerTilingModel()->GetValue();
+  unsigned int rows = layout[0], cols = layout[1];
+
+  // Indicate the fact that we are currently drawing in thumbnail mode
+  m_ThumbnailDrawing = true;
+
+  // Set up the GL matrices
+  glPushMatrix();
+  glLoadIdentity();
+  glTranslated((double) tPos[0], (double) tPos[1], 0.0);
+  glScaled(tZoom, tZoom, 1.0);
+
+  glPushMatrix();
+  glScalef(m_Model->GetSliceSpacing()[0],m_Model->GetSliceSpacing()[1],1.0);
+
+  // Draw the Main image (the background will be picked automatically)
+  DrawMainTexture();
+
+  // Draw the overlays that are shown on the thumbnail
+  DrawTiledOverlays();
+
+  // Apply the line settings
+  elt->ApplyLineSettings();
+
+  // Draw the little version of the image in the corner of the window
+  double w = m_Model->GetSliceSize()[0];
+  double h = m_Model->GetSliceSize()[1];
+
+  // Draw the line around the image
+  glColor3dv(elt->GetNormalColor().data_block());
+  glBegin(GL_LINE_LOOP);
+  glVertex2d(0,0);
+  glVertex2d(0,h);
+  glVertex2d(w,h);
+  glVertex2d(w,0);
+  glEnd();
+
+  // Draw a box representing the current zoom level
+  glPopMatrix();
+  glTranslated(m_Model->GetViewPosition()[0],
+               m_Model->GetViewPosition()[1],
+               0.0);
+  w = m_Model->GetSize()[0] * 0.5 / m_Model->GetViewZoom();
+  h = m_Model->GetSize()[1] * 0.5 / m_Model->GetViewZoom();
+
+  glColor3dv(elt->GetActiveColor().data_block());
+  glBegin(GL_LINE_LOOP);
+  glVertex2d(-w,-h);
+  glVertex2d(-w, h);
+  glVertex2d( w, h);
+  glVertex2d( w,-h);
+  glEnd();
+
+  glPopMatrix();
+
+  // Indicate the fact that we are not drawing in thumbnail mode
+  m_ThumbnailDrawing = false;
+  }
+
+GenericSliceRenderer::Texture *
+GenericSliceRenderer::CreateTexture(ImageWrapperBase *iw)
+{
+  if(iw->IsInitialized())
+    {
+    Texture *texture = new Texture(4, GL_RGBA);
+    texture->SetImage(iw->GetDisplaySlice(m_Model->GetId()).GetPointer());
+
+    const GlobalDisplaySettings *gds = m_Model->GetParentUI()->GetGlobalDisplaySettings();
+
+    GLint imode =
+        (gds->GetGreyInterpolationMode() == GlobalDisplaySettings::LINEAR)
+        ? GL_LINEAR : GL_NEAREST;
+
+    texture->SetInterpolation(imode);
+    return texture;
+    }
+  else return NULL;
+}
+
+/*
+void GenericSliceRenderer::AssociateTexture(
+  ImageWrapperBase *iw, TextureMap &src, TextureMap &trg)
+{
+  if(iw->IsInitialized())
+    {
+    TextureMap::iterator it = src.find(iw);
+    Texture *texture;
+
+    if (it != src.end())
+      {
+      texture = it->second;
+      itk::ImageBase<2> *b1 = iw->GetDisplaySlice(m_Model->GetId()).GetPointer();
+      const itk::ImageBase<2> *b2 = texture->GetImage();
+      std::cout << "TEX1 " << b1 << "   TEX2" << b2 << std::endl;
+      src.erase(it);
+      }
+    else
+      {
+      texture = new Texture(4, GL_RGBA);
+      texture->SetImage(iw->GetDisplaySlice(m_Model->GetId()).GetPointer());
+      }
+
+    // Set the interpolation approach
+    SNAPAppearanceSettings *as = m_Model->GetParentUI()->GetAppearanceSettings();
+    GLint imode = as->GetGreyInterpolationMode() == SNAPAppearanceSettings::LINEAR
+        ? GL_LINEAR : GL_NEAREST;
+    texture->SetInterpolation(imode);
+
+    // Store the texture association
+    trg[iw] = texture;
+    }
+}
+
+*/
+
+void GenericSliceRenderer::UpdateTextureMap()
+{
+  if(m_Model->IsSliceInitialized())
+    {
+    m_Texture.Update();
+    }
+}
+
+void GenericSliceRenderer::initializeGL()
+{
+}
+
+void GenericSliceRenderer::DrawTiledOverlays()
+{
+  // The renderer will contain a list of overlays that implement the
+  // generic interface
+  for(RendererDelegateList::iterator it = m_TiledOverlays.begin();
+      it != m_TiledOverlays.end(); it++)
+    {
+    (*it)->paintGL();
+    }
+}
+
+void GenericSliceRenderer::DrawGlobalOverlays()
+{
+  // The renderer will contain a list of overlays that implement the
+  // generic interface
+  for(RendererDelegateList::iterator it = m_GlobalOverlays.begin();
+      it != m_GlobalOverlays.end(); it++)
+    {
+    (*it)->paintGL();
+    }
+}
+
+OpenGLTextureAssociationFactory::Texture *
+OpenGLTextureAssociationFactory
+::New(ImageWrapperBase *layer)
+{
+  return m_Renderer->CreateTexture(layer);
+}
+
+
+template class LayerAssociation<GenericSliceRenderer::Texture,
+                                ImageWrapperBase,
+                                OpenGLTextureAssociationFactory>;
+
+
diff --git a/GUI/Renderer/GenericSliceRenderer.h b/GUI/Renderer/GenericSliceRenderer.h
new file mode 100644
index 0000000..3eb6ae6
--- /dev/null
+++ b/GUI/Renderer/GenericSliceRenderer.h
@@ -0,0 +1,149 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/
+
+#ifndef GENERICSLICERENDERER_H
+#define GENERICSLICERENDERER_H
+
+#include <AbstractRenderer.h>
+#include <GenericSliceModel.h>
+#include <ImageWrapper.h>
+#include <OpenGLSliceTexture.h>
+#include <SNAPOpenGL.h>
+#include <list>
+#include <LayerAssociation.h>
+
+class GenericSliceRenderer;
+
+class SliceRendererDelegate : public AbstractRenderer
+{
+public:
+  virtual ~SliceRendererDelegate() {}
+
+  irisGetSetMacro(ParentRenderer, GenericSliceRenderer *)
+
+protected:
+  GenericSliceRenderer *m_ParentRenderer;
+};
+
+struct OpenGLTextureAssociationFactory
+{
+  typedef OpenGLSliceTexture<ImageWrapperBase::DisplayPixelType> Texture;
+  Texture *New(ImageWrapperBase *layer);
+  GenericSliceRenderer *m_Renderer;
+};
+
+class GenericSliceRenderer : public AbstractRenderer
+{
+public:
+
+  irisITKObjectMacro(GenericSliceRenderer, AbstractModel)
+
+  FIRES(ModelUpdateEvent)
+
+  void SetModel(GenericSliceModel *model);
+
+  void initializeGL();
+  void resizeGL(int w, int h);
+  void paintGL();
+
+  irisGetMacro(Model, GenericSliceModel *)
+  irisIsMacro(ThumbnailDrawing)
+
+  typedef std::list<SliceRendererDelegate *> RendererDelegateList;
+
+  // Get a reference to the list of overlays stored in here
+  const RendererDelegateList &GetGlobalOverlays() const
+    { return m_GlobalOverlays; }
+
+  RendererDelegateList &GetGlobalOverlays()
+    { return m_GlobalOverlays; }
+
+  // Get a reference to the list of overlays stored in here
+  const RendererDelegateList &GetTiledOverlays() const
+    { return m_TiledOverlays; }
+
+  RendererDelegateList &GetTiledOverlays()
+    { return m_TiledOverlays; }
+
+  // This method can be used by the renderer delegates to draw a texture
+  void DrawTextureForLayer(ImageWrapperBase *layer, bool use_transparency);
+
+  // Get the layer that is drawn in the given tile
+  ImageWrapperBase *GetLayerForNthTile(int row, int col);
+
+  // A callback for when the model is reinitialized
+  // void OnModelReinitialize();
+
+protected:
+
+  GenericSliceRenderer();
+  virtual ~GenericSliceRenderer() {}
+
+  void OnUpdate();
+
+  void DrawMainTexture();
+  void DrawSegmentationTexture();
+  void DrawOverlayTexture();
+  void DrawThumbnail();
+  void DrawTiledOverlays();
+  void DrawGlobalOverlays();
+
+  // Draw the image and overlays either on top of each other or separately
+  // in individual cells. Returns true if a layer was drawn, false if not,
+  // i.e., the cell is outside of the range of available layers
+  bool DrawImageLayers(int nrows, int ncols, int irow, int icol);
+
+  GenericSliceModel *m_Model;
+
+  // Whether rendering to thumbnail or not
+  bool m_ThumbnailDrawing;
+
+  // A dynamic association between various image layers and texture objects
+  typedef OpenGLSliceTexture<ImageWrapperBase::DisplayPixelType> Texture;
+  typedef LayerAssociation<Texture, ImageWrapperBase,
+                           OpenGLTextureAssociationFactory> TextureMap;
+
+  TextureMap m_Texture;
+
+  // A list of overlays that the user can configure
+  RendererDelegateList m_TiledOverlays, m_GlobalOverlays;
+
+  // Internal method used by UpdateTextureMap()
+  // void AssociateTexture(ImageWrapperBase *iw, TextureMap &src, TextureMap &trg);
+
+  // Texture factory method
+  Texture *CreateTexture(ImageWrapperBase *iw);
+
+
+  // Update the texture map to mirror the current images in the model
+  void UpdateTextureMap();
+
+  friend struct OpenGLTextureAssociationFactory;
+};
+
+
+
+#endif // GENERICSLICERENDERER_H
diff --git a/GUI/Renderer/IntensityCurveVTKRenderer.cxx b/GUI/Renderer/IntensityCurveVTKRenderer.cxx
new file mode 100644
index 0000000..71c2273
--- /dev/null
+++ b/GUI/Renderer/IntensityCurveVTKRenderer.cxx
@@ -0,0 +1,578 @@
+#include "IntensityCurveVTKRenderer.h"
+
+#include <vtkChartXY.h>
+#include <vtkPlot.h>
+#include <vtkFloatArray.h>
+#include <vtkTable.h>
+#include <vtkContextView.h>
+#include <vtkContextScene.h>
+#include <vtkAxis.h>
+#include "vtkControlPointsItem.h"
+#include "vtkObjectFactory.h"
+#include "vtkContext2D.h"
+#include "vtkPen.h"
+#include "vtkBrush.h"
+#include "vtkGenericOpenGLRenderWindow.h"
+#include "vtkIdTypeArray.h"
+#include "vtkPlotPoints.h"
+#include "vtkTransform2D.h"
+#include "vtkScalarsToColorsItem.h"
+#include "vtkImageData.h"
+#include "vtkContextInteractorStyle.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkContextMouseEvent.h"
+#include "vtkChartLegend.h"
+
+#include "IntensityCurveModel.h"
+#include "IntensityCurveInterface.h"
+#include "LayerHistogramPlotAssembly.h"
+#include "ScalarImageHistogram.h"
+#include "ColorMapModel.h"
+
+
+class AbstractColorMapContextItem : public vtkScalarsToColorsItem
+{
+public:
+  vtkTypeMacro(AbstractColorMapContextItem, vtkScalarsToColorsItem)
+
+  void SetModel(IntensityCurveModel *model)
+  {
+    m_Model = model;
+    m_ColorMapModel = model->GetParentModel()->GetColorMapModel();
+    this->Modified();
+  }
+
+protected:
+
+  AbstractColorMapContextItem()
+  {
+    m_Model = NULL;
+    m_ColorMapModel = NULL;
+  }
+
+
+  virtual ~AbstractColorMapContextItem() {}
+
+  IntensityCurveModel *m_Model;
+  ColorMapModel *m_ColorMapModel;
+
+};
+
+
+
+class HorizontalColorMapContextItem : public AbstractColorMapContextItem
+{
+public:
+  vtkTypeMacro(HorizontalColorMapContextItem, AbstractColorMapContextItem)
+
+  static HorizontalColorMapContextItem *New();
+
+
+protected:
+
+  HorizontalColorMapContextItem() {}
+  virtual ~HorizontalColorMapContextItem() {}
+
+  virtual void GetBounds(double bounds[4])
+  {
+    if(m_Model && m_Model->GetLayer())
+      {
+      Vector2d vis_range = m_Model->GetVisibleImageRange();
+      bounds[0] = vis_range[0];
+      bounds[1] = vis_range[1];
+
+      // Draw under the axes
+      bounds[2] = -0.1;
+      bounds[3] = -0.02;
+      }
+  }
+
+  virtual void ComputeTexture()
+  {
+    // The size of the texture - fixed
+    const unsigned int dim = 256;
+
+    // Compute the bounds
+    double bounds[4];
+    this->GetBounds(bounds);
+    if (bounds[0] == bounds[1] || !m_Model)
+      return;
+
+    // Get the curve object
+    IntensityCurveInterface *curve = m_Model->GetCurve();
+
+    // Define the texture
+    if (this->Texture == 0)
+      {
+      this->Texture = vtkImageData::New();
+      this->Texture->SetExtent(0, dim-1, 0, 0, 0, 0);
+      this->Texture->SetPointDataActiveScalarInfo(
+            this->Texture->GetInformation(), VTK_UNSIGNED_CHAR, 4);
+      this->Texture->AllocateScalars(this->Texture->GetInformation());
+      }
+
+    // Get the texture array
+    unsigned char *data =
+        reinterpret_cast<unsigned char*>(this->Texture->GetScalarPointer(0,0,0));
+    Vector2d range = m_Model->GetNativeImageRangeForCurve();
+
+    // Get the colormap, and if there is none (RGB display), then use
+    // the default greyscale colormap
+    ColorMap *cm = m_ColorMapModel->GetColorMap();
+
+    // Draw the texture. The texture is being drawn on the x-axis, so it must
+    // first be interpolated through the intensity curve
+    for(int i = 0; i < dim; i++)
+      {
+      // Here x is the intensity value for which we want to look up the color
+      double x = bounds[0] + i * (bounds[1] - bounds[0]) / (dim - 1);
+
+      // We first map this to a value t, which is normalized for intensity range
+      double t = (x - range[0]) / (range[1] - range[0]);
+
+      // Map the intensity value to the colormap index
+      double y = curve->Evaluate(t);
+
+      // Below we handle the null colormap case, used when adjusting contrast
+      // on RGB-mode images
+      ColorMap::RGBAType rgba;
+      if(cm)
+        rgba = cm->MapIndexToRGBA(y);
+      else
+        rgba[0] = rgba[1] = rgba[2] = (unsigned char)(255.0 * y);
+
+      for(int j = 0; j < 3; j++)
+        *data++ = rgba[j];
+
+      // Skip the opacity part
+      *data++ = 255;
+      }
+
+    this->Texture->Modified();
+  }
+};
+
+
+
+class VerticalColorMapContextItem : public AbstractColorMapContextItem
+{
+public:
+  vtkTypeMacro(VerticalColorMapContextItem, AbstractColorMapContextItem)
+
+  static VerticalColorMapContextItem *New();
+
+
+protected:
+
+  VerticalColorMapContextItem() {}
+  virtual ~VerticalColorMapContextItem() {}
+
+  virtual void GetBounds(double bounds[4])
+  {
+    if(m_Model && m_Model->GetLayer())
+      {
+      Vector2d vis_range = m_Model->GetVisibleImageRange();
+      float margin = (vis_range[1] - vis_range[0]) / 40.0;
+      bounds[0] = vis_range[0] - 0.9 * margin;
+      bounds[1] = vis_range[0] - 0.1 * margin;
+      bounds[2] = 0.0;
+      bounds[3] = 1.0;
+      }
+  }
+
+  virtual void ComputeTexture()
+  {
+    if (!m_Model)
+      return;
+
+    // The size of the texture - fixed
+    const unsigned int dim = 256;
+
+    // Compute the bounds
+    double bounds[4];
+    this->GetBounds(bounds);
+
+    // Define the texture
+    if (this->Texture == 0)
+      {
+      vtkInformation *info = this->Texture->GetInformation();
+      this->Texture = vtkImageData::New();
+      this->Texture->SetExtent(0, 0, 0, 0, 0, dim-1);
+      this->Texture->SetPointDataActiveScalarInfo(info, VTK_UNSIGNED_CHAR, 4);
+      this->Texture->AllocateScalars(info);
+      }
+
+    // Get the texture array
+    unsigned char *data =
+        reinterpret_cast<unsigned char*>(this->Texture->GetScalarPointer(0,0,0));
+
+    // Get the colormap (may be NULL)
+    ColorMap *cm = m_ColorMapModel->GetColorMap();
+
+    // Draw the texture. The texture is being drawn on the y-axis, so we use
+    // simple interpolation
+    for(int i = 0; i < dim; i++)
+      {
+      // Here x is the intensity value for which we want to look up the color
+      double t = i * 1.0 / (dim - 1);
+
+      // Below we handle the null colormap case, used when adjusting contrast
+      // on RGB-mode images
+      ColorMap::RGBAType rgba;
+      if(cm)
+        rgba = cm->MapIndexToRGBA(t);
+      else
+        rgba[0] = rgba[1] = rgba[2] = (unsigned char)(255.0 * t);
+
+      for(int j = 0; j < 3; j++)
+        *data++ = rgba[j];
+
+      // Skip the opacity part
+      *data++ = 255;
+      }
+
+    this->Texture->Modified();
+  }
+};
+
+
+#include "vtkPiecewiseControlPointsItem.h"
+
+
+class IntensityCurveControlPointsContextItem : public vtkControlPointsItem
+{
+public:
+  vtkTypeMacro(IntensityCurveControlPointsContextItem, vtkControlPointsItem)
+
+  static IntensityCurveControlPointsContextItem *New();
+
+  virtual void GetControlPoint(vtkIdType index, double *point) const
+  {
+    // Return the coordinates of the point, in plot units
+    IntensityCurveInterface *curve = m_Model->GetCurve();
+    Vector2d range = m_Model->GetNativeImageRangeForCurve();
+
+    float t, x, y;
+    curve->GetControlPoint(index, t, y);
+    x = range[0] * (1 - t) + range[1] * t;
+
+    point[0] = x;
+    point[1] = y;
+  }
+
+  virtual vtkIdType GetNumberOfPoints() const
+  {
+    if(m_Model && m_Model->GetLayer())
+      return m_Model->GetCurve()->GetControlPointCount();
+    else return 0;
+  }
+
+  virtual vtkIdType RemovePoint(double *pos) { return -1; }
+
+  virtual vtkIdType AddPoint(double *newPos) { return -1; }
+
+  virtual void emitEvent(unsigned long event, void* params = 0) {};
+
+  virtual void SetControlPoint(vtkIdType index, double *point)
+  {
+    // Return the coordinates of the point, in plot units
+    Vector2d range = m_Model->GetNativeImageRangeForCurve();
+
+    // Force the positions of the starting and ending points
+    float t = (point[0] - range[0]) / (range[1] - range[0]);
+    float y = point[1];
+
+    m_Model->UpdateControlPoint(index, t, y);
+  }
+
+  virtual void DrawSelectedPoints(vtkContext2D *painter)
+  {
+    painter->GetBrush()->SetColor(255, 255, 0, 255);
+    Superclass::DrawSelectedPoints(painter);
+  }
+
+  // I had to cannibalize the paint method because VTK hardcoded some basic
+  // properties such as the point color
+  virtual bool Paint(vtkContext2D *painter)
+  {
+    painter->GetBrush()->SetColor(255, 0, 0, 255);
+    painter->GetPen()->SetLineType(vtkPen::SOLID_LINE);
+    painter->GetPen()->SetWidth(1.2);
+    painter->GetPen()->SetColor(0, 0, 0, 128);
+
+    // When expressing anything in screen pixel units, we need to watch out
+    // for retina displays
+    float vppr = m_Model->GetViewportReporter()->GetViewportPixelRatio();
+    this->ScreenPointRadius = 5 * vppr;
+    this->DrawUnselectedPoints(painter);
+
+    if (this->CurrentPoint != -1)
+      {
+
+      painter->GetBrush()->SetColor(255, 255, 0, 255);
+      painter->GetPen()->SetLineType(vtkPen::SOLID_LINE);
+
+      this->ScreenPointRadius = 6 * vppr;
+      this->DrawPoint(painter, this->CurrentPoint);
+      }
+
+    this->Transform->SetMatrix(painter->GetTransform()->GetMatrix());
+    return true;
+  }
+
+  virtual bool MouseButtonPressEvent(const vtkContextMouseEvent &mouse)
+  {
+    this->MouseMoved = false;
+
+    if (mouse.Button == vtkContextMouseEvent::LEFT_BUTTON)
+      {
+      double pos[2];
+      pos[0] = mouse.Pos[0];
+      pos[1] = mouse.Pos[1];
+      vtkIdType pointUnderMouse = this->FindPoint(pos);
+      this->SetCurrentPoint(pointUnderMouse);
+      return true;
+      }
+
+    else return false;
+  }
+
+  virtual unsigned long int GetControlPointsMTime()
+  {
+    // TODO: figure this out!
+    return this->GetMTime();
+  }
+
+
+  void SetModel(IntensityCurveModel *model)
+  {
+    m_Model = model;
+    this->Modified();
+  }
+
+protected:
+
+  IntensityCurveControlPointsContextItem()
+  {
+    m_Model = NULL;
+  }
+
+  ~IntensityCurveControlPointsContextItem() {}
+
+  IntensityCurveModel *m_Model;
+
+};
+
+
+vtkStandardNewMacro(HorizontalColorMapContextItem)
+vtkStandardNewMacro(VerticalColorMapContextItem)
+vtkStandardNewMacro(IntensityCurveControlPointsContextItem);
+
+
+IntensityCurveVTKRenderer::IntensityCurveVTKRenderer()
+  : AbstractVTKSceneRenderer()
+{
+  this->m_RenderWindow->SetMultiSamples(0);
+  this->m_RenderWindow->SetLineSmoothing(1);
+  this->m_RenderWindow->SetPolygonSmoothing(1);
+
+  m_Model = NULL;
+
+  // Set up the scene for rendering
+  m_Chart = vtkSmartPointer<vtkChartXY>::New();
+
+  // Configure chart behavior
+  m_Chart->ForceAxesToBoundsOn();
+
+  // Add the chart to the renderer
+  m_ContextView->GetScene()->AddItem(m_Chart);
+
+  // Set up the data
+  m_CurveX = vtkSmartPointer<vtkFloatArray>::New();
+  m_CurveX->SetName("Image Intensity");
+  m_CurveY = vtkSmartPointer<vtkFloatArray>::New();
+  m_CurveY->SetName("Output Intensity");
+
+  // Set up the table
+  m_PlotTable = vtkSmartPointer<vtkTable>::New();
+  m_PlotTable->AddColumn(m_CurveX);
+  m_PlotTable->AddColumn(m_CurveY);
+
+  // There are additional points at the tails of the curve so it looks like
+  // the curve runs over the entire range of the axis
+  m_PlotTable->SetNumberOfRows(CURVE_RESOLUTION+3);
+
+  // Set up the histogram plot
+  m_HistogramAssembly = new LayerHistogramPlotAssembly();
+  m_HistogramAssembly->AddToChart(m_Chart);
+
+  // Set up the curve plot
+  m_CurvePlot = m_Chart->AddPlot(vtkChart::LINE);
+  m_CurvePlot->SetInputData(m_PlotTable, 0, 1);
+  m_CurvePlot->SetColor(1, 0, 0);
+  m_CurvePlot->SetWidth(1.0);
+  m_CurvePlot->GetYAxis()->SetBehavior(vtkAxis::FIXED);
+  m_CurvePlot->GetYAxis()->SetMinimumLimit(-0.1);
+  m_CurvePlot->GetYAxis()->SetMinimum(-0.1);
+  m_CurvePlot->GetYAxis()->SetMaximumLimit(1.1);
+  m_CurvePlot->GetYAxis()->SetMaximum(1.1);
+
+  m_CurvePlot->GetXAxis()->SetTitle("Image Intensity");
+  m_CurvePlot->GetYAxis()->SetTitle("Index into Color Map");
+  m_CurvePlot->GetXAxis()->SetBehavior(vtkAxis::FIXED);
+
+  // Set up the color map plot
+  m_XColorMapItem = vtkSmartPointer<HorizontalColorMapContextItem>::New();
+  m_YColorMapItem = vtkSmartPointer<VerticalColorMapContextItem>::New();
+  m_Chart->AddPlot(m_XColorMapItem);
+
+  // I commented this out, because the chart looks too busy
+  // m_Chart->AddPlot(m_YColorMapItem);
+
+  m_Controls = vtkSmartPointer<IntensityCurveControlPointsContextItem>::New();
+  m_Chart->AddPlot(m_Controls);
+
+  // Disable the legend in the plot. This seems like somewhat of a bug, but
+  // the Hit() method in vtkChartLegend responds to events even when the
+  // legend is not visible. So we have to instead make the legend not draggable
+  m_Chart->SetShowLegend(false);
+  m_Chart->GetLegend()->SetDragEnabled(false);
+
+  // Listen to events from the control points item, in order to synchronize
+  // the selected control point in the model with the context item
+  AddListenerVTK(m_Controls, vtkControlPointsItem::CurrentPointChangedEvent,
+                 this, &Self::OnCurrentControlPointChangedInScene);
+
+}
+
+IntensityCurveVTKRenderer::~IntensityCurveVTKRenderer()
+{
+  delete m_HistogramAssembly;
+}
+
+void
+IntensityCurveVTKRenderer
+::SetModel(IntensityCurveModel *model)
+{
+  m_Model = model;
+
+  m_Controls->SetModel(model);
+  m_XColorMapItem->SetModel(model);
+  m_YColorMapItem->SetModel(model);
+
+  // Rebroadcast the relevant events from the model in order for the
+  // widget that uses this renderer to cause an update
+  Rebroadcast(model, ModelUpdateEvent(), ModelUpdateEvent());
+}
+
+
+
+void
+IntensityCurveVTKRenderer
+::UpdatePlotValues()
+{
+  if(m_Model->GetLayer())
+    {
+    IntensityCurveInterface *curve = m_Model->GetCurve();
+    Vector2d range = m_Model->GetNativeImageRangeForCurve();
+
+    // Get the range over which to draw the curve
+    float t0, t1, y0, y1;
+    curve->GetControlPoint(0, t0, y0);
+    curve->GetControlPoint(curve->GetControlPointCount() - 1, t1, y1);
+
+    // Compute the range over which the curve is plotted, where [0 1] is the
+    // image intensity range
+    float z0 = std::min(t0, 0.0f);
+    float z1 = std::max(t1, 1.0f);
+
+    // Compute the range over which the curve is plotted, in intensity units
+    float x0 = range[0] * (1 - z0) + range[1] * z0;
+    float x1 = range[0] * (1 - z1) + range[1] * z1;
+
+    // Sample the curve
+    for(int i = 0; i <= CURVE_RESOLUTION; i++)
+      {
+      float p = i * 1.0 / CURVE_RESOLUTION;
+      float t = z0 * (1.0 - p) + z1 * p;
+      float x = x0 * (1.0 - p) + x1 * p;
+      float y = curve->Evaluate(t);
+      m_CurveX->SetValue(i+1, x);
+      m_CurveY->SetValue(i+1, y);
+      }
+
+    // Set the range of the plot. In order for the control points to be visible,
+    // we include a small margin on the left and right.
+    float margin = (x1 - x0) / 40.0;
+    m_CurvePlot->GetXAxis()->SetMinimumLimit(x0 - margin);
+    m_CurvePlot->GetXAxis()->SetMaximumLimit(x1 + margin);
+    m_CurvePlot->GetXAxis()->SetMinimum(x0 - margin);
+    m_CurvePlot->GetXAxis()->SetMaximum(x1 + margin);
+
+    // While we are here, also update the range of the y axis, because it seems
+    // that it sometimes gets messed up due to mouse interaction
+    m_CurvePlot->GetYAxis()->SetMinimumLimit(-0.1);
+    m_CurvePlot->GetYAxis()->SetMinimum(-0.1);
+    m_CurvePlot->GetYAxis()->SetMaximumLimit(1.1);
+    m_CurvePlot->GetYAxis()->SetMaximum(1.1);
+
+
+    // While we are here, we need to set the bounds on the control point plot
+    m_Controls->SetUserBounds(x0, x1, 0.0, 1.0);
+
+    // And also make sure the selected point is correctly set
+    int cpoint;
+    if(m_Model->GetMovingControlIdModel()->GetValueAndDomain(cpoint, NULL))
+      m_Controls->SetCurrentPoint(cpoint - 1);
+    else
+      m_Controls->SetCurrentPoint(-1);
+
+    // Set the terminal points of the curve as well
+    m_CurveX->SetValue(0, x0 - margin);
+    m_CurveY->SetValue(0, 0.0);
+    m_CurveX->SetValue(CURVE_RESOLUTION+2, x1 + margin);
+    m_CurveY->SetValue(CURVE_RESOLUTION+2, 1.0);
+
+    m_PlotTable->Modified();
+
+    // Compute the histogram entries
+    m_HistogramAssembly->PlotWithFixedLimits(
+          m_Model->GetHistogram(), 0.0, 1.0,
+          m_Model->GetProperties().GetHistogramCutoff(),
+          m_Model->GetProperties().IsHistogramLog());
+
+    m_XColorMapItem->Modified();
+    m_YColorMapItem->Modified();
+
+    m_Chart->RecalculateBounds();
+
+
+    }
+}
+
+void IntensityCurveVTKRenderer::paintGL()
+{
+  if(m_Model && m_Model->GetLayer())
+    {
+    Superclass::paintGL();
+    }
+}
+
+void
+IntensityCurveVTKRenderer
+::OnUpdate()
+{
+  m_Model->Update();
+  if(m_Model && m_Model->GetLayer())
+    {
+    this->UpdatePlotValues();
+    }
+}
+
+void
+IntensityCurveVTKRenderer
+::OnCurrentControlPointChangedInScene(vtkObject *, unsigned long , void *)
+{
+  m_Model->GetMovingControlIdModel()->SetValue(
+        m_Controls->GetCurrentPoint() + 1);
+}
diff --git a/GUI/Renderer/IntensityCurveVTKRenderer.h b/GUI/Renderer/IntensityCurveVTKRenderer.h
new file mode 100644
index 0000000..94b10db
--- /dev/null
+++ b/GUI/Renderer/IntensityCurveVTKRenderer.h
@@ -0,0 +1,63 @@
+#ifndef INTENSITYCURVEVTKRENDERER_H
+#define INTENSITYCURVEVTKRENDERER_H
+
+#include "AbstractVTKSceneRenderer.h"
+#include "vtkSmartPointer.h"
+#include "LayerHistogramPlotAssembly.h"
+
+class vtkActor;
+class vtkPropAssembly;
+class vtkChartXY;
+class vtkFloatArray;
+class vtkPlot;
+class vtkTable;
+
+class IntensityCurveModel;
+class IntensityCurveControlPointsContextItem;
+class AbstractColorMapContextItem;
+class HorizontalColorMapContextItem;
+class VerticalColorMapContextItem;
+
+class IntensityCurveVTKRenderer : public AbstractVTKSceneRenderer
+{
+public:
+  irisITKObjectMacro(IntensityCurveVTKRenderer, AbstractVTKSceneRenderer)
+
+  void SetModel(IntensityCurveModel *model);
+
+  void OnUpdate();
+
+  void UpdatePlotValues();
+
+  virtual void paintGL();
+
+protected:
+
+  IntensityCurveVTKRenderer();
+  virtual ~IntensityCurveVTKRenderer();
+
+  // Rendering stuff
+  vtkSmartPointer<vtkChartXY> m_Chart;
+  vtkSmartPointer<vtkTable> m_PlotTable;
+  vtkSmartPointer<vtkPlot> m_CurvePlot;
+  vtkSmartPointer<vtkFloatArray> m_CurveX, m_CurveY;
+
+  // vtkSmartPointer<IntensityCurveControlPointsContextItem> m_ControlPoints;
+
+  vtkSmartPointer<IntensityCurveControlPointsContextItem> m_Controls;
+
+  // Histogram
+  LayerHistogramPlotAssembly *m_HistogramAssembly;
+
+  vtkSmartPointer<HorizontalColorMapContextItem> m_XColorMapItem;
+  vtkSmartPointer<VerticalColorMapContextItem> m_YColorMapItem;
+
+  IntensityCurveModel *m_Model;
+
+  enum { CURVE_RESOLUTION = 64 };
+
+  void OnCurrentControlPointChangedInScene(vtkObject *, unsigned long, void *);
+
+};
+
+#endif // INTENSITYCURVEVTKRENDERER_H
diff --git a/GUI/Renderer/LayerHistogramPlotAssembly.cxx b/GUI/Renderer/LayerHistogramPlotAssembly.cxx
new file mode 100644
index 0000000..831a5d5
--- /dev/null
+++ b/GUI/Renderer/LayerHistogramPlotAssembly.cxx
@@ -0,0 +1,101 @@
+#include "LayerHistogramPlotAssembly.h"
+
+#include <vtkChartXY.h>
+#include <vtkPlot.h>
+#include <vtkFloatArray.h>
+#include <vtkTable.h>
+#include <vtkAxis.h>
+
+#include "ScalarImageHistogram.h"
+
+LayerHistogramPlotAssembly::LayerHistogramPlotAssembly()
+{
+  // Set up the histogram plot
+  m_HistogramX = vtkSmartPointer<vtkFloatArray>::New();
+  m_HistogramX->SetName("Image Intensity");
+  m_HistogramY = vtkSmartPointer<vtkFloatArray>::New();
+  m_HistogramY->SetName("Frequency");
+  m_HistogramTable = vtkSmartPointer<vtkTable>::New();
+  m_HistogramTable->AddColumn(m_HistogramX);
+  m_HistogramTable->AddColumn(m_HistogramY);
+
+  m_ReasonableScaleHeightParameter = 0.6;
+  m_ReasonableScaleQuantileParameter = 0.95;
+}
+
+void LayerHistogramPlotAssembly::AddToChart(vtkChartXY *chart)
+{
+  m_HistogramPlot = chart->AddPlot(vtkChart::BAR);
+  m_HistogramPlot->SetInputData(m_HistogramTable, 0, 1);
+  m_HistogramPlot->SetColor(0.8, 0.8, 1.0);
+}
+
+/**
+ * Plot the histogram with fixed limits of the frequency variable. The
+ * histogram is scaled within the limits, so that the zero frequency is
+ * plotted at ymin, and the largest plottable frequency is plotted at ymax.
+ *
+ * The largest plottable frequency can be specified as the percentage of
+ * the highest frequency or if the percentage is set to zero, it is computed
+ * automatically using quantiles
+ */
+void LayerHistogramPlotAssembly::PlotWithFixedLimits(
+    const ScalarImageHistogram *histogram,
+    double ymin, double ymax,
+    double max_plotted_freq_fraction,
+    bool log_plot)
+{
+  // Compute the histogram entries
+  m_HistogramTable->SetNumberOfRows(histogram->GetSize());
+
+  // Determine the maximum frequency we are going to show
+  double fmax = (max_plotted_freq_fraction > 0.0)
+      ? histogram->GetMaxFrequency() * max_plotted_freq_fraction
+      : histogram->GetMaxFrequency() * histogram->GetReasonableDisplayCutoff(
+          m_ReasonableScaleQuantileParameter,
+          m_ReasonableScaleHeightParameter);
+
+  // Change it to log if necessary
+  if(log_plot)
+    fmax = log10(fmax);
+
+  // Plot the frequency values
+  for(int i = 0; i < histogram->GetSize(); i++)
+    {
+    m_HistogramX->SetValue(i, histogram->GetBinCenter(i));
+
+    double y = histogram->GetFrequency(i);
+    if(log_plot)
+      y = log10(y);
+
+    double yplot = (y / fmax) * (ymax - ymin) + ymin;
+    m_HistogramY->SetValue(i, yplot);
+    }
+
+  m_HistogramTable->Modified();
+}
+
+double LayerHistogramPlotAssembly::PlotAsEmpiricalDensity(
+    const ScalarImageHistogram *histogram)
+{
+  // Compute the histogram entries
+  m_HistogramTable->SetNumberOfRows(histogram->GetSize());
+
+  // Figure out how to scale the histogram
+  double scaleFactor = 1.0 / (histogram->GetTotalSamples() * histogram->GetBinWidth());
+
+  // Plot the bins
+  for(int i = 0; i < histogram->GetSize(); i++)
+    {
+    m_HistogramX->SetValue(i, histogram->GetBinCenter(i));
+    m_HistogramY->SetValue(i, histogram->GetFrequency(i) * scaleFactor);
+    }
+
+  m_HistogramTable->Modified();
+
+  // Return the y cutoff
+  return histogram->GetReasonableDisplayCutoff(
+        m_ReasonableScaleQuantileParameter,
+        m_ReasonableScaleHeightParameter)
+      * histogram->GetMaxFrequency() * scaleFactor;
+}
diff --git a/GUI/Renderer/LayerHistogramPlotAssembly.h b/GUI/Renderer/LayerHistogramPlotAssembly.h
new file mode 100644
index 0000000..4e801d1
--- /dev/null
+++ b/GUI/Renderer/LayerHistogramPlotAssembly.h
@@ -0,0 +1,67 @@
+#ifndef LAYERHISTOGRAMPLOTASSEMBLY_H
+#define LAYERHISTOGRAMPLOTASSEMBLY_H
+
+#include "SNAPCommon.h"
+
+class vtkActor;
+class vtkChartXY;
+class vtkFloatArray;
+class vtkPlot;
+class vtkTable;
+
+class ScalarImageHistogram;
+
+#include <vtkSmartPointer.h>
+
+/**
+ * @brief The HistogramPlotAssembly class
+ * This class creates vtk objects needed to plot a histogram of a
+ * SNAP image layer using VTK charts
+ */
+class LayerHistogramPlotAssembly
+{
+public:
+  LayerHistogramPlotAssembly();
+
+  void AddToChart(vtkChartXY *chart);
+
+  /** See ScalarImageHistogram::GetReasonableDisplayCutoff */
+  irisGetSetMacro(ReasonableScaleQuantileParameter, double)
+
+  /** See ScalarImageHistogram::GetReasonableDisplayCutoff */
+  irisGetSetMacro(ReasonableScaleHeightParameter, double)
+
+  /**
+   * Plot the histogram with fixed limits of the frequency variable. The
+   * histogram is scaled within the limits, so that the zero frequency is
+   * plotted at ymin, and the largest plottable frequency is plotted at ymax.
+   *
+   * The largest plottable frequency can be specified as the percentage of
+   * the highest frequency or if the percentage is set to zero, it is computed
+   * automatically using quantiles
+   */
+  void PlotWithFixedLimits(
+      const ScalarImageHistogram *histogram,
+      double ymin, double ymax,
+      double max_plotted_freq_fraction = 0.0,
+      bool log_plot = false);
+
+  /**
+   * Plot the histogram as an empirical probability density. The heights
+   * (y coordinates) of the bars are scaled so that the histogram integrates
+   * to one. The reasonable max for the y coordinate (one that tries to
+   * assure that outlier bins don't cause the rest of the histogram to shrink)
+   * is returned.
+   */
+  double PlotAsEmpiricalDensity(const ScalarImageHistogram *histogram);
+
+protected:
+  vtkSmartPointer<vtkTable> m_HistogramTable;
+  vtkSmartPointer<vtkPlot> m_HistogramPlot;
+  vtkSmartPointer<vtkFloatArray> m_HistogramX, m_HistogramY;
+
+  double m_ReasonableScaleQuantileParameter;
+  double m_ReasonableScaleHeightParameter;
+};
+
+#endif // LAYERHISTOGRAMPLOTASSEMBLY_H
diff --git a/GUI/Renderer/OpenGLSliceTexture.cxx b/GUI/Renderer/OpenGLSliceTexture.cxx
new file mode 100755
index 0000000..424fdbe
--- /dev/null
+++ b/GUI/Renderer/OpenGLSliceTexture.cxx
@@ -0,0 +1,252 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: OpenGLSliceTexture.cxx,v $
+  Language:  C++
+  Date:      $Date: 2009/08/25 19:44:25 $
+  Version:   $Revision: 1.2 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#include "OpenGLSliceTexture.h"
+#include "ImageWrapper.h"
+
+
+template<class TPixel>
+OpenGLSliceTexture<TPixel>
+::OpenGLSliceTexture()
+{
+  // Set to -1 to force a call to 'generate'
+  m_IsTextureInitalized = false;
+
+  // Set the update time to -1
+  m_UpdateTime = 0;
+
+  // Init the GL settings to uchar, luminance defautls, which are harmless
+  m_GlComponents = 1;
+  m_GlFormat = GL_LUMINANCE;
+  m_GlType = GL_UNSIGNED_BYTE;
+  m_InterpolationMode = GL_NEAREST;
+}
+
+template<class TPixel>
+OpenGLSliceTexture<TPixel>
+::OpenGLSliceTexture(GLuint components, GLenum format)
+{
+  // Set to -1 to force a call to 'generate'
+  m_IsTextureInitalized = false;
+
+  // Set the update time to -1
+  m_UpdateTime = 0;
+
+  // Init the GL settings to uchar, luminance defautls, which are harmless
+  m_GlComponents = components;
+  m_GlFormat = format;
+  m_GlType = GL_UNSIGNED_BYTE;
+  m_InterpolationMode = GL_NEAREST;
+}
+
+template<class TPixel>
+OpenGLSliceTexture<TPixel>
+::~OpenGLSliceTexture()
+{
+  if(m_IsTextureInitalized)
+    glDeleteTextures(1,&m_TextureIndex);
+}
+
+template<class TPixel>
+void
+OpenGLSliceTexture<TPixel>
+::SetInterpolation(GLenum interp)
+{
+  assert(interp == GL_LINEAR || interp == GL_NEAREST);
+  if(interp != m_InterpolationMode)
+    {
+    m_InterpolationMode = interp;
+    m_UpdateTime = 0; // make it out-of-date
+    }
+}
+
+
+template<class TPixel>
+void
+OpenGLSliceTexture<TPixel>
+::Update()
+{
+  // Better have an image
+  assert(m_Image);
+
+  // Update the image (necessary?)
+  if(m_Image->GetSource())
+    m_Image->GetSource()->UpdateLargestPossibleRegion();
+
+  // Check if everything is up-to-date and no computation is needed
+  if (m_IsTextureInitalized && m_UpdateTime == m_Image->GetPipelineMTime())
+    {
+    return;
+    }
+
+  // Promote the image dimensions to powers of 2
+  itk::Size<2> szImage = m_Image->GetLargestPossibleRegion().GetSize();
+  m_TextureSize = Vector2ui(1);
+
+  // Use shift to quickly double the coordinates
+  for (unsigned int i=0;i<2;i++)
+    while (m_TextureSize(i) < szImage[i])
+      m_TextureSize(i) <<= 1;
+
+  // Create the texture index if necessary
+  if(!m_IsTextureInitalized)
+    {
+    // Generate one texture
+    glGenTextures(1,&m_TextureIndex);
+    m_IsTextureInitalized = true;
+    }
+
+  // Select the texture for pixel pumping
+  glBindTexture(GL_TEXTURE_2D,m_TextureIndex);
+
+  // Properties for the texture
+  glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_InterpolationMode );
+  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_InterpolationMode );
+
+  // Turn off modulo-4 rounding in GL
+  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+  glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+  // Allocate texture of slightly bigger size
+  glTexImage2D(GL_TEXTURE_2D, 0, m_GlComponents,
+    m_TextureSize(0), m_TextureSize(1),
+    0, m_GlFormat, m_GlType, NULL);
+
+  // Copy a subtexture of correct size into the image
+  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, szImage[0], szImage[1],
+                  m_GlFormat, m_GlType, m_Image->GetBufferPointer());
+
+  // Remember the image's timestamp
+  m_UpdateTime = m_Image->GetPipelineMTime();
+}
+
+
+template<class TPixel>
+void
+OpenGLSliceTexture<TPixel>
+::Draw(const Vector3d &clrBackground)
+{
+  // Update the texture
+  Update();
+
+  // Should have a texture number
+  assert(m_IsTextureInitalized);
+
+  // GL settings
+  glPushAttrib(GL_TEXTURE_BIT);
+  glEnable(GL_TEXTURE_2D);
+
+  // Select our texture
+  glBindTexture(GL_TEXTURE_2D,m_TextureIndex);
+
+  // Set the color to the background color
+  glColor3dv(clrBackground.data_block());
+
+  int w = m_Image->GetBufferedRegion().GetSize()[0];
+  int h = m_Image->GetBufferedRegion().GetSize()[1];
+  double tx = w * 1.0 / m_TextureSize(0);
+  double ty = h * 1.0 / m_TextureSize(1);
+
+  // Draw quad 
+  glBegin(GL_QUADS);
+  glTexCoord2d(0,0);
+  glVertex2d(0,0);
+  glTexCoord2d(0,ty);
+  glVertex2d(0,h);
+  glTexCoord2d(tx,ty);
+  glVertex2d(w,h);
+  glTexCoord2d(tx,0);
+  glVertex2d(w,0);
+  glEnd();
+
+  glPopAttrib();
+}
+
+
+template<class TPixel>
+void
+OpenGLSliceTexture<TPixel>
+::DrawTransparent(double alpha)
+{
+  // Update the texture
+  Update();
+
+  // Should have a texture number
+  assert(m_IsTextureInitalized);
+
+  // GL settings
+  glPushAttrib(GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
+  glEnable(GL_TEXTURE_2D);
+
+  // Turn on alpha blending
+  glEnable(GL_BLEND);
+  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+
+  // Select our texture
+  glBindTexture(GL_TEXTURE_2D,m_TextureIndex);
+
+  // Set the color to white
+  glColor4ub(255,255,255,(unsigned char)(alpha * 255));
+    
+  int w = m_Image->GetBufferedRegion().GetSize()[0];
+  int h = m_Image->GetBufferedRegion().GetSize()[1];
+  double tx = w * 1.0 / m_TextureSize(0);
+  double ty = h * 1.0 / m_TextureSize(1);
+
+  // Draw quad 
+  glBegin(GL_QUADS);
+  glTexCoord2d(0,0);
+  glVertex2d(0,0);
+  glTexCoord2d(0,ty);
+  glVertex2d(0,h);
+  glTexCoord2d(tx,ty);
+  glVertex2d(w,h);
+  glTexCoord2d(tx,0);
+  glVertex2d(w,0);
+  glEnd();
+
+  glPopAttrib();
+}
+
+template<class TPixel>
+void OpenGLSliceTexture<TPixel>::SetImage(ImageType *inImage)
+{
+  m_Image = inImage;
+  m_Image->GetSource()->UpdateLargestPossibleRegion();
+  m_UpdateTime = 0;
+}
+
+// Explicit instantiation of templates
+template class OpenGLSliceTexture<ImageWrapperBase::DisplayPixelType>;
diff --git a/GUI/Renderer/OpenGLSliceTexture.h b/GUI/Renderer/OpenGLSliceTexture.h
new file mode 100644
index 0000000..561f30c
--- /dev/null
+++ b/GUI/Renderer/OpenGLSliceTexture.h
@@ -0,0 +1,144 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: OpenGLSliceTexture.h,v $
+  Language:  C++
+  Date:      $Date: 2009/08/25 19:44:25 $
+  Version:   $Revision: 1.9 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#ifndef __OpenGLSliceTexture_h_
+#define __OpenGLSliceTexture_h_
+
+#include "SNAPCommon.h"
+#include "SNAPOpenGL.h"
+
+#ifndef _WIN32
+#ifndef GLU_VERSION_1_2
+#define GLU_VERSION_1_2 1
+#endif
+#endif
+
+#include "itkImage.h"
+
+/**
+ * \class OpenGLSliceTexture
+ * \brief This class is used to turn a 2D ITK image of (arbitrary) type
+ * into a GL texture.  
+ *
+ * The calls to Update will make sure that the texture is up to date.  
+ */
+template <class TPixel>
+class OpenGLSliceTexture 
+{
+public:
+  // Image typedefs
+  typedef itk::Image<TPixel, 2> ImageType;
+  typedef typename itk::SmartPointer<ImageType> ImagePointer;
+
+  /** Constructor, initializes the texture object */
+  OpenGLSliceTexture();
+  OpenGLSliceTexture(GLuint, GLenum);
+
+  /** Destructor, deallocates texture memory */
+  virtual ~OpenGLSliceTexture();
+  
+  irisGetMacro(Image, const ImageType *);
+
+  /** Pass in a pointer to a 2D image */
+  void SetImage(ImageType *inImage);
+
+  /** Get the dimensions of the texture image, which are powers of 2 */
+  irisGetMacro(TextureSize,Vector2ui);
+
+  /** Get the GL texture number automatically allocated by this object */
+  irisGetMacro(TextureIndex,int);
+
+  /** Set the number of components used in call to glTextureImage */
+  irisSetMacro(GlComponents,GLuint);
+
+  /** Get the format (e.g. GL_LUMINANCE) in call to glTextureImage */
+  irisSetMacro(GlFormat,GLenum);
+
+  /** Get the type (e.g. GL_UNSIGNED_INT) in call to glTextureImage */
+  irisSetMacro(GlType,GLenum);
+
+  /**
+   * Make sure that the texture is up to date (reflects the image)
+   */
+  void Update();
+
+  /**
+   * Set the interpolation mode for the texture. If the interpolation mode
+   * is changed, Update() will be called on the next Draw() command. The value
+   * must be GL_NEAREST or GL_LINEAR
+   */
+  void SetInterpolation(GLenum newmode);
+
+  /**
+   * Draw the texture in the current OpenGL context on a polygon with vertices
+   * (0,0) - (size_x,size_y). Paramters are the background color of the polygon
+   */
+  void Draw(const Vector3d &clrBackground);
+
+  /**
+   * Draw the texture in transparent mode, with given level of alpha blending.
+   */
+  void DrawTransparent(double alpha);
+
+private:
+  
+  // The dimensions of the texture as stored in memory
+  Vector2ui m_TextureSize;
+
+  // The pointer to the image from which the texture is computed
+  ImagePointer m_Image;
+
+  // The texture number (index)
+  GLuint m_TextureIndex;
+
+  // Has the texture been initialized?
+  bool m_IsTextureInitalized;
+
+  // The pipeline time of the source image (vs. our pipeline time)
+  unsigned long m_UpdateTime;
+
+  // The number of components for Gl op
+  GLuint m_GlComponents;
+
+  // The format for Gl op
+  GLenum m_GlFormat;
+
+  // The type for Gl op
+  GLenum m_GlType;
+
+  // Interpolation mode
+  GLenum m_InterpolationMode;
+};
+
+#endif // __OpenGLSliceTexture_h_
diff --git a/GUI/Renderer/OrientationGraphicRenderer.cxx b/GUI/Renderer/OrientationGraphicRenderer.cxx
new file mode 100644
index 0000000..7f4c7c8
--- /dev/null
+++ b/GUI/Renderer/OrientationGraphicRenderer.cxx
@@ -0,0 +1,93 @@
+#include "OrientationGraphicRenderer.h"
+
+#include <vtkSphereSource.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkRenderer.h>
+#include <vtkGenericOpenGLRenderWindow.h>
+#include <vtkProperty.h>
+#include <vtkCamera.h>
+
+#include "ScannedHuman.h"
+#include "ScanningROI.h"
+#include "AxesWidget.h"
+#include <PropertyModel.h>
+
+OrientationGraphicRenderer::OrientationGraphicRenderer()
+{
+  m_Model = NULL;
+
+  //m_Dummy = vtkSmartPointer<vtkSphereSource>::New();
+  //m_Dummy->SetCenter(0.0, 0.0, 0.0);
+  //m_Dummy->SetRadius(200.00);
+
+//  vtkSmartPointer<vtkPolyDataMapper> mapper =
+//      vtkSmartPointer<vtkPolyDataMapper>::New();
+//  mapper->SetInputConnection(m_Dummy->GetOutputPort());
+
+//  vtkSmartPointer<vtkActor> actor =
+//      vtkSmartPointer<vtkActor>::New();
+//  actor->SetMapper(mapper);
+
+//  actor->GetProperty()->SetColor(0, 0, 1);
+//  actor->GetProperty()->SetOpacity(1.0);
+
+  //this->m_Renderer->AddActor(actor);
+
+  double dbGraphicScale = 2.0;
+  double dbPositionFactor = 2.6;
+
+  m_ReorientProps.Connect2Renderer(m_Renderer);
+
+  vtkCamera * pCamera = m_Renderer->GetActiveCamera();
+  double dbPosXYZ = dbGraphicScale * dbPositionFactor;
+  pCamera->SetPosition(dbPosXYZ, -dbPosXYZ, dbPosXYZ);
+  pCamera->SetViewUp(0.0, -1.0, 0.0);
+
+  this->SetInteractionStyle(TRACKBALL_CAMERA);
+}
+
+
+
+void OrientationGraphicRenderer::SetModel(DirectionMatrixModel *model)
+{
+  this->m_Model = model;
+
+  // Rebroadcast the relevant events from the model in order for the
+  // widget that uses this renderer to cause an update
+  Rebroadcast(m_Model, ValueChangedEvent(), ModelUpdateEvent());
+}
+
+void OrientationGraphicRenderer::OnUpdate()
+{
+  // Get the current direction matrix from the model ...
+  DirectionMatrix dm;
+  if(m_Model->GetValueAndDomain(dm, NULL))
+    {
+    // Set the transform on the slices and arrows ...
+    vtkSmartPointer < vtkMatrix4x4 > pMatrix4x4 =
+        vtkSmartPointer < vtkMatrix4x4 >::New();
+    pMatrix4x4->Identity();
+    int nI, nJ;
+    for(nI = 0; nI < 3; nI++)
+      {
+      for(nJ = 0; nJ < 3; nJ++)
+        {
+        (*pMatrix4x4)[nI][nJ] = dm[nI][nJ];
+        }
+    }
+    m_ReorientProps.Update(pMatrix4x4);
+    }
+  else
+    {
+    // Hide the slices and arrows
+    m_ReorientProps.SetROIVisibility(false);
+    }
+}
+
+void OrientationGraphicRenderer::Update(const vtkSmartPointer < vtkMatrix4x4 > apMatrix4x4)
+{
+  m_ReorientProps.Update(apMatrix4x4);
+
+  GetRenderWindow()->Render();
+}
diff --git a/GUI/Renderer/OrientationGraphicRenderer.h b/GUI/Renderer/OrientationGraphicRenderer.h
new file mode 100644
index 0000000..c871500
--- /dev/null
+++ b/GUI/Renderer/OrientationGraphicRenderer.h
@@ -0,0 +1,40 @@
+#ifndef ORIENTATIONGRAPHICRENDERER_H
+#define ORIENTATIONGRAPHICRENDERER_H
+
+#include "vtkMatrix4x4.h"
+#include "AbstractVTKRenderer.h"
+#include "vtkSmartPointer.h"
+#include "PropertyModel.h"
+#include "ReorientProps.h"
+
+class vtkSphereSource;
+
+class OrientationGraphicRenderer : public AbstractVTKRenderer
+{
+public:
+
+  typedef vnl_matrix<double> DirectionMatrix;
+  typedef AbstractPropertyModel<DirectionMatrix> DirectionMatrixModel;
+
+  irisITKObjectMacro(OrientationGraphicRenderer, AbstractVTKRenderer)
+
+  void SetModel(DirectionMatrixModel *model);
+
+  void OnUpdate();
+
+  void Update(const vtkSmartPointer < vtkMatrix4x4 > apMatrix4x4);
+
+  //void SetDirections(const vtkSmartPointer < vtkMatrix4x4 > apDirections);
+  //void GetDirections(vtkSmartPointer < vtkMatrix4x4 > apDirections) const;
+
+protected:
+
+  OrientationGraphicRenderer();
+  virtual ~OrientationGraphicRenderer() {}
+
+  DirectionMatrixModel *m_Model;
+
+  ReorientProps m_ReorientProps;
+};
+
+#endif // ORIENTATIONGRAPHICRENDERER_H
diff --git a/GUI/Renderer/OrientationWidget/Reorient/AbstractScannerHelper.cxx b/GUI/Renderer/OrientationWidget/Reorient/AbstractScannerHelper.cxx
new file mode 100755
index 0000000..e7638b6
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/AbstractScannerHelper.cxx
@@ -0,0 +1,29 @@
+#include <vtkObjectFactory.h>
+#include <vtkAssembly.h>
+
+#include "AbstractScannerHelper.h"
+
+AbstractScannerHelper::AbstractScannerHelper()
+{
+
+  //setGraphicScale(1.0);
+  
+  m_pvtkAssembly = vtkSmartPointer < vtkAssembly >::New();
+  
+}
+
+AbstractScannerHelper::~AbstractScannerHelper()
+{
+}
+
+void AbstractScannerHelper::setGraphicScale(double adbGraphicScale)
+{
+
+  m_dbGraphicScale = adbGraphicScale;
+
+}
+
+vtkSmartPointer < vtkAssembly > AbstractScannerHelper::getAssembly()
+{
+  return(m_pvtkAssembly);
+}
diff --git a/GUI/Renderer/OrientationWidget/Reorient/AbstractScannerHelper.h b/GUI/Renderer/OrientationWidget/Reorient/AbstractScannerHelper.h
new file mode 100755
index 0000000..8cf78df
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/AbstractScannerHelper.h
@@ -0,0 +1,28 @@
+#ifndef ABSTRACT_SCANNER_HELPER_H
+#define ABSTRACT_SCANNER_HELPER_H
+
+#include "vtkSmartPointer.h"
+class vtkObject;
+class vtkAssembly;
+
+class PolyDataAlgorithm2ActorPipe;
+
+class AbstractScannerHelper : public vtkObject
+{
+protected:
+
+  vtkSmartPointer < vtkAssembly > m_pvtkAssembly;
+  double m_dbGraphicScale;
+  
+  AbstractScannerHelper();
+  virtual ~AbstractScannerHelper() = 0;
+
+public:
+  static AbstractScannerHelper * New();
+  
+  virtual void setGraphicScale(double adbGraphicScale) = 0;
+  vtkSmartPointer < vtkAssembly > getAssembly();
+};
+
+
+#endif //ABSTRACT_SCANNER_HELPER_H
diff --git a/GUI/Renderer/OrientationWidget/Reorient/AxesWidget.cxx b/GUI/Renderer/OrientationWidget/Reorient/AxesWidget.cxx
new file mode 100755
index 0000000..175b797
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/AxesWidget.cxx
@@ -0,0 +1,105 @@
+#include "vtkObjectFactory.h"
+#include "vtkAxesActor.h"
+#include "vtkSmartPointer.h"
+#include "vtkCaptionActor2D.h"
+#include "vtkTextProperty.h"
+#include "vtkProperty.h"
+
+#include "AxesWidget.h"
+
+const double AxesWidget::m_arrdbColRed[3] = {1.0, 0.0, 0.0};
+const double AxesWidget::m_arrdbColGreen[3] = {0.0, 1.0, 0.0};
+const double AxesWidget::m_arrdbColBlue[3] = {0.0, 0.0, 1.0};
+
+AxesWidget::AxesWidget()
+{
+ 
+  m_pvtkAxesActor = vtkSmartPointer < vtkAxesActor > ::New();
+
+  m_pvtkAxesActor->SetShaftTypeToCylinder();
+  m_pvtkAxesActor->SetXAxisLabelText( "x" );
+  m_pvtkAxesActor->SetYAxisLabelText( "y" );
+  m_pvtkAxesActor->SetZAxisLabelText( "z" );
+
+  m_pvtkAxesActor->SetTotalLength( 1.5, 1.5, 1.5 );
+  m_pvtkAxesActor->SetCylinderRadius( 0.500 * m_pvtkAxesActor->GetCylinderRadius() );
+  m_pvtkAxesActor->SetConeRadius    ( 1.025 * m_pvtkAxesActor->GetConeRadius() );
+  m_pvtkAxesActor->SetSphereRadius  ( 1.500 * m_pvtkAxesActor->GetSphereRadius() );
+
+  m_pvtkAxesActor->SetConeResolution(100);
+  m_pvtkAxesActor->SetCylinderResolution(100);
+
+  vtkTextProperty* tprop = m_pvtkAxesActor->GetXAxisCaptionActor2D()->
+    GetCaptionTextProperty();
+  tprop->ItalicOn();
+  tprop->ShadowOn();
+  tprop->SetFontFamilyToTimes();
+
+  m_pvtkAxesActor->GetYAxisCaptionActor2D()->GetCaptionTextProperty()->ShallowCopy( tprop );
+  m_pvtkAxesActor->GetZAxisCaptionActor2D()->GetCaptionTextProperty()->ShallowCopy( tprop );
+
+}
+
+vtkStandardNewMacro(AxesWidget);
+
+void AxesWidget::VisibilityOn()
+{
+  m_pvtkAxesActor->VisibilityOn();
+}
+
+void AxesWidget::VisibilityOff()
+{
+  m_pvtkAxesActor->VisibilityOff();
+}
+
+int AxesWidget::GetVisibility()
+{
+  return(m_pvtkAxesActor->GetVisibility());
+}
+
+void AxesWidget::SetVisibility(int Visibility) {
+  m_pvtkAxesActor->SetVisibility(Visibility);
+
+  m_pvtkAxesActor->GetXAxisCaptionActor2D()->SetVisibility(Visibility);
+  m_pvtkAxesActor->GetYAxisCaptionActor2D()->SetVisibility(Visibility);
+  m_pvtkAxesActor->GetZAxisCaptionActor2D()->SetVisibility(Visibility);
+}
+
+void AxesWidget::SetLengths(double adbLength)
+{
+  m_pvtkAxesActor->SetTotalLength
+    //SetNormalizedShaftLength
+    (adbLength, adbLength, adbLength);
+}
+
+vtkSmartPointer < vtkAxesActor > AxesWidget::GetAxesActor()
+{
+  return(m_pvtkAxesActor);
+}
+
+void AxesWidget::SetLabels(const char * apchX, const char * apchY, const char * apchZ)
+{
+  m_pvtkAxesActor->SetXAxisLabelText( apchX );
+  m_pvtkAxesActor->SetYAxisLabelText( apchY );
+  m_pvtkAxesActor->SetZAxisLabelText( apchZ );
+}
+
+void AxesWidget::SetColors(const double aarrdbX[3], const double aarrdbY[3], const double aarrdbZ[3])
+{
+
+  vtkSmartPointer < vtkAxesActor > pAxesActor = GetAxesActor();
+
+  double arrdbX[3], arrdbY[3], arrdbZ[3];
+  memcpy(arrdbX, aarrdbX, 3 * sizeof(double));
+  memcpy(arrdbY, aarrdbY, 3 * sizeof(double));
+  memcpy(arrdbZ, aarrdbZ, 3 * sizeof(double));
+
+  pAxesActor->GetXAxisTipProperty()->SetColor(arrdbX);
+  pAxesActor->GetYAxisTipProperty()->SetColor(arrdbY);
+  pAxesActor->GetZAxisTipProperty()->SetColor(arrdbZ);
+
+  pAxesActor->GetXAxisShaftProperty()->SetColor(arrdbX);
+  pAxesActor->GetYAxisShaftProperty()->SetColor(arrdbY);
+  pAxesActor->GetZAxisShaftProperty()->SetColor(arrdbZ);
+
+}
diff --git a/GUI/Renderer/OrientationWidget/Reorient/AxesWidget.h b/GUI/Renderer/OrientationWidget/Reorient/AxesWidget.h
new file mode 100755
index 0000000..4469e9e
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/AxesWidget.h
@@ -0,0 +1,36 @@
+#ifndef AXES_WIDGET_H
+#define AXES_WIDGET_H
+
+#include "vtkObject.h"
+#include "vtkAxesActor.h"
+#include "vtkSmartPointer.h"
+
+class AxesWidget : public vtkObject {
+	AxesWidget();
+
+public:
+
+    static const double m_arrdbColRed[3];
+    static const double m_arrdbColGreen[3];
+    static const double m_arrdbColBlue[3];
+
+	virtual void VisibilityOn();
+	virtual void VisibilityOff();
+	virtual int GetVisibility();
+    virtual void SetVisibility(int anVisibility);
+
+	static AxesWidget * New();
+	
+
+	void SetLengths(double adbLength);
+
+	vtkSmartPointer < vtkAxesActor > GetAxesActor();
+
+	void SetLabels(const char * apchX, const char * apchY, const char * apchZ);
+    void SetColors(const double aarrdbX[3], const double aarrdbY[3], const double aarrdbZ[3]);
+protected:
+	vtkSmartPointer < vtkAxesActor > m_pvtkAxesActor;
+private:
+};
+
+#endif //AXES_WIDGET_H
diff --git a/GUI/Renderer/OrientationWidget/Reorient/PolyDataAlgorithm2ActorPipe.cxx b/GUI/Renderer/OrientationWidget/Reorient/PolyDataAlgorithm2ActorPipe.cxx
new file mode 100755
index 0000000..871243e
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/PolyDataAlgorithm2ActorPipe.cxx
@@ -0,0 +1,37 @@
+#include <vtkPolyDataAlgorithm.h>
+#include <vtkObjectFactory.h>
+#include <vtkActor.h>
+#include <vtkPolyDataMapper.h>
+
+#include "PolyDataAlgorithm2ActorPipe.h"
+
+vtkStandardNewMacro(PolyDataAlgorithm2ActorPipe);
+
+PolyDataAlgorithm2ActorPipe::PolyDataAlgorithm2ActorPipe()
+{
+
+  m_pvtkPolyDataMapper = vtkSmartPointer < vtkPolyDataMapper >::New();
+  m_pvtkActor = vtkSmartPointer < vtkActor >::New();
+  m_pvtkActor->SetMapper(m_pvtkPolyDataMapper);
+
+}
+
+void PolyDataAlgorithm2ActorPipe::setSource(vtkSmartPointer < vtkPolyDataAlgorithm > apvtkPolyDataAlgorithm)
+{
+  m_pvtkPolyDataAlgorithm = apvtkPolyDataAlgorithm;
+  m_pvtkPolyDataMapper->SetInputConnection(m_pvtkPolyDataAlgorithm->GetOutputPort());
+}
+
+vtkSmartPointer < vtkActor > PolyDataAlgorithm2ActorPipe::getActor()
+{
+  return(m_pvtkActor);
+}
+
+vtkProperty * PolyDataAlgorithm2ActorPipe::getProperty()
+{
+  vtkActor * pActor = getActor();
+
+  vtkProperty * pProperty = pActor->GetProperty();
+
+  return(pProperty);
+}
diff --git a/GUI/Renderer/OrientationWidget/Reorient/PolyDataAlgorithm2ActorPipe.h b/GUI/Renderer/OrientationWidget/Reorient/PolyDataAlgorithm2ActorPipe.h
new file mode 100755
index 0000000..2895cf8
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/PolyDataAlgorithm2ActorPipe.h
@@ -0,0 +1,28 @@
+#ifndef SOURCE_2_ACTOR_PIPE_H
+#define SOURCE_2_ACTOR_PIPE_H
+
+#include "vtkSmartPointer.h"
+class vtkObject;
+class vtkPolyDataAlgorithm;
+class vtkPolyDataMapper;
+class vtkActor;
+class vtkProperty;
+
+class PolyDataAlgorithm2ActorPipe : public vtkObject
+{
+  vtkSmartPointer < vtkPolyDataAlgorithm > m_pvtkPolyDataAlgorithm;
+  vtkSmartPointer < vtkPolyDataMapper > m_pvtkPolyDataMapper;
+  vtkSmartPointer < vtkActor > m_pvtkActor;
+
+  PolyDataAlgorithm2ActorPipe();
+public:
+
+  static PolyDataAlgorithm2ActorPipe *New();
+  
+  void setSource(vtkSmartPointer < vtkPolyDataAlgorithm > apvtkPolyDataAlgorithm);
+  
+  vtkSmartPointer < vtkActor > getActor();
+  vtkProperty * getProperty();
+};
+
+#endif //SOURCE_2_ACTOR_PIPE_H
diff --git a/GUI/Renderer/OrientationWidget/Reorient/ReorientProps.cxx b/GUI/Renderer/OrientationWidget/Reorient/ReorientProps.cxx
new file mode 100755
index 0000000..e5dfd29
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/ReorientProps.cxx
@@ -0,0 +1,103 @@
+#include "vtkCamera.h"
+#include "vtkRenderWindow.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkRenderer.h"
+#include "vtkWindowToImageFilter.h"
+#include "vtkBMPWriter.h"
+#include "vtkTextProperty.h"
+#include "vtkCaptionActor2D.h"
+#include "vtkMath.h"
+
+#include "ScanningROI.h"
+#include "ReorientProps.h"
+
+bool ReorientProps::isMatrixValid(const vtkSmartPointer < vtkMatrix4x4 > apMatrix4x4)
+{
+  const double dbError = 0.01;
+  double dbDeterminant = apMatrix4x4->Determinant();
+  if(fabs(fabs(dbDeterminant) -  1.0) > dbError)
+  {
+    return(false);
+  }
+
+  int nI, nJ;
+  for(nI = 0; nI < 3; nI++)
+    {
+    double * pdbLine1 = apMatrix4x4->Element[nI];
+    for(nJ = nI + 1; nJ < 3; nJ++)
+      {
+      double * pdbLine2 = apMatrix4x4->Element[nJ];
+      //check orthogonality
+      double dbDotProd = vtkMath::Dot(pdbLine1, pdbLine2);
+      if(fabs(dbDotProd) > dbError)
+      {
+        return(false);
+      }
+      //check normality
+      double dbNorm = vtkMath::Norm(pdbLine1);
+      if(fabs(dbNorm - 1.0) > dbError)
+      {
+          return(false);
+      }
+      }
+    }
+
+  return(true);
+}
+
+ReorientProps::ReorientProps()
+{
+  //m_pAxesWidgetAbsolute = vtkSmartPointer < AxesWidget >::New();
+  //m_pAxesWidgetAbsolute->SetLengths(3.0);
+
+  m_pScannedHuman = vtkSmartPointer < ScannedHuman >::New();
+  m_pScannedHuman->setGraphicScale(1.0);
+
+  m_pScanningROI = vtkSmartPointer < ScanningROI >::New();
+  m_pScanningROI->setGraphicScale(2.0);
+}
+
+ReorientProps::~ReorientProps()
+{
+}
+
+void ReorientProps::Update(const vtkSmartPointer < vtkMatrix4x4 > apMatrix4x4)
+{
+  if(isMatrixValid(apMatrix4x4))
+    {
+    m_pScanningROI->SetVisibility(1);
+    SetDirections(apMatrix4x4);
+    }
+  else
+    m_pScanningROI->SetVisibility(0);
+  m_pScanningROI->Update();
+}
+
+void ReorientProps::SetDirections(const vtkSmartPointer < vtkMatrix4x4 > apDirections)
+{
+	m_pScanningROI->setDirections(apDirections);
+}
+
+void ReorientProps::GetDirections(vtkSmartPointer < vtkMatrix4x4 > apDirections) const
+{
+  vtkSmartPointer < vtkMatrix4x4 > pDirections =
+	  m_pScanningROI->getDirections();
+  apDirections->DeepCopy(pDirections);
+}
+
+void ReorientProps::Connect2Renderer(vtkRenderer * apRenderer)
+{
+  //apRenderer->AddActor(m_pAxesWidgetAbsolute->GetAxesActor());
+  apRenderer->AddActor(m_pScannedHuman->getAssembly());
+  apRenderer->AddActor(m_pScanningROI->getAssembly());
+
+  vtkSmartPointer < vtkAxesActor > pAxesActor = m_pScanningROI->m_pAxesWidget->GetAxesActor();
+  apRenderer->AddActor(pAxesActor->GetXAxisCaptionActor2D());
+  apRenderer->AddActor(pAxesActor->GetYAxisCaptionActor2D());
+  apRenderer->AddActor(pAxesActor->GetZAxisCaptionActor2D());
+}
+
+void ReorientProps::SetROIVisibility(int anVisibility)
+{
+  m_pScanningROI->SetVisibility(anVisibility);
+}
diff --git a/GUI/Renderer/OrientationWidget/Reorient/ReorientProps.h b/GUI/Renderer/OrientationWidget/Reorient/ReorientProps.h
new file mode 100755
index 0000000..a49fd6f
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/ReorientProps.h
@@ -0,0 +1,36 @@
+#ifndef REORIENT_PROPS_H
+#define REORIENT_PROPS_H
+
+#include <vtkSmartPointer.h>
+#include <vtkMatrix4x4.h>
+
+#include "AxesWidget.h"
+
+#include "ScannedHuman.h"
+#include "ScanningROI.h"
+
+class ReorientProps
+{
+  //vtkSmartPointer < AxesWidget > m_pAxesWidgetAbsolute;
+  vtkSmartPointer < ScannedHuman > m_pScannedHuman;
+  vtkSmartPointer < ScanningROI > m_pScanningROI;
+
+  static bool isMatrixValid(const vtkSmartPointer < vtkMatrix4x4 > apMatrix4x4);
+
+public:
+
+  ReorientProps();
+  ~ReorientProps();
+  
+  void Update(const vtkSmartPointer < vtkMatrix4x4 > apMatrix4x4);
+
+  void SetDirections(const vtkSmartPointer < vtkMatrix4x4 > apDirections);
+  void GetDirections(vtkSmartPointer < vtkMatrix4x4 > apDirections) const;
+
+  virtual void Connect2Renderer(vtkRenderer * apRenderer);
+
+  void SetROIVisibility(int anVisibility);
+};
+
+
+#endif //REORIENT_PROPS_H
diff --git a/GUI/Renderer/OrientationWidget/Reorient/ScannedHuman.cxx b/GUI/Renderer/OrientationWidget/Reorient/ScannedHuman.cxx
new file mode 100755
index 0000000..a084c8f
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/ScannedHuman.cxx
@@ -0,0 +1,131 @@
+#include <vtkPolyDataAlgorithm.h>
+#include <vtkObjectFactory.h>
+#include <vtkProperty.h>
+#include <vtkActor.h>
+#include <vtkLineSource.h>
+#include <vtkPoints.h>
+
+#include "ScannedHuman.h"
+
+vtkStandardNewMacro(ScannedHuman);
+
+ScannedHuman::ScannedHuman()
+{
+  m_pSphereSourceHead = vtkSmartPointer < vtkSphereSource >::New();
+  m_pSphereSourceRightEye = vtkSmartPointer < vtkSphereSource >::New();
+  m_pSphereSourceLeftEye = vtkSmartPointer < vtkSphereSource >::New();
+  m_pConeSource = vtkSmartPointer < vtkConeSource >::New();
+
+  m_pPolyDataMouth = vtkSmartPointer < vtkPolyData >::New();
+  m_pPointsMouth = vtkSmartPointer < vtkPoints >::New();
+  m_pPolyDataMouth->SetPoints(m_pPointsMouth);
+  m_pCellArrayMouthLines = vtkSmartPointer < vtkCellArray >::New();
+  m_pPolyDataMouth->SetLines(m_pCellArrayMouthLines);
+
+  m_pTubeFilterMouth = vtkSmartPointer < vtkTubeFilter >::New();
+  m_pTubeFilterMouth->SetInputData(m_pPolyDataMouth);
+  
+  m_pCubeSourceBody = vtkSmartPointer < vtkCubeSource >::New();
+    
+  m_PipeHead = vtkSmartPointer < PolyDataAlgorithm2ActorPipe >::New();
+  m_PipeRightEye = vtkSmartPointer < PolyDataAlgorithm2ActorPipe >::New();
+  m_PipeLeftEye = vtkSmartPointer < PolyDataAlgorithm2ActorPipe >::New();
+  m_PipeCone = vtkSmartPointer < PolyDataAlgorithm2ActorPipe >::New();
+  m_PipeMouth = vtkSmartPointer < PolyDataAlgorithm2ActorPipe >::New();
+  m_PipeBody = vtkSmartPointer < PolyDataAlgorithm2ActorPipe >::New();
+  
+  m_PipeHead->setSource(m_pSphereSourceHead);
+  m_PipeRightEye->setSource(m_pSphereSourceRightEye);
+  m_PipeLeftEye->setSource(m_pSphereSourceLeftEye);
+  m_PipeCone->setSource(m_pConeSource);
+  m_PipeMouth->setSource(m_pTubeFilterMouth);
+  m_PipeBody->setSource(m_pCubeSourceBody);
+
+  m_pvtkAssembly->AddPart(m_PipeHead->getActor());
+  m_pvtkAssembly->AddPart(m_PipeRightEye->getActor());
+  m_pvtkAssembly->AddPart(m_PipeLeftEye->getActor());
+  m_pvtkAssembly->AddPart(m_PipeCone->getActor());
+  m_pvtkAssembly->AddPart(m_PipeMouth->getActor());
+  m_pvtkAssembly->AddPart(m_PipeBody->getActor());
+
+  setGraphicScale(1.0);
+
+}
+
+void ScannedHuman::setGraphicScale(double adbGraphicScale)
+{
+  AbstractScannerHelper::setGraphicScale(adbGraphicScale);
+
+  double dbL = adbGraphicScale;
+  
+  vtkSmartPointer < vtkActor > pActor = m_PipeHead->getActor();
+  vtkProperty * pProperty = pActor->GetProperty();
+  pProperty->SetColor(0.0, 0.0, 1.0);
+  //pProperty->SetDiffuseColor(0.0, 0.0, 1.0);
+  //pProperty->SetDiffuse(1.0);
+  pProperty->SetSpecularColor(0.0, 0.0, 1.0);
+  pProperty->SetSpecular(1.0);
+  pActor->SetPosition(0.0, 0.0, dbL * 1.5);
+  m_pSphereSourceHead->SetThetaResolution(100);
+  m_pSphereSourceHead->SetPhiResolution(100);
+
+  pActor = m_PipeRightEye->getActor();
+  pProperty = pActor->GetProperty();
+  pProperty->SetColor(1.0, 1.0, 1.0);
+  pActor->SetPosition(- dbL / 5, - dbL / 2.85, dbL * 1.7);
+  m_pSphereSourceRightEye->SetRadius(dbL/8.0);
+  m_pSphereSourceRightEye->SetThetaResolution(100);
+  m_pSphereSourceRightEye->SetPhiResolution(100);
+
+  pActor = m_PipeLeftEye->getActor();
+  pProperty = pActor->GetProperty();
+  pProperty->SetColor(1.0, 1.0, 1.0);
+  pActor->SetPosition(dbL / 5, - dbL / 2.85, dbL * 1.7);
+  m_pSphereSourceLeftEye->SetRadius(dbL/8.0);
+  m_pSphereSourceLeftEye->SetThetaResolution(100);
+  m_pSphereSourceLeftEye->SetPhiResolution(100);
+  
+  pActor = m_PipeCone->getActor();
+  pProperty = pActor->GetProperty();
+  pProperty->SetColor(1.0, 1.0, 1.0);
+  double arrdbConeCenter[3];
+  arrdbConeCenter[0] = 0.0;
+  arrdbConeCenter[1] = - dbL * 0.6;
+  arrdbConeCenter[2] = dbL * 1.5;
+  pActor->SetPosition(arrdbConeCenter);
+  m_pConeSource->SetHeight(dbL * 0.25);
+  m_pConeSource->SetRadius(dbL * 0.1);
+  m_pConeSource->SetDirection(0.0, - 1.0, 0.0);
+  m_pConeSource->SetResolution(100);
+  
+  pActor = m_PipeMouth->getActor();
+  pProperty = pActor->GetProperty();
+  pProperty->SetColor(1.0, 1.0, 1.0);
+  m_pTubeFilterMouth->SetRadius(0.05*dbL);
+  m_pTubeFilterMouth->SetNumberOfSides(100);
+  int nPointsNr = 11;
+  m_pPointsMouth->SetNumberOfPoints(nPointsNr);
+  int nI;
+  for(nI = 0; nI < nPointsNr; nI++)
+  {
+	double dbAlpha = 5.0 * ((double)(nI - 5)) / 180.0;
+	m_pPointsMouth->SetPoint (nI,
+		arrdbConeCenter[0] + sin(dbAlpha) * dbL,
+		arrdbConeCenter[1] - cos(dbAlpha) * dbL + dbL * 1.15,
+		arrdbConeCenter[2] - dbL * 0.2);
+  }
+  m_pCellArrayMouthLines->InsertNextCell(nPointsNr);
+  for(nI = 0; nI < nPointsNr; nI++)
+    m_pCellArrayMouthLines->InsertCellPoint(nI);
+
+  pActor = m_PipeBody->getActor();
+  pProperty = pActor->GetProperty();
+  pProperty->SetColor(0.0, 0.0, 1.0);
+  //pProperty->SetDiffuseColor(0.0, 0.0, 1.0);
+  //pProperty->SetDiffuse(1.0);
+  pProperty->SetSpecularColor(0.0, 0.0, 1.0);
+  pProperty->SetSpecular(0.5);
+  m_pCubeSourceBody->SetYLength(0.75 * dbL);
+  m_pCubeSourceBody->SetZLength(2 * dbL);
+
+}
diff --git a/GUI/Renderer/OrientationWidget/Reorient/ScannedHuman.h b/GUI/Renderer/OrientationWidget/Reorient/ScannedHuman.h
new file mode 100755
index 0000000..eb611e0
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/ScannedHuman.h
@@ -0,0 +1,45 @@
+#ifndef SCANNED_HUMAN_H
+#define SCANNED_HUMAN_H
+
+#include <vtkSmartPointer.h>
+#include <vtkSphereSource.h>
+#include <vtkConeSource.h>
+#include <vtkCubeSource.h>
+#include <vtkCellArray.h>
+#include <vtkTubeFilter.h>
+#include <vtkAssembly.h>
+
+#include "PolyDataAlgorithm2ActorPipe.h"
+#include "AbstractScannerHelper.h"
+
+class ScannedHuman : public AbstractScannerHelper
+{
+  vtkSmartPointer < vtkSphereSource > m_pSphereSourceHead;
+  vtkSmartPointer < PolyDataAlgorithm2ActorPipe > m_PipeHead;
+  
+  vtkSmartPointer < vtkSphereSource > m_pSphereSourceRightEye;
+  vtkSmartPointer < PolyDataAlgorithm2ActorPipe > m_PipeRightEye;
+  
+  vtkSmartPointer < vtkSphereSource > m_pSphereSourceLeftEye;
+  vtkSmartPointer < PolyDataAlgorithm2ActorPipe > m_PipeLeftEye;
+  
+  vtkSmartPointer < vtkConeSource > m_pConeSource;
+  vtkSmartPointer < PolyDataAlgorithm2ActorPipe > m_PipeCone;
+
+  vtkSmartPointer < vtkPoints > m_pPointsMouth;
+  vtkSmartPointer < vtkCellArray > m_pCellArrayMouthLines;
+  vtkSmartPointer < vtkTubeFilter > m_pTubeFilterMouth;
+  vtkSmartPointer < vtkPolyData > m_pPolyDataMouth;
+  vtkSmartPointer < PolyDataAlgorithm2ActorPipe > m_PipeMouth;
+  
+  vtkSmartPointer < vtkCubeSource > m_pCubeSourceBody;
+  vtkSmartPointer < PolyDataAlgorithm2ActorPipe > m_PipeBody;
+
+  ScannedHuman();
+public:
+  static ScannedHuman * New();
+  
+  virtual void setGraphicScale(double adbGraphicScale);
+};
+
+#endif //SCANNED_HUMAN_H
diff --git a/GUI/Renderer/OrientationWidget/Reorient/ScanningROI.cxx b/GUI/Renderer/OrientationWidget/Reorient/ScanningROI.cxx
new file mode 100755
index 0000000..a3fdc42
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/ScanningROI.cxx
@@ -0,0 +1,320 @@
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataAlgorithm.h>
+#include <vtkObjectFactory.h>
+#include <vtkProperty.h>
+#include <vtkLineSource.h>
+#include <vtkPoints.h>
+#include <vtkLinearTransform.h>
+#include <vtkTransform.h>
+#include <vtkArrowSource.h>
+#include <vtkCaptionActor2D.h>
+#include <vtkTextProperty.h>
+#include <vtkProp.h>
+#include <vtkActor.h>
+#include <vtkPolyDataNormals.h>
+#include <vtkPlaneSource.h>
+#include <vtkAxesActor.h>
+#include <vtkAssembly.h>
+#include <vtkTubeFilter.h>
+#include <vtkCellArray.h>
+#include <vtkLine.h>
+#include <vtkLineSource.h>
+
+#include "PolyDataAlgorithm2ActorPipe.h"
+#include "ScanningROI.h"
+#include "AxesWidget.h"
+
+Pairs_Plane_Pipe::Pairs_Plane_Pipe()
+{
+  init();
+}
+
+void Pairs_Plane_Pipe::init(int anGridResolution)
+{
+  m_p_PlaneSource = vtkSmartPointer < vtkPlaneSource >::New();
+  m_p_PlaneSource_Pipe = vtkSmartPointer < PolyDataAlgorithm2ActorPipe >::New();
+  m_p_PlaneSource_Pipe->setSource(m_p_PlaneSource);
+
+  m_p_TubeFilter_WireFrame = vtkSmartPointer < vtkTubeFilter >::New();
+  m_p_TubeFilter_WireFrame_Pipe = vtkSmartPointer < PolyDataAlgorithm2ActorPipe >::New();
+  m_p_TubeFilter_WireFrame_Pipe->setSource(m_p_TubeFilter_WireFrame);
+
+  m_arrp_TubeFilter_PlanarGrid.resize(anGridResolution);
+  m_arrp_TubeFilter_PlanarGrid_Pipe.resize(anGridResolution);
+  int nI;
+  for(nI = 0; nI < anGridResolution; nI++)
+    {
+    m_arrp_TubeFilter_PlanarGrid[nI] = vtkSmartPointer < vtkTubeFilter >::New();
+    m_arrp_TubeFilter_PlanarGrid_Pipe[nI] = vtkSmartPointer < PolyDataAlgorithm2ActorPipe >::New();
+    m_arrp_TubeFilter_PlanarGrid_Pipe[nI]->setSource(m_arrp_TubeFilter_PlanarGrid[nI]);
+    }
+}
+
+void Pairs_Plane_Pipe::SetVisibility(int anVisibility)
+{
+  m_p_PlaneSource_Pipe->getActor()->SetVisibility(anVisibility);
+
+  m_p_TubeFilter_WireFrame_Pipe->getActor()->SetVisibility(anVisibility);
+
+  for(size_t nI = 0; nI < m_arrp_TubeFilter_PlanarGrid_Pipe.size(); nI++)
+    {
+    m_arrp_TubeFilter_PlanarGrid_Pipe[nI]->getActor()->SetVisibility(anVisibility);
+    }
+}
+
+vtkStandardNewMacro(ScanningROI);
+
+ScanningROI::ScanningROI()
+{
+
+  m_pMatrix4x4Directions = vtkSmartPointer < vtkMatrix4x4 > ::New();
+  m_pMatrix4x4Directions->Identity();
+
+  int nPlanesNr = 5;
+
+  m_arrdbSpacing[0] = 1.0;
+  m_arrdbSpacing[1] = 1.0;
+  m_arrdbSpacing[2] = 1.0;
+  
+  setPlanesNr(nPlanesNr);
+
+  m_pAxesWidget = vtkSmartPointer < AxesWidget >::New();
+  m_pvtkAssembly->AddPart(m_pAxesWidget->GetAxesActor());
+
+  setGraphicScale(1.0);
+
+}
+
+void ScanningROI::setPlanesNr(int anPlanesNr)
+{
+
+  int nI, nJ;
+  
+  int nPlanesNr = m_arrpPairsPP_Axial.size();
+  if(nPlanesNr != anPlanesNr)
+    {
+
+    for(nI = 0; nI < nPlanesNr; nI++)
+	  {
+      Pairs_Plane_Pipe & ppp = m_arrpPairsPP_Axial[nI];
+      m_pvtkAssembly->RemovePart(ppp.m_p_PlaneSource_Pipe->getActor());
+      m_pvtkAssembly->RemovePart(ppp.m_p_TubeFilter_WireFrame_Pipe->getActor());
+      for(nJ = 0; nJ < nPlanesNr; nJ++)
+        {
+        m_pvtkAssembly->RemovePart(ppp.m_arrp_TubeFilter_PlanarGrid_Pipe[nJ]->getActor());
+        }
+      }
+    m_arrpPairsPP_Axial.resize(anPlanesNr);
+	for(nI = 0; nI < anPlanesNr; nI++)
+	  {
+      Pairs_Plane_Pipe & ppp = m_arrpPairsPP_Axial[nI];
+      ppp.init(anPlanesNr);
+      m_pvtkAssembly->AddPart(ppp.m_p_PlaneSource_Pipe->getActor());
+      m_pvtkAssembly->AddPart(ppp.m_p_TubeFilter_WireFrame_Pipe->getActor());
+      for(nJ = 0; nJ < anPlanesNr; nJ++)
+        {
+        m_pvtkAssembly->AddPart(ppp.m_arrp_TubeFilter_PlanarGrid_Pipe[nJ]->getActor());
+        }
+	  }						 
+    }
+  for(nI = 0; nI < anPlanesNr; nI++)
+    {
+    Pairs_Plane_Pipe & ppp = m_arrpPairsPP_Axial[nI];
+    vtkSmartPointer < PolyDataAlgorithm2ActorPipe > pPipe = ppp.m_p_PlaneSource_Pipe;
+	vtkProperty * pProperty = pPipe->getProperty();
+    pProperty->SetColor(1.0, 1.0, 1.0);
+    pProperty->SetOpacity(0.2);
+
+    pPipe = ppp.m_p_TubeFilter_WireFrame_Pipe;
+    pProperty = pPipe->getProperty();
+    pProperty->SetColor(1.0, 1.0, 1.0);
+
+    for(nJ = 0; nJ < anPlanesNr; nJ++)
+      {
+      pPipe = ppp.m_arrp_TubeFilter_PlanarGrid_Pipe[nJ];
+      pProperty = pPipe->getProperty();
+      pProperty->SetColor(0.8, 0.8, 0.8);
+      pProperty->SetOpacity(0.2);
+      }
+    }
+   
+}
+
+int ScanningROI::getPlanesNr() const
+{
+  return(m_arrpPairsPP_Axial.size());
+}
+
+void ScanningROI::setSpacing(double adbX, double adbY, double adbZ)
+{
+  m_arrdbSpacing[0] = adbX;
+  m_arrdbSpacing[1] = adbY;
+  m_arrdbSpacing[2] = adbZ;
+}
+
+void ScanningROI::setSpacing(double aarrdbXYZ[3])
+{
+  setSpacing(aarrdbXYZ[0], aarrdbXYZ[1], aarrdbXYZ[2]);
+}
+
+void ScanningROI::Update()
+{
+
+  vtkSmartPointer < vtkMatrix4x4 > pMatrix4x4DirectionsAccompanying =
+	  vtkSmartPointer < vtkMatrix4x4 >::New();
+  pMatrix4x4DirectionsAccompanying->Identity();
+
+  if(m_pMatrix4x4Directions->Determinant() > 0.0)
+    {
+    m_pAxesWidget->GetAxesActor()->SetPosition(- m_dbGraphicScale / 2.0, -m_dbGraphicScale / 2.0, -m_dbGraphicScale / 2.0);
+	m_pAxesWidget->SetLabels("i", "j", "k");
+    m_pAxesWidget->SetColors(AxesWidget::m_arrdbColRed, AxesWidget::m_arrdbColGreen, AxesWidget::m_arrdbColBlue);
+    }
+  else
+    {
+	//m_pAxesWidget->GetAxesActor()->SetPosition(m_dbGraphicScale / 2.0, m_dbGraphicScale / 2.0, m_dbGraphicScale / 2.0);
+	
+	(*pMatrix4x4DirectionsAccompanying)[0][0] = -1.0;
+	(*pMatrix4x4DirectionsAccompanying)[1][1] = 0.0;
+	(*pMatrix4x4DirectionsAccompanying)[1][2] = -1.0;
+	(*pMatrix4x4DirectionsAccompanying)[2][1] = -1.0;
+	(*pMatrix4x4DirectionsAccompanying)[2][2] = 0.0;
+
+	changeOrientation3x3(m_pMatrix4x4Directions);
+	m_pAxesWidget->SetLabels("i", "k", "j");
+    m_pAxesWidget->SetColors(AxesWidget::m_arrdbColRed, AxesWidget::m_arrdbColBlue, AxesWidget::m_arrdbColGreen);
+    }
+
+  m_pAxesWidget->GetAxesActor()->SetUserMatrix(pMatrix4x4DirectionsAccompanying);
+
+  //m_pMatrix4x4Directions->DeepCopy(apMatrix4x4);
+  //widget->GetProp3D()->SetUserTransform(t);
+  vtkSmartPointer < vtkTransform > pTransform = vtkSmartPointer < vtkTransform >::New();
+  pTransform->SetMatrix(m_pMatrix4x4Directions);
+  vtkLinearTransform *pLinearTransform = m_pvtkAssembly->GetUserTransform();
+  if(pLinearTransform == 0)
+    m_pvtkAssembly->SetUserTransform(pTransform);
+  else
+	pLinearTransform->DeepCopy(pTransform);
+
+  m_pAxesWidget->SetLengths(2.0 * m_dbGraphicScale);
+  
+  int nI;
+  int nPlanesNr = getPlanesNr();
+  double dbDelta = m_dbGraphicScale / ((double)(nPlanesNr - 1));
+  for(nI = 0; nI < nPlanesNr; nI++)
+    {
+    //First, create the transparent planes
+    double arrdbOrigin[4] = {0.0, 0.0, 0.0, 1.0},
+      arrdbP1[4] = {0.0, 0.0, 0.0, 1.0},
+	  arrdbP2[4] = {0.0, 0.0, 0.0, 1.0};
+
+    arrdbOrigin[0] = - m_dbGraphicScale / 2.0;
+	arrdbOrigin[1] = - m_dbGraphicScale / 2.0;
+    arrdbOrigin[2] = dbDelta * nI - ((int)(((double)nPlanesNr) / 2.0))  * dbDelta;
+
+	arrdbP1[0] = m_dbGraphicScale / 2.0;
+	arrdbP1[1] = - m_dbGraphicScale / 2.0;
+	arrdbP1[2] = arrdbOrigin[2];
+
+	arrdbP2[0] = - m_dbGraphicScale / 2.0;
+	arrdbP2[1] = m_dbGraphicScale / 2.0;
+	arrdbP2[2] = arrdbOrigin[2];
+
+    //pMatrix4x4DirectionsAccompanying->MultiplyDoublePoint(arrdbOrigin);
+    //pMatrix4x4DirectionsAccompanying->MultiplyDoublePoint(arrdbP2);
+    //pMatrix4x4DirectionsAccompanying->MultiplyDoublePoint(arrdbP2);
+
+    Pairs_Plane_Pipe & ppp = m_arrpPairsPP_Axial[nI];
+    vtkSmartPointer < vtkPlaneSource > pPlaneSource = ppp.m_p_PlaneSource;
+    pPlaneSource->SetOrigin(arrdbOrigin);
+    pPlaneSource->SetPoint1(arrdbP1);
+    pPlaneSource->SetPoint2(arrdbP2);
+
+    //Second, insert the TubeFilter edge wires
+    double arrdbP3[4] = {0.0, 0.0, 0.0, 1.0};
+    arrdbP3[0] = arrdbP1[0];
+    arrdbP3[1] = arrdbP2[1];
+    arrdbP3[2] = arrdbOrigin[2];
+
+    vtkSmartPointer<vtkPoints> pPoints = vtkSmartPointer<vtkPoints>::New();
+    pPoints->InsertPoint(0, arrdbOrigin);
+    pPoints->InsertPoint(1, arrdbP1);
+
+    //Yes, the order is correct, this point is the 4th one
+    //in defining order on top of the Plane sorce!
+    pPoints->InsertPoint(2, arrdbP3);
+
+    pPoints->InsertPoint(3, arrdbP2);
+    pPoints->InsertPoint(4, arrdbOrigin);
+
+    vtkSmartPointer<vtkCellArray> pLines = vtkSmartPointer<vtkCellArray>::New();
+    pLines->InsertNextCell(5);
+    int nJ;
+    for (nJ = 0; nJ < 5; nJ++)
+      {
+      pLines->InsertCellPoint(nJ);
+      }
+
+    vtkSmartPointer<vtkPolyData> pPolyData = vtkSmartPointer<vtkPolyData>::New();
+    pPolyData->SetPoints(pPoints);
+    pPolyData->SetLines(pLines);
+
+    vtkSmartPointer < vtkTubeFilter > pTubeFilter = ppp.m_p_TubeFilter_WireFrame;
+    pTubeFilter->SetInputData(pPolyData);
+    pTubeFilter->SetNumberOfSides(100);
+    pTubeFilter->SetRadius(0.01 * m_dbGraphicScale);
+
+    //All right, now let's set the grid
+    for(nJ = 0; nJ < nPlanesNr; nJ++)
+      {
+      vtkSmartPointer< vtkLineSource > pLineSource =
+        vtkSmartPointer< vtkLineSource >::New();
+      pLineSource->SetPoint1(arrdbOrigin[0] + dbDelta * nJ, arrdbOrigin[1], arrdbOrigin[2]);
+      pLineSource->SetPoint2(arrdbOrigin[0] + dbDelta * nJ, arrdbP2[1], arrdbOrigin[2]);
+      vtkSmartPointer < vtkTubeFilter > pTubeFilter =
+        ppp.m_arrp_TubeFilter_PlanarGrid[nJ];
+      pTubeFilter->SetInputConnection(pLineSource->GetOutputPort());
+      pTubeFilter->SetNumberOfSides(100);
+      pTubeFilter->SetRadius(0.005 * m_dbGraphicScale);
+      }
+    }
+
+}
+
+void ScanningROI::setGraphicScale(double adbGraphicScale)
+{
+  AbstractScannerHelper::setGraphicScale(adbGraphicScale);
+  Update();
+}
+
+vtkSmartPointer < vtkMatrix4x4 > ScanningROI::getDirections()
+{
+  return(m_pMatrix4x4Directions);
+}
+
+void ScanningROI::setDirections(const vtkSmartPointer < vtkMatrix4x4 > & apMatrix4x4)
+{
+  m_pMatrix4x4Directions->DeepCopy(apMatrix4x4);
+}
+
+void ScanningROI::changeOrientation3x3(vtkSmartPointer < vtkMatrix4x4 > apvtkMatrix4x4)
+{
+  int nI, nJ;
+  for(nI = 0; nI < 3; nI++)
+    {
+    for(nJ = 0; nJ < 3; nJ++)
+  	  {
+  	  (*apvtkMatrix4x4)[nI][nJ] = - (*apvtkMatrix4x4)[nI][nJ];
+  	  }
+    }
+}
+
+void ScanningROI::SetVisibility(int anVisibility)
+{
+  for(size_t nI = 0; nI < m_arrpPairsPP_Axial.size(); nI++)
+  {
+  m_arrpPairsPP_Axial[nI].SetVisibility(anVisibility);
+  }
+  m_pAxesWidget->SetVisibility(anVisibility);
+}
diff --git a/GUI/Renderer/OrientationWidget/Reorient/ScanningROI.h b/GUI/Renderer/OrientationWidget/Reorient/ScanningROI.h
new file mode 100755
index 0000000..8fd117d
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Reorient/ScanningROI.h
@@ -0,0 +1,75 @@
+#ifndef SCANNING_ROI_H
+#define SCANNING_ROI_H
+
+#include <vector>
+
+template <class T> class vtkSmartPointer;
+class vtkAssembly;
+class vtkPlaneSource;
+class vtkCaptionActor2D;
+class vtkTubeFilter;
+
+class AxesWidget;
+class PolyDataAlgorithm2ActorPipe;
+
+#include "AbstractScannerHelper.h"
+
+struct Pairs_Plane_Pipe
+{
+  vtkSmartPointer < vtkPlaneSource > m_p_PlaneSource;
+  vtkSmartPointer < PolyDataAlgorithm2ActorPipe > m_p_PlaneSource_Pipe;
+
+  vtkSmartPointer < vtkTubeFilter >
+    m_p_TubeFilter_WireFrame;
+  vtkSmartPointer < PolyDataAlgorithm2ActorPipe >
+    m_p_TubeFilter_WireFrame_Pipe;
+
+  //TF stands for TubeFilter
+  std::vector < vtkSmartPointer < vtkTubeFilter > >
+    m_arrp_TubeFilter_PlanarGrid;
+  std::vector < vtkSmartPointer < PolyDataAlgorithm2ActorPipe > >
+    m_arrp_TubeFilter_PlanarGrid_Pipe;
+
+  Pairs_Plane_Pipe();
+
+  void init(int anGridResolution = 0);
+
+  void SetVisibility(int anVisibility);
+};
+
+class ScanningROI : public AbstractScannerHelper
+{
+
+  double m_arrdbSpacing[3];
+
+  std::vector < Pairs_Plane_Pipe > m_arrpPairsPP_Axial;
+
+  vtkSmartPointer < vtkMatrix4x4 > m_pMatrix4x4Directions;
+
+public:
+  vtkSmartPointer < AxesWidget > m_pAxesWidget;
+
+private:
+  ScanningROI();
+public:
+  static ScanningROI * New();
+  
+  void setPlanesNr(int anPlanesNr);
+  int getPlanesNr() const;
+
+  void setSpacing(double adbX, double adbY, double adbZ);
+  void setSpacing(double aarrdbXYZ[3]);
+
+  void Update();
+
+  virtual void setGraphicScale(double adbGraphicScale);
+
+  vtkSmartPointer < vtkMatrix4x4 > getDirections();
+  void setDirections(const vtkSmartPointer < vtkMatrix4x4 > & apMatrix4x4);
+
+  static void changeOrientation3x3(vtkSmartPointer < vtkMatrix4x4 > apvtkMatrix4x4);
+
+  void SetVisibility(int anVisibility);
+};
+
+#endif //SCANNING_ROI_H
diff --git a/GUI/Renderer/OrientationWidget/Test_OrientationWidget/CMakeLists.txt b/GUI/Renderer/OrientationWidget/Test_OrientationWidget/CMakeLists.txt
new file mode 100755
index 0000000..629ab9e
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_OrientationWidget/CMakeLists.txt
@@ -0,0 +1,78 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+PROJECT(OrientationWidgetGUI)
+
+FIND_PACKAGE(ITK REQUIRED)
+INCLUDE(${ITK_USE_FILE})
+
+# Find VTK.
+FIND_PACKAGE(VTK REQUIRED)
+INCLUDE(${VTK_USE_FILE})
+
+# use what QVTK built with
+SET(QT_QMAKE_EXECUTABLE ${VTK_QT_QMAKE_EXECUTABLE} CACHE FILEPATH "")
+SET(QT_MOC_EXECUTABLE ${VTK_QT_MOC_EXECUTABLE} CACHE FILEPATH "")
+SET(QT_UIC_EXECUTABLE ${VTK_QT_UIC_EXECUTABLE} CACHE FILEPATH "")
+SET(DESIRED_QT_VERSION ${VTK_DESIRED_QT_VERSION} CACHE FILEPATH "")
+FIND_PACKAGE(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED)
+IF(QT_USE_FILE)
+  INCLUDE(${QT_USE_FILE})
+ELSE(QT_USE_FILE)
+  SET(QT_LIBRARIES   ${QT_QT_LIBRARY})
+ENDIF(QT_USE_FILE)
+
+INCLUDE(${QT_USE_FILE})
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+
+# Look for OpenGL.
+FIND_PACKAGE(OpenGL REQUIRED)
+
+# Use the include path and library for Qt that is used by VTK.
+INCLUDE_DIRECTORIES(
+  ${QT_INCLUDE_DIR}
+  ${CONFIGURED_SOURCE_DIRECTORY}
+  ${OPENGL_INCLUDE_PATH}
+  ${QT_QTSCRIPT_INCLUDE_DIR}
+  ${QT_QTSCRIPTTOOLS_INCLUDE_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}
+  ${CMAKE_SOURCE_DIR}/../Reorient
+  ${CMAKE_SOURCE_DIR}/../../../Qt/View/
+  ${CMAKE_SOURCE_DIR}/../../../../Common
+)
+
+QT4_WRAP_UI(UI_SRCS OrientationWidgetGUI.ui)
+QT4_WRAP_CPP(MOC_SRCS OrientationWidgetGUI.h)
+SET(SRCS ${SRCS} ${MOC_SRCS}
+  main.cxx
+  OrientationWidget.h OrientationWidget.cxx
+  OrientationWidgetGUI.h OrientationWidgetGUI.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/AxesWidget.h ${CMAKE_SOURCE_DIR}/../Reorient/AxesWidget.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/AbstractScannerHelper.h ${CMAKE_SOURCE_DIR}/../Reorient/AbstractScannerHelper.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/PolyDataAlgorithm2ActorPipe.h ${CMAKE_SOURCE_DIR}/../Reorient/PolyDataAlgorithm2ActorPipe.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/ScannedHuman.h ${CMAKE_SOURCE_DIR}/../Reorient/ScannedHuman.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/ScanningROI.h ${CMAKE_SOURCE_DIR}/../Reorient/ScanningROI.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/ReorientProps.h ${CMAKE_SOURCE_DIR}/../Reorient/ReorientProps.cxx
+  ${CMAKE_SOURCE_DIR}/../../../Qt/View/QtAbstractOpenGLBox.h ${CMAKE_SOURCE_DIR}/../../../Qt/View/QtAbstractOpenGLBox.cxx
+  ${CMAKE_SOURCE_DIR}/../../../Qt/View/QtSimpleOpenGLBox.h ${CMAKE_SOURCE_DIR}/../../../Qt/View/QtSimpleOpenGLBox.cxx
+  ${CMAKE_SOURCE_DIR}/../../../../Common/SNAPCommon.h
+  #${CMAKE_SOURCE_DIR}/../../../Common/SNAPEvents.h
+)
+
+ADD_EXECUTABLE(OrientationWidgetGUI ${SRCS} ${UI_SRCS})
+
+TARGET_LINK_LIBRARIES( OrientationWidgetGUI
+  QVTK
+  ${QT_LIBRARIES}
+  ${QT_QTSCRIPT_LIBRARY}
+  ${QT_QTSCRIPTTOOLS_LIBRARY}
+  vtkRendering
+  vtkGraphics
+  vtkIO
+  vtkCommon
+  vtkVolumeRendering
+)
+
+
+
+
diff --git a/GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.cxx b/GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.cxx
new file mode 100755
index 0000000..9a9131f
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.cxx
@@ -0,0 +1,149 @@
+#include <string>
+
+#include <QMenu>
+#include <qstring.h>
+#include <QFileDialog>
+#include <QWheelEvent>
+
+#include <vtkCamera.h>
+#include <vtkRenderWindow.h>
+#include <vtkRendererCollection.h>
+
+
+#include <OrientationGraphicRenderer.h>
+#include <QtSimpleOpenGLBox.h>
+#include <ScanningROI.h>
+#include "OrientationWidgetGUI.h"
+
+
+using namespace std;
+
+
+OrientationWidgetGUI::OrientationWidgetGUI()
+{	
+
+  setupUi(this);
+  
+  m_pRAIRenderer = OrientationGraphicRenderer::New();
+  m_pQtSimpleOpenGLBox->SetRenderer(m_pRAIRenderer);
+
+  vtkSmartPointer < vtkMatrix4x4 > pMatrix = vtkSmartPointer < vtkMatrix4x4 >::New();
+  m_ReorientProps.GetDirections(pMatrix);
+
+  int nI, nJ;
+  for(nI = 0; nI < 4; nI++)
+  {
+	for(nJ = 0; nJ < 4; nJ++)
+    {
+	  double dbEquals = (*pMatrix)[nI][nJ];
+
+	  QTableWidgetItem* pItem= new QTableWidgetItem();
+	  pItem->setText(QString::number(dbEquals));
+	  m_pTableWidget->setItem(nI,nJ,pItem); 
+    }
+  }
+
+  connect(m_pTableWidget,SIGNAL( cellChanged (int, int) ), this, SLOT( slotReorient(int, int) ));
+
+  connect(m_pDoubleSpinBoxRotPhi,SIGNAL( valueChanged(double) ), this, SLOT( slotPhiThetaPsi(double) ));
+  connect(m_pDoubleSpinBoxRotTheta,SIGNAL( valueChanged(double) ), this, SLOT( slotPhiThetaPsi(double) ));
+  connect(m_pDoubleSpinBoxRotPsi,SIGNAL( valueChanged(double) ), this, SLOT( slotPhiThetaPsi(double) ));
+
+  connect(m_pRadioButtonInterpretNegativeOrientation3x3,SIGNAL( toggled(bool) ), this, SLOT( slotSelectNegativeOrientation(bool) ));
+  
+  vtkRenderWindow * pWin = m_pRAIRenderer->GetRenderWindow();
+  vtkRendererCollection * pRC = pWin->GetRenderers();
+  vtkRenderer * pRenderer = pRC->GetFirstRenderer();
+  vtkCamera * pCamera = pRenderer->GetActiveCamera();
+  pCamera->SetPosition(10.0, -10.0, 10.0);
+  pCamera->SetViewUp(0.0, -1.0, 0.0);
+
+}
+
+OrientationWidgetGUI::~OrientationWidgetGUI()
+{
+}
+
+vtkSmartPointer < vtkMatrix4x4 > OrientationWidgetGUI::getMtrx4x4GUI()
+{
+  vtkSmartPointer < vtkMatrix4x4 > pMatrix4x4 = vtkSmartPointer < vtkMatrix4x4 >::New();
+  int nI, nJ;
+  for(nI = 0; nI < 4; nI++)
+  {
+	for(nJ = 0; nJ < 4; nJ++)
+    {
+	  QTableWidgetItem* pItem = m_pTableWidget->item(nI, nJ);
+	  (*pMatrix4x4)[nI][nJ] = pItem->text().toDouble(); 
+    }
+  }
+  return(pMatrix4x4);
+}
+
+void OrientationWidgetGUI::slotReorient(int anDummyRow, int anDummyCol)
+{
+  vtkSmartPointer < vtkMatrix4x4 > pMatrix4x4 = getMtrx4x4GUI();
+  m_ReorientProps.Update(pMatrix4x4);
+}
+
+void OrientationWidgetGUI::slotPhiThetaPsi(double adbValue)
+{
+  disconnect(m_pTableWidget,SIGNAL( cellChanged (int, int) ), this, SLOT( slotReorient(int, int) ));
+
+  double dbPhi = m_pDoubleSpinBoxRotPhi->value();
+  double dbTheta = m_pDoubleSpinBoxRotTheta->value();
+  double dbPsi = m_pDoubleSpinBoxRotPsi->value();
+
+  double cosPhi = cos(dbPhi);
+  double sinPhi = sin(dbPhi);
+  double cosTheta = cos(dbTheta);
+  double sinTheta = sin(dbTheta);
+  double cosPsi = cos(dbPsi);
+  double sinPsi = sin(dbPsi);
+
+  //Formulas taken from http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions
+  vtkSmartPointer < vtkMatrix4x4 > pMatrix4x4 = vtkSmartPointer < vtkMatrix4x4 >::New();
+  (*pMatrix4x4)[0][0] = cosTheta  * cosPsi;
+  (*pMatrix4x4)[0][1] = cosPhi    * sinPsi + sinPhi * sinTheta * cosPsi;
+  (*pMatrix4x4)[0][2] = sinPhi    * sinPsi - cosPhi * sinTheta * cosPsi;
+
+  (*pMatrix4x4)[1][0] = -cosTheta * sinPsi;
+  (*pMatrix4x4)[1][1] =  cosPhi   * cosPsi - sinPhi * sinTheta * sinPsi;
+  (*pMatrix4x4)[1][2] =  sinPhi   * cosPsi + cosPhi * sinTheta * sinPsi;
+
+  (*pMatrix4x4)[2][0] = sinTheta;
+  (*pMatrix4x4)[2][1] = -sinPhi   * cosTheta;
+  (*pMatrix4x4)[2][2] = cosPhi    * cosTheta;
+
+  int nI, nJ;
+  for(nI = 0; nI < 4; nI++)
+  {
+	for(nJ = 0; nJ < 4; nJ++)
+    {
+	  QTableWidgetItem* pItem = m_pTableWidget->item(nI, nJ);
+	  pItem->setText(QString::number((*pMatrix4x4)[nI][nJ]));
+    }
+  }
+  pMatrix4x4->Transpose();
+  
+  bool bInterpretNegativeOrientation3x3 = m_pRadioButtonInterpretNegativeOrientation3x3->isChecked();
+  if(bInterpretNegativeOrientation3x3 == true)
+    {
+	ScanningROI::changeOrientation3x3(pMatrix4x4);
+    }
+  m_ReorientProps.Update(pMatrix4x4);
+
+  connect(m_pTableWidget,SIGNAL( cellChanged (int, int) ), this, SLOT( slotReorient(int, int) ));
+}
+
+void OrientationWidgetGUI::slotSelectNegativeOrientation(bool abInterpretNegativeOrientation3x3)
+{
+  vtkSmartPointer < vtkMatrix4x4 > pMatrix4x4 =
+	//vtkSmartPointer < vtkMatrix4x4 >::New();
+  getMtrx4x4GUI();
+  pMatrix4x4->Transpose();
+  if(abInterpretNegativeOrientation3x3 == true)
+    {
+	ScanningROI::changeOrientation3x3(pMatrix4x4);
+    }
+  m_ReorientProps.Update(pMatrix4x4);
+}
diff --git a/GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.h b/GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.h
new file mode 100755
index 0000000..c630415
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.h
@@ -0,0 +1,39 @@
+#ifndef ORIENTATION_WIDGET_GUI_H
+#define ORIENTATION_WIDGET_GUI_H
+
+#include <QMainWindow>
+
+
+#include "ui_OrientationWidgetGUI.h"
+
+class vtkRenderer;
+class vtkEventQtSlotConnect;
+class vtkObject;
+class vtkCommand;
+class vtkMatrix4x4;
+#include <vtkSmartPointer.h>
+
+class OrientationGraphicRenderer;
+#include "ReorientProps.h"
+
+class OrientationWidgetGUI : public QMainWindow, public Ui::MainWindow
+{
+
+  SmartPtr< OrientationGraphicRenderer > m_pRAIRenderer;
+
+  ReorientProps m_ReorientProps;
+
+  Q_OBJECT
+public:
+  OrientationWidgetGUI();
+  ~OrientationWidgetGUI();
+
+  vtkSmartPointer < vtkMatrix4x4 > getMtrx4x4GUI();
+
+public slots:
+  void slotReorient(int anDummyRow, int anDummyCol);
+  void slotPhiThetaPsi(double adbValue);
+  void slotSelectNegativeOrientation(bool abInterpretNegativeOrientation3x3);
+};
+
+#endif //ORIENTATION_WIDGET_GUI_H
diff --git a/GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.ui b/GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.ui
new file mode 100755
index 0000000..313c768
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_OrientationWidget/OrientationWidgetGUI.ui
@@ -0,0 +1,586 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>826</width>
+    <height>533</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="0">
+     <widget class="QFrame" name="frame">
+      <property name="frameShape">
+       <enum>QFrame::StyledPanel</enum>
+      </property>
+      <property name="frameShadow">
+       <enum>QFrame::Raised</enum>
+      </property>
+      <widget class="QFrame" name="frame_2">
+       <property name="geometry">
+        <rect>
+         <x>410</x>
+         <y>10</y>
+         <width>380</width>
+         <height>440</height>
+        </rect>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>380</width>
+         <height>440</height>
+        </size>
+       </property>
+       <property name="frameShape">
+        <enum>QFrame::StyledPanel</enum>
+       </property>
+       <property name="frameShadow">
+        <enum>QFrame::Raised</enum>
+       </property>
+       <widget class="QLabel" name="label">
+        <property name="geometry">
+         <rect>
+          <x>30</x>
+          <y>10</y>
+          <width>71</width>
+          <height>16</height>
+         </rect>
+        </property>
+        <property name="text">
+         <string>Translate</string>
+        </property>
+       </widget>
+       <widget class="QLabel" name="label_2">
+        <property name="geometry">
+         <rect>
+          <x>30</x>
+          <y>140</y>
+          <width>71</width>
+          <height>16</height>
+         </rect>
+        </property>
+        <property name="text">
+         <string>Directions</string>
+        </property>
+       </widget>
+       <widget class="QTableWidget" name="m_pTableWidget">
+        <property name="geometry">
+         <rect>
+          <x>30</x>
+          <y>160</y>
+          <width>301</width>
+          <height>201</height>
+         </rect>
+        </property>
+        <property name="toolTip">
+         <string/>
+        </property>
+        <property name="verticalScrollBarPolicy">
+         <enum>Qt::ScrollBarAlwaysOff</enum>
+        </property>
+        <property name="horizontalScrollBarPolicy">
+         <enum>Qt::ScrollBarAlwaysOff</enum>
+        </property>
+        <property name="showGrid">
+         <bool>true</bool>
+        </property>
+        <attribute name="horizontalHeaderVisible">
+         <bool>false</bool>
+        </attribute>
+        <attribute name="horizontalHeaderDefaultSectionSize">
+         <number>75</number>
+        </attribute>
+        <attribute name="horizontalHeaderHighlightSections">
+         <bool>false</bool>
+        </attribute>
+        <attribute name="horizontalHeaderMinimumSectionSize">
+         <number>75</number>
+        </attribute>
+        <attribute name="verticalHeaderVisible">
+         <bool>false</bool>
+        </attribute>
+        <attribute name="verticalHeaderDefaultSectionSize">
+         <number>50</number>
+        </attribute>
+        <attribute name="verticalHeaderHighlightSections">
+         <bool>false</bool>
+        </attribute>
+        <attribute name="verticalHeaderMinimumSectionSize">
+         <number>50</number>
+        </attribute>
+        <row>
+         <property name="text">
+          <string>New Row</string>
+         </property>
+        </row>
+        <row>
+         <property name="text">
+          <string>New Row</string>
+         </property>
+        </row>
+        <row>
+         <property name="text">
+          <string>New Row</string>
+         </property>
+        </row>
+        <row>
+         <property name="text">
+          <string>New Row</string>
+         </property>
+        </row>
+        <column>
+         <property name="text">
+          <string>New Column</string>
+         </property>
+        </column>
+        <column>
+         <property name="text">
+          <string>New Column</string>
+         </property>
+        </column>
+        <column>
+         <property name="text">
+          <string>New Column</string>
+         </property>
+        </column>
+        <column>
+         <property name="text">
+          <string>New Column</string>
+         </property>
+        </column>
+       </widget>
+       <widget class="QLabel" name="label_3">
+        <property name="geometry">
+         <rect>
+          <x>30</x>
+          <y>70</y>
+          <width>71</width>
+          <height>16</height>
+         </rect>
+        </property>
+        <property name="text">
+         <string>Spacing</string>
+        </property>
+       </widget>
+       <widget class="QFrame" name="frame_3">
+        <property name="enabled">
+         <bool>false</bool>
+        </property>
+        <property name="geometry">
+         <rect>
+          <x>30</x>
+          <y>30</y>
+          <width>301</width>
+          <height>40</height>
+         </rect>
+        </property>
+        <property name="frameShape">
+         <enum>QFrame::StyledPanel</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Raised</enum>
+        </property>
+        <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxTX">
+         <property name="geometry">
+          <rect>
+           <x>39</x>
+           <y>10</y>
+           <width>61</width>
+           <height>20</height>
+          </rect>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+         <property name="maximum">
+          <double>9999.989999999999782</double>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_4">
+         <property name="geometry">
+          <rect>
+           <x>20</x>
+           <y>10</y>
+           <width>16</width>
+           <height>16</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>X</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_5">
+         <property name="geometry">
+          <rect>
+           <x>120</x>
+           <y>10</y>
+           <width>16</width>
+           <height>16</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>Y</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_6">
+         <property name="geometry">
+          <rect>
+           <x>210</x>
+           <y>10</y>
+           <width>16</width>
+           <height>16</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>Z</string>
+         </property>
+        </widget>
+        <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxTY">
+         <property name="geometry">
+          <rect>
+           <x>134</x>
+           <y>10</y>
+           <width>61</width>
+           <height>20</height>
+          </rect>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+         <property name="maximum">
+          <double>9999.989999999999782</double>
+         </property>
+        </widget>
+        <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxTZ">
+         <property name="geometry">
+          <rect>
+           <x>230</x>
+           <y>10</y>
+           <width>61</width>
+           <height>20</height>
+          </rect>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+         <property name="maximum">
+          <double>9999.989999999999782</double>
+         </property>
+        </widget>
+       </widget>
+       <widget class="QFrame" name="frame_4">
+        <property name="enabled">
+         <bool>false</bool>
+        </property>
+        <property name="geometry">
+         <rect>
+          <x>30</x>
+          <y>90</y>
+          <width>301</width>
+          <height>40</height>
+         </rect>
+        </property>
+        <property name="frameShape">
+         <enum>QFrame::StyledPanel</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Raised</enum>
+        </property>
+        <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxSX">
+         <property name="geometry">
+          <rect>
+           <x>39</x>
+           <y>10</y>
+           <width>61</width>
+           <height>20</height>
+          </rect>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+         <property name="maximum">
+          <double>9999.989999999999782</double>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_10">
+         <property name="geometry">
+          <rect>
+           <x>20</x>
+           <y>10</y>
+           <width>16</width>
+           <height>16</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>X</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_11">
+         <property name="geometry">
+          <rect>
+           <x>120</x>
+           <y>10</y>
+           <width>16</width>
+           <height>16</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>Y</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_12">
+         <property name="geometry">
+          <rect>
+           <x>210</x>
+           <y>10</y>
+           <width>16</width>
+           <height>16</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>Z</string>
+         </property>
+        </widget>
+        <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxSY">
+         <property name="geometry">
+          <rect>
+           <x>134</x>
+           <y>10</y>
+           <width>61</width>
+           <height>20</height>
+          </rect>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+         <property name="maximum">
+          <double>9999.989999999999782</double>
+         </property>
+        </widget>
+        <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxSX_2">
+         <property name="geometry">
+          <rect>
+           <x>230</x>
+           <y>10</y>
+           <width>61</width>
+           <height>20</height>
+          </rect>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+         <property name="maximum">
+          <double>9999.989999999999782</double>
+         </property>
+        </widget>
+       </widget>
+       <widget class="QFrame" name="frame_5">
+        <property name="geometry">
+         <rect>
+          <x>30</x>
+          <y>390</y>
+          <width>301</width>
+          <height>40</height>
+         </rect>
+        </property>
+        <property name="frameShape">
+         <enum>QFrame::StyledPanel</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Raised</enum>
+        </property>
+        <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxRotPhi">
+         <property name="geometry">
+          <rect>
+           <x>40</x>
+           <y>10</y>
+           <width>61</width>
+           <height>20</height>
+          </rect>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+         <property name="minimum">
+          <double>-9999.989999999999782</double>
+         </property>
+         <property name="maximum">
+          <double>9999.989999999999782</double>
+         </property>
+         <property name="singleStep">
+          <double>0.010000000000000</double>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_13">
+         <property name="geometry">
+          <rect>
+           <x>20</x>
+           <y>10</y>
+           <width>16</width>
+           <height>16</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>Phi</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_14">
+         <property name="geometry">
+          <rect>
+           <x>105</x>
+           <y>10</y>
+           <width>31</width>
+           <height>20</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>Theta</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_15">
+         <property name="geometry">
+          <rect>
+           <x>210</x>
+           <y>10</y>
+           <width>16</width>
+           <height>16</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>Psi</string>
+         </property>
+        </widget>
+        <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxRotTheta">
+         <property name="geometry">
+          <rect>
+           <x>134</x>
+           <y>10</y>
+           <width>61</width>
+           <height>20</height>
+          </rect>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+         <property name="minimum">
+          <double>-9999.989999999999782</double>
+         </property>
+         <property name="maximum">
+          <double>9999.989999999999782</double>
+         </property>
+         <property name="singleStep">
+          <double>0.010000000000000</double>
+         </property>
+        </widget>
+        <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxRotPsi">
+         <property name="geometry">
+          <rect>
+           <x>230</x>
+           <y>10</y>
+           <width>61</width>
+           <height>20</height>
+          </rect>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+         <property name="minimum">
+          <double>-9999.989999999999782</double>
+         </property>
+         <property name="maximum">
+          <double>9999.989999999999782</double>
+         </property>
+         <property name="singleStep">
+          <double>0.010000000000000</double>
+         </property>
+        </widget>
+       </widget>
+       <widget class="QLabel" name="label_7">
+        <property name="geometry">
+         <rect>
+          <x>30</x>
+          <y>370</y>
+          <width>71</width>
+          <height>16</height>
+         </rect>
+        </property>
+        <property name="text">
+         <string>Rotations</string>
+        </property>
+       </widget>
+       <widget class="QRadioButton" name="m_pRadioButtonInterpretNegativeOrientation3x3">
+        <property name="geometry">
+         <rect>
+          <x>100</x>
+          <y>140</y>
+          <width>231</width>
+          <height>20</height>
+         </rect>
+        </property>
+        <property name="toolTip">
+         <string comment="This means in reality the first 3x3 elements will be treated as oposite sign values " extracomment="This means in reality the first 3x3 elements will be treated as oposite sign values "/>
+        </property>
+        <property name="statusTip">
+         <string/>
+        </property>
+        <property name="whatsThis">
+         <string comment="This means in reality the first 3x3 elements will be treated as negative values " extracomment="This means in reality the first 3x3 elements will be treated as negative values "/>
+        </property>
+        <property name="accessibleName">
+         <string/>
+        </property>
+        <property name="accessibleDescription">
+         <string/>
+        </property>
+        <property name="layoutDirection">
+         <enum>Qt::RightToLeft</enum>
+        </property>
+        <property name="text">
+         <string>Assign negative orientation 3x3</string>
+        </property>
+       </widget>
+      </widget>
+      <widget class="QtSimpleOpenGLBox" name="m_pQtSimpleOpenGLBox" native="true">
+       <property name="geometry">
+        <rect>
+         <x>9</x>
+         <y>19</y>
+         <width>391</width>
+         <height>431</height>
+        </rect>
+       </property>
+      </widget>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>826</width>
+     <height>22</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QtSimpleOpenGLBox</class>
+   <extends>QWidget</extends>
+   <header location="global">QtSimpleOpenGLBox.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Renderer/OrientationWidget/Test_OrientationWidget/main.cxx b/GUI/Renderer/OrientationWidget/Test_OrientationWidget/main.cxx
new file mode 100755
index 0000000..ed2d356
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_OrientationWidget/main.cxx
@@ -0,0 +1,27 @@
+#include <string>
+
+#include "qapplication.h"
+
+#include "OrientationWidgetGUI.h"
+
+#ifdef SNAP_DEBUG_EVENTS
+bool flag_snap_debug_events = false;
+#endif
+
+using namespace std;
+
+int main(int argc, char** argv)
+{
+
+	QApplication app(argc, argv);
+
+    OrientationWidgetGUI owGUI;
+
+    owGUI.show();
+
+	int nRetCode = app.exec();
+
+	return(nRetCode);
+
+}
+
diff --git a/GUI/Renderer/OrientationWidget/Test_ReorientGUI/CMakeLists.txt b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/CMakeLists.txt
new file mode 100755
index 0000000..c21ccc9
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/CMakeLists.txt
@@ -0,0 +1,57 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+PROJECT(ReorientGUI)
+
+# Find VTK.
+FIND_PACKAGE(VTK REQUIRED)
+INCLUDE(${VTK_USE_FILE})
+
+# use what QVTK built with
+SET(QT_QMAKE_EXECUTABLE ${VTK_QT_QMAKE_EXECUTABLE} CACHE FILEPATH "")
+SET(QT_MOC_EXECUTABLE ${VTK_QT_MOC_EXECUTABLE} CACHE FILEPATH "")
+SET(QT_UIC_EXECUTABLE ${VTK_QT_UIC_EXECUTABLE} CACHE FILEPATH "")
+SET(DESIRED_QT_VERSION ${VTK_DESIRED_QT_VERSION} CACHE FILEPATH "")
+FIND_PACKAGE(Qt)
+IF(QT_USE_FILE)
+  INCLUDE(${QT_USE_FILE})
+ELSE(QT_USE_FILE)
+  SET(QT_LIBRARIES   ${QT_QT_LIBRARY})
+ENDIF(QT_USE_FILE)
+
+# Use the include path and library for Qt that is used by VTK.
+INCLUDE_DIRECTORIES(
+  ${QT_INCLUDE_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}
+  ${CMAKE_SOURCE_DIR}/../Reorient
+)
+
+QT4_WRAP_UI(UI_SRCS ReorientGUI.ui)
+QT4_WRAP_CPP(MOC_SRCS ReorientGUI.h)
+SET(SRCS ${SRCS} ${MOC_SRCS}
+  main.cxx
+  Reorient.h Reorient.cxx
+  ReorientGUI.h ReorientGUI.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/AxesWidget.h ${CMAKE_SOURCE_DIR}/../Reorient/AxesWidget.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/AbstractScannerHelper.h ${CMAKE_SOURCE_DIR}/../Reorient/AbstractScannerHelper.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/PolyDataAlgorithm2ActorPipe.h ${CMAKE_SOURCE_DIR}/../Reorient/PolyDataAlgorithm2ActorPipe.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/ScannedHuman.h ${CMAKE_SOURCE_DIR}/../Reorient/ScannedHuman.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/ScanningROI.h ${CMAKE_SOURCE_DIR}/../Reorient/ScanningROI.cxx
+  ${CMAKE_SOURCE_DIR}/../Reorient/ReorientProps.h ${CMAKE_SOURCE_DIR}/../Reorient/ReorientProps.cxx
+)
+
+ADD_EXECUTABLE(ReorientGUI ${SRCS} ${UI_SRCS})
+
+TARGET_LINK_LIBRARIES( ReorientGUI
+  QVTK
+  ${QT_LIBRARIES}
+  vtkRendering
+  vtkGraphics
+  vtkIO
+  vtkCommon
+  vtkVolumeRendering
+)
+
+
+
+
diff --git a/GUI/Renderer/OrientationWidget/Test_ReorientGUI/Reorient.cxx b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/Reorient.cxx
new file mode 100755
index 0000000..1995712
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/Reorient.cxx
@@ -0,0 +1,65 @@
+#include "qvtkwidget.h"
+
+#include "vtkCamera.h"
+#include "vtkRenderWindow.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkRenderer.h"
+#include "vtkWindowToImageFilter.h"
+#include "vtkBMPWriter.h"
+#include "vtkTextProperty.h"
+#include "vtkCubeAxesActor2D.h"
+
+#include "ScanningROI.h"
+#include "Reorient.h"
+
+Reorient::Reorient()
+{
+
+  m_pRenderer = vtkSmartPointer < vtkRenderer >::New();
+  //m_pRenderer->TwoSidedLightingOn();
+  m_pRenWin = vtkSmartPointer < vtkRenderWindow >::New();
+  m_pRenWin->SetSize(200, 500);
+  m_pRenWin->AddRenderer(m_pRenderer);
+
+  Connect2Renderer(m_pRenderer);
+
+  vtkCamera * pCamera = m_pRenderer->GetActiveCamera();
+  pCamera->SetPosition(10.0, -10.0, 10.0);
+  pCamera->SetViewUp(0.0, -1.0, 0.0);
+
+  Connect2Renderer(m_pRenderer);
+}
+
+Reorient::~Reorient()
+{
+}
+
+void Reorient::setInteractor(vtkRenderWindowInteractor * apIren)
+{
+  m_pIren = apIren;
+}
+
+void Reorient::updateRenderer() 
+{
+
+  m_pRenderer->ResetCamera();
+  m_pRenWin->Render();
+
+}
+
+vtkRenderer * Reorient::GetRenderer()
+{
+  return(m_pRenderer);
+}
+
+vtkRenderWindow * Reorient::GetRenderWindow()
+{
+  return(m_pRenWin);
+}
+
+void Reorient::Update(const vtkSmartPointer < vtkMatrix4x4 > apMatrix4x4)
+{
+  ReorientProps::Update(apMatrix4x4);
+
+  m_pRenWin->Render();
+}
diff --git a/GUI/Renderer/OrientationWidget/Test_ReorientGUI/Reorient.h b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/Reorient.h
new file mode 100755
index 0000000..e1a7d06
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/Reorient.h
@@ -0,0 +1,35 @@
+#ifndef REORIENT_H
+#define REORIENT_H
+
+#include <vtkSmartPointer.h>
+#include <vtkMatrix4x4.h>
+
+//#include "AxesWidget.h"
+
+//#include "ScannedHuman.h"
+//#include "ScanningROI.h"
+#include "ReorientProps.h"
+
+class Reorient : public ReorientProps
+{
+  vtkSmartPointer < vtkRenderer > m_pRenderer;
+  vtkSmartPointer < vtkRenderWindow > m_pRenWin;
+  vtkRenderWindowInteractor * m_pIren;
+  
+  void updateRenderer();
+  
+public:
+
+  Reorient();
+  ~Reorient();
+  
+  void setInteractor(vtkRenderWindowInteractor * apIren);
+  
+  vtkRenderer * GetRenderer();
+  vtkRenderWindow * GetRenderWindow();
+
+  virtual void Update(const vtkSmartPointer < vtkMatrix4x4 > apMatrix4x4);
+};
+
+
+#endif //REORIENT_H
diff --git a/GUI/Renderer/OrientationWidget/Test_ReorientGUI/ReorientGUI.cxx b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/ReorientGUI.cxx
new file mode 100755
index 0000000..13a2553
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/ReorientGUI.cxx
@@ -0,0 +1,136 @@
+#include <string>
+
+#include <QMenu>
+#include <qstring.h>
+#include <QFileDialog>
+#include <QWheelEvent>
+
+
+#include "ReorientGUI.h"
+#include "Reorient.h"
+#include "ScanningROI.h"
+
+using namespace std;
+
+
+ReorientGUI::ReorientGUI()
+{	
+
+  setupUi(this);
+  
+  m_pQVTKWidget->SetRenderWindow(m_Reorient.GetRenderWindow());
+  m_Reorient.setInteractor(m_pQVTKWidget->GetInteractor());
+  
+  vtkSmartPointer < vtkMatrix4x4 > pMatrix = vtkSmartPointer < vtkMatrix4x4 >::New();
+  m_Reorient.GetDirections(pMatrix);
+
+  int nI, nJ;
+  for(nI = 0; nI < 4; nI++)
+  {
+	for(nJ = 0; nJ < 4; nJ++)
+    {
+	  double dbEquals = (*pMatrix)[nI][nJ];
+
+	  QTableWidgetItem* pItem= new QTableWidgetItem();
+	  pItem->setText(QString::number(dbEquals));
+	  m_pTableWidget->setItem(nI,nJ,pItem); 
+    }
+  }
+
+  connect(m_pTableWidget,SIGNAL( cellChanged (int, int) ), this, SLOT( slotReorient(int, int) ));
+
+  connect(m_pDoubleSpinBoxRotPhi,SIGNAL( valueChanged(double) ), this, SLOT( slotPhiThetaPsi(double) ));
+  connect(m_pDoubleSpinBoxRotTheta,SIGNAL( valueChanged(double) ), this, SLOT( slotPhiThetaPsi(double) ));
+  connect(m_pDoubleSpinBoxRotPsi,SIGNAL( valueChanged(double) ), this, SLOT( slotPhiThetaPsi(double) ));
+
+  connect(m_pRadioButtonInterpretNegativeOrientation3x3,SIGNAL( toggled(bool) ), this, SLOT( slotSelectNegativeOrientation(bool) ));
+  
+}
+
+ReorientGUI::~ReorientGUI()
+{
+}
+
+vtkSmartPointer < vtkMatrix4x4 > ReorientGUI::getMtrx4x4GUI()
+{
+  vtkSmartPointer < vtkMatrix4x4 > pMatrix4x4 = vtkSmartPointer < vtkMatrix4x4 >::New();
+  int nI, nJ;
+  for(nI = 0; nI < 4; nI++)
+  {
+	for(nJ = 0; nJ < 4; nJ++)
+    {
+	  QTableWidgetItem* pItem = m_pTableWidget->item(nI, nJ);
+	  (*pMatrix4x4)[nI][nJ] = pItem->text().toDouble(); 
+    }
+  }
+  return(pMatrix4x4);
+}
+
+void ReorientGUI::slotReorient(int anDummyRow, int anDummyCol)
+{
+  vtkSmartPointer < vtkMatrix4x4 > pMatrix4x4 = getMtrx4x4GUI();
+  m_Reorient.Update(pMatrix4x4);
+}
+
+void ReorientGUI::slotPhiThetaPsi(double adbValue)
+{
+  disconnect(m_pTableWidget,SIGNAL( cellChanged (int, int) ), this, SLOT( slotReorient(int, int) ));
+
+  double dbPhi = m_pDoubleSpinBoxRotPhi->value();
+  double dbTheta = m_pDoubleSpinBoxRotTheta->value();
+  double dbPsi = m_pDoubleSpinBoxRotPsi->value();
+
+  double cosPhi = cos(dbPhi);
+  double sinPhi = sin(dbPhi);
+  double cosTheta = cos(dbTheta);
+  double sinTheta = sin(dbTheta);
+  double cosPsi = cos(dbPsi);
+  double sinPsi = sin(dbPsi);
+
+  //Formulas taken from http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions
+  vtkSmartPointer < vtkMatrix4x4 > pMatrix4x4 = vtkSmartPointer < vtkMatrix4x4 >::New();
+  (*pMatrix4x4)[0][0] = cosTheta  * cosPsi;
+  (*pMatrix4x4)[0][1] = cosPhi    * sinPsi + sinPhi * sinTheta * cosPsi;
+  (*pMatrix4x4)[0][2] = sinPhi    * sinPsi - cosPhi * sinTheta * cosPsi;
+
+  (*pMatrix4x4)[1][0] = -cosTheta * sinPsi;
+  (*pMatrix4x4)[1][1] =  cosPhi   * cosPsi - sinPhi * sinTheta * sinPsi;
+  (*pMatrix4x4)[1][2] =  sinPhi   * cosPsi + cosPhi * sinTheta * sinPsi;
+
+  (*pMatrix4x4)[2][0] = sinTheta;
+  (*pMatrix4x4)[2][1] = -sinPhi   * cosTheta;
+  (*pMatrix4x4)[2][2] = cosPhi    * cosTheta;
+
+  int nI, nJ;
+  for(nI = 0; nI < 4; nI++)
+  {
+	for(nJ = 0; nJ < 4; nJ++)
+    {
+	  QTableWidgetItem* pItem = m_pTableWidget->item(nI, nJ);
+	  pItem->setText(QString::number((*pMatrix4x4)[nI][nJ]));
+    }
+  }
+  pMatrix4x4->Transpose();
+  
+  bool bInterpretNegativeOrientation3x3 = m_pRadioButtonInterpretNegativeOrientation3x3->isChecked();
+  if(bInterpretNegativeOrientation3x3 == true)
+    {
+	ScanningROI::changeOrientation3x3(pMatrix4x4);
+    }
+  m_Reorient.Update(pMatrix4x4);
+
+  connect(m_pTableWidget,SIGNAL( cellChanged (int, int) ), this, SLOT( slotReorient(int, int) ));
+}
+
+void ReorientGUI::slotSelectNegativeOrientation(bool abInterpretNegativeOrientation3x3)
+{
+  vtkSmartPointer < vtkMatrix4x4 > pMatrix4x4 =
+	//vtkSmartPointer < vtkMatrix4x4 >::New();
+  getMtrx4x4GUI();
+  pMatrix4x4->Transpose();
+  if(abInterpretNegativeOrientation3x3 == true)
+    {
+	ScanningROI::changeOrientation3x3(pMatrix4x4);
+    }
+  m_Reorient.Update(pMatrix4x4);
+}
diff --git a/GUI/Renderer/OrientationWidget/Test_ReorientGUI/ReorientGUI.h b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/ReorientGUI.h
new file mode 100755
index 0000000..ccf188d
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/ReorientGUI.h
@@ -0,0 +1,34 @@
+#ifndef REORIENT_GUI_H
+#define REORIENT_GUI_H
+
+#include <QMainWindow>
+
+
+#include "ui_ReorientGUI.h"
+
+#include "Reorient.h"
+
+class vtkRenderer;
+class vtkEventQtSlotConnect;
+class vtkObject;
+class vtkCommand;
+
+class ReorientGUI : public QMainWindow, public Ui::MainWindow
+{
+
+  Reorient m_Reorient;
+
+  Q_OBJECT
+public:
+  ReorientGUI();
+  ~ReorientGUI();
+
+  vtkSmartPointer < vtkMatrix4x4 > getMtrx4x4GUI();
+
+public slots:
+  void slotReorient(int anDummyRow, int anDummyCol);
+  void slotPhiThetaPsi(double adbValue);
+  void slotSelectNegativeOrientation(bool abInterpretNegativeOrientation3x3);
+};
+
+#endif //REORIENT_GUI_H
\ No newline at end of file
diff --git a/GUI/Renderer/OrientationWidget/Test_ReorientGUI/ReorientGUI.ui b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/ReorientGUI.ui
new file mode 100755
index 0000000..6fca93c
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/ReorientGUI.ui
@@ -0,0 +1,582 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>826</width>
+    <height>533</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="0">
+     <widget class="QFrame" name="frame">
+      <property name="frameShape">
+       <enum>QFrame::StyledPanel</enum>
+      </property>
+      <property name="frameShadow">
+       <enum>QFrame::Raised</enum>
+      </property>
+      <layout class="QGridLayout" name="gridLayout_2">
+       <item row="0" column="0">
+        <widget class="QVTKWidget" name="m_pQVTKWidget" native="true">
+         <property name="minimumSize">
+          <size>
+           <width>380</width>
+           <height>440</height>
+          </size>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1">
+        <widget class="QFrame" name="frame_2">
+         <property name="minimumSize">
+          <size>
+           <width>380</width>
+           <height>440</height>
+          </size>
+         </property>
+         <property name="frameShape">
+          <enum>QFrame::StyledPanel</enum>
+         </property>
+         <property name="frameShadow">
+          <enum>QFrame::Raised</enum>
+         </property>
+         <widget class="QLabel" name="label">
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>10</y>
+            <width>71</width>
+            <height>16</height>
+           </rect>
+          </property>
+          <property name="text">
+           <string>Translate</string>
+          </property>
+         </widget>
+         <widget class="QLabel" name="label_2">
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>140</y>
+            <width>71</width>
+            <height>16</height>
+           </rect>
+          </property>
+          <property name="text">
+           <string>Directions</string>
+          </property>
+         </widget>
+         <widget class="QTableWidget" name="m_pTableWidget">
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>160</y>
+            <width>301</width>
+            <height>201</height>
+           </rect>
+          </property>
+          <property name="toolTip">
+           <string/>
+          </property>
+          <property name="verticalScrollBarPolicy">
+           <enum>Qt::ScrollBarAlwaysOff</enum>
+          </property>
+          <property name="horizontalScrollBarPolicy">
+           <enum>Qt::ScrollBarAlwaysOff</enum>
+          </property>
+          <property name="showGrid">
+           <bool>true</bool>
+          </property>
+          <attribute name="horizontalHeaderVisible">
+           <bool>false</bool>
+          </attribute>
+          <attribute name="horizontalHeaderDefaultSectionSize">
+           <number>75</number>
+          </attribute>
+          <attribute name="horizontalHeaderHighlightSections">
+           <bool>false</bool>
+          </attribute>
+          <attribute name="horizontalHeaderMinimumSectionSize">
+           <number>75</number>
+          </attribute>
+          <attribute name="verticalHeaderVisible">
+           <bool>false</bool>
+          </attribute>
+          <attribute name="verticalHeaderDefaultSectionSize">
+           <number>50</number>
+          </attribute>
+          <attribute name="verticalHeaderHighlightSections">
+           <bool>false</bool>
+          </attribute>
+          <attribute name="verticalHeaderMinimumSectionSize">
+           <number>50</number>
+          </attribute>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <row>
+           <property name="text">
+            <string>New Row</string>
+           </property>
+          </row>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>New Column</string>
+           </property>
+          </column>
+         </widget>
+         <widget class="QLabel" name="label_3">
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>70</y>
+            <width>71</width>
+            <height>16</height>
+           </rect>
+          </property>
+          <property name="text">
+           <string>Spacing</string>
+          </property>
+         </widget>
+         <widget class="QFrame" name="frame_3">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>30</y>
+            <width>301</width>
+            <height>40</height>
+           </rect>
+          </property>
+          <property name="frameShape">
+           <enum>QFrame::StyledPanel</enum>
+          </property>
+          <property name="frameShadow">
+           <enum>QFrame::Raised</enum>
+          </property>
+          <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxTX">
+           <property name="geometry">
+            <rect>
+             <x>39</x>
+             <y>10</y>
+             <width>61</width>
+             <height>20</height>
+            </rect>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+           <property name="maximum">
+            <double>9999.989999999999782</double>
+           </property>
+          </widget>
+          <widget class="QLabel" name="label_4">
+           <property name="geometry">
+            <rect>
+             <x>20</x>
+             <y>10</y>
+             <width>16</width>
+             <height>16</height>
+            </rect>
+           </property>
+           <property name="text">
+            <string>X</string>
+           </property>
+          </widget>
+          <widget class="QLabel" name="label_5">
+           <property name="geometry">
+            <rect>
+             <x>120</x>
+             <y>10</y>
+             <width>16</width>
+             <height>16</height>
+            </rect>
+           </property>
+           <property name="text">
+            <string>Y</string>
+           </property>
+          </widget>
+          <widget class="QLabel" name="label_6">
+           <property name="geometry">
+            <rect>
+             <x>210</x>
+             <y>10</y>
+             <width>16</width>
+             <height>16</height>
+            </rect>
+           </property>
+           <property name="text">
+            <string>Z</string>
+           </property>
+          </widget>
+          <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxTY">
+           <property name="geometry">
+            <rect>
+             <x>134</x>
+             <y>10</y>
+             <width>61</width>
+             <height>20</height>
+            </rect>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+           <property name="maximum">
+            <double>9999.989999999999782</double>
+           </property>
+          </widget>
+          <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxTZ">
+           <property name="geometry">
+            <rect>
+             <x>230</x>
+             <y>10</y>
+             <width>61</width>
+             <height>20</height>
+            </rect>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+           <property name="maximum">
+            <double>9999.989999999999782</double>
+           </property>
+          </widget>
+         </widget>
+         <widget class="QFrame" name="frame_4">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>90</y>
+            <width>301</width>
+            <height>40</height>
+           </rect>
+          </property>
+          <property name="frameShape">
+           <enum>QFrame::StyledPanel</enum>
+          </property>
+          <property name="frameShadow">
+           <enum>QFrame::Raised</enum>
+          </property>
+          <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxSX">
+           <property name="geometry">
+            <rect>
+             <x>39</x>
+             <y>10</y>
+             <width>61</width>
+             <height>20</height>
+            </rect>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+           <property name="maximum">
+            <double>9999.989999999999782</double>
+           </property>
+          </widget>
+          <widget class="QLabel" name="label_10">
+           <property name="geometry">
+            <rect>
+             <x>20</x>
+             <y>10</y>
+             <width>16</width>
+             <height>16</height>
+            </rect>
+           </property>
+           <property name="text">
+            <string>X</string>
+           </property>
+          </widget>
+          <widget class="QLabel" name="label_11">
+           <property name="geometry">
+            <rect>
+             <x>120</x>
+             <y>10</y>
+             <width>16</width>
+             <height>16</height>
+            </rect>
+           </property>
+           <property name="text">
+            <string>Y</string>
+           </property>
+          </widget>
+          <widget class="QLabel" name="label_12">
+           <property name="geometry">
+            <rect>
+             <x>210</x>
+             <y>10</y>
+             <width>16</width>
+             <height>16</height>
+            </rect>
+           </property>
+           <property name="text">
+            <string>Z</string>
+           </property>
+          </widget>
+          <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxSY">
+           <property name="geometry">
+            <rect>
+             <x>134</x>
+             <y>10</y>
+             <width>61</width>
+             <height>20</height>
+            </rect>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+           <property name="maximum">
+            <double>9999.989999999999782</double>
+           </property>
+          </widget>
+          <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxSX_2">
+           <property name="geometry">
+            <rect>
+             <x>230</x>
+             <y>10</y>
+             <width>61</width>
+             <height>20</height>
+            </rect>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+           <property name="maximum">
+            <double>9999.989999999999782</double>
+           </property>
+          </widget>
+         </widget>
+         <widget class="QFrame" name="frame_5">
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>390</y>
+            <width>301</width>
+            <height>40</height>
+           </rect>
+          </property>
+          <property name="frameShape">
+           <enum>QFrame::StyledPanel</enum>
+          </property>
+          <property name="frameShadow">
+           <enum>QFrame::Raised</enum>
+          </property>
+          <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxRotPhi">
+           <property name="geometry">
+            <rect>
+             <x>40</x>
+             <y>10</y>
+             <width>61</width>
+             <height>20</height>
+            </rect>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+           <property name="minimum">
+            <double>-9999.989999999999782</double>
+           </property>
+           <property name="maximum">
+            <double>9999.989999999999782</double>
+           </property>
+           <property name="singleStep">
+            <double>0.010000000000000</double>
+           </property>
+          </widget>
+          <widget class="QLabel" name="label_13">
+           <property name="geometry">
+            <rect>
+             <x>20</x>
+             <y>10</y>
+             <width>16</width>
+             <height>16</height>
+            </rect>
+           </property>
+           <property name="text">
+            <string>Phi</string>
+           </property>
+          </widget>
+          <widget class="QLabel" name="label_14">
+           <property name="geometry">
+            <rect>
+             <x>105</x>
+             <y>10</y>
+             <width>31</width>
+             <height>20</height>
+            </rect>
+           </property>
+           <property name="text">
+            <string>Theta</string>
+           </property>
+          </widget>
+          <widget class="QLabel" name="label_15">
+           <property name="geometry">
+            <rect>
+             <x>210</x>
+             <y>10</y>
+             <width>16</width>
+             <height>16</height>
+            </rect>
+           </property>
+           <property name="text">
+            <string>Psi</string>
+           </property>
+          </widget>
+          <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxRotTheta">
+           <property name="geometry">
+            <rect>
+             <x>134</x>
+             <y>10</y>
+             <width>61</width>
+             <height>20</height>
+            </rect>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+           <property name="minimum">
+            <double>-9999.989999999999782</double>
+           </property>
+           <property name="maximum">
+            <double>9999.989999999999782</double>
+           </property>
+           <property name="singleStep">
+            <double>0.010000000000000</double>
+           </property>
+          </widget>
+          <widget class="QDoubleSpinBox" name="m_pDoubleSpinBoxRotPsi">
+           <property name="geometry">
+            <rect>
+             <x>230</x>
+             <y>10</y>
+             <width>61</width>
+             <height>20</height>
+            </rect>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+           <property name="minimum">
+            <double>-9999.989999999999782</double>
+           </property>
+           <property name="maximum">
+            <double>9999.989999999999782</double>
+           </property>
+           <property name="singleStep">
+            <double>0.010000000000000</double>
+           </property>
+          </widget>
+         </widget>
+         <widget class="QLabel" name="label_7">
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>370</y>
+            <width>71</width>
+            <height>16</height>
+           </rect>
+          </property>
+          <property name="text">
+           <string>Rotations</string>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="m_pRadioButtonInterpretNegativeOrientation3x3">
+          <property name="geometry">
+           <rect>
+            <x>100</x>
+            <y>140</y>
+            <width>231</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="toolTip">
+           <string comment="This means in reality the first 3x3 elements will be treated as oposite sign values " extracomment="This means in reality the first 3x3 elements will be treated as oposite sign values "/>
+          </property>
+          <property name="statusTip">
+           <string/>
+          </property>
+          <property name="whatsThis">
+           <string comment="This means in reality the first 3x3 elements will be treated as negative values " extracomment="This means in reality the first 3x3 elements will be treated as negative values "/>
+          </property>
+          <property name="accessibleName">
+           <string/>
+          </property>
+          <property name="accessibleDescription">
+           <string/>
+          </property>
+          <property name="layoutDirection">
+           <enum>Qt::RightToLeft</enum>
+          </property>
+          <property name="text">
+           <string>Assign negative orientation 3x3</string>
+          </property>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>826</width>
+     <height>22</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QVTKWidget</class>
+   <extends>QWidget</extends>
+   <header location="global">qvtkwidget.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/GUI/Renderer/OrientationWidget/Test_ReorientGUI/main.cxx b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/main.cxx
new file mode 100755
index 0000000..22fac19
--- /dev/null
+++ b/GUI/Renderer/OrientationWidget/Test_ReorientGUI/main.cxx
@@ -0,0 +1,23 @@
+#include <string>
+
+#include "qapplication.h"
+
+#include "ReorientGUI.h"
+
+using namespace std;
+
+int main(int argc, char** argv)
+{
+
+	QApplication app(argc, argv);
+
+	ReorientGUI reorientGUI;
+
+	reorientGUI.show();
+
+	int nRetCode = app.exec();
+
+	return(nRetCode);
+
+}
+
diff --git a/GUI/Renderer/PaintbrushRenderer.cxx b/GUI/Renderer/PaintbrushRenderer.cxx
new file mode 100644
index 0000000..d4dde26
--- /dev/null
+++ b/GUI/Renderer/PaintbrushRenderer.cxx
@@ -0,0 +1,124 @@
+#include "PaintbrushRenderer.h"
+#include "PaintbrushModel.h"
+#include "IRISApplication.h"
+#include "GlobalState.h"
+#include "SNAPAppearanceSettings.h"
+#include "GlobalUIModel.h"
+#include "SNAPOpenGL.h"
+
+PaintbrushRenderer::PaintbrushRenderer()
+{
+}
+
+void PaintbrushRenderer::BuildBrush()
+{
+  // Get the current properties
+  GlobalState *gs = m_Model->GetParent()->GetDriver()->GetGlobalState();
+  PaintbrushSettings ps = gs->GetPaintbrushSettings();
+
+  // This is a simple 2D marching algorithm. At any given state of the
+  // marching, there is a 'tail' and a 'head' of an arrow. To the right
+  // of the arrow is a voxel that's inside the brush and to the left a
+  // voxel that's outside. Depending on the two voxels that are
+  // ahead of the arrow to the left and right (in in, in out, out out)
+  // at the next step the arrow turns right, continues straight or turns
+  // left. This goes on until convergence
+
+  // Initialize the marching. This requires constructing the first arrow
+  // and marching it to the left until it is between out and in voxels.
+  // If the brush has even diameter, the arrow is from (0,0) to (1,0). If
+  // the brush has odd diameter (center at voxel center) then the arrow
+  // is from (-0.5, -0.5) to (-0.5, 0.5)
+  Vector2d xTail, xHead;
+  if(fmod(ps.radius,1.0) == 0)
+    { xTail = Vector2d(0.0, 0.0); xHead = Vector2d(0.0, 1.0); }
+  else
+    { xTail = Vector2d(-0.5, -0.5); xHead = Vector2d(-0.5, 0.5); }
+
+  // Shift the arrow to the left until it is in position
+
+  while(m_Model->TestInside(Vector2d(xTail(0) - 0.5, xTail(1) + 0.5), ps))
+    { xTail(0) -= 1.0; xHead(0) -= 1.0; }
+
+  // Record the starting point, which is the current tail. Once the head
+  // returns to the starting point, the loop is done
+  Vector2d xStart = xTail;
+
+  // Do the loop
+  m_Walk.clear();
+  size_t n = 0;
+  while((xHead - xStart).squared_magnitude() > 0.01 && (++n) < 10000)
+    {
+    // Add the current head to the loop
+    m_Walk.push_back(xHead);
+
+    // Check the voxels ahead to the right and left
+    Vector2d xStep = xHead - xTail;
+    Vector2d xLeft(-xStep(1), xStep(0));
+    Vector2d xRight(xStep(1), -xStep(0));
+    bool il = m_Model->TestInside(xHead + 0.5 * (xStep + xLeft),ps);
+    bool ir = m_Model->TestInside(xHead + 0.5 * (xStep + xRight),ps);
+
+    // Update the tail
+    xTail = xHead;
+
+    // Decide which way to go
+    if(il && ir)
+      xHead += xLeft;
+    else if(!il && ir)
+      xHead += xStep;
+    else if(!il && !ir)
+      xHead += xRight;
+    else
+      assert(0);
+    }
+
+  // Add the last vertex
+  m_Walk.push_back(xStart);
+}
+
+
+
+void PaintbrushRenderer::paintGL()
+{
+  // Check if the mouse is inside
+  if(!m_Model->IsMouseInside())
+    return;
+
+  // Paint all the edges in the paintbrush definition
+  SNAPAppearanceSettings *as =
+      m_Model->GetParent()->GetParentUI()->GetAppearanceSettings();
+  const OpenGLAppearanceElement *elt =
+    as->GetUIElement(SNAPAppearanceSettings::PAINTBRUSH_OUTLINE);
+
+  // Build the mask edges
+  BuildBrush();
+
+  // Set line properties
+  glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
+
+  // Apply the line properties
+  glColor3dv(elt->GetNormalColor().data_block());
+  elt->ApplyLineSettings();
+
+  // Get the brush position
+  Vector3f xPos = m_Model->GetCenterOfPaintbrushInSliceSpace();
+
+  // Refit matrix so that the lines are centered on the current pixel
+  glPushMatrix();
+  glTranslated( xPos(0), xPos(1), 0.0 );
+
+  // Draw the lines around the point
+  glBegin(GL_LINE_LOOP);
+  for(std::list<Vector2d>::iterator it = m_Walk.begin(); it != m_Walk.end(); ++it)
+    glVertex2d((*it)(0), (*it)(1));
+  glEnd();
+
+  // Pop the matrix
+  glPopMatrix();
+
+  // Pop the attributes
+  glPopAttrib();
+
+
+}
diff --git a/GUI/Renderer/PaintbrushRenderer.h b/GUI/Renderer/PaintbrushRenderer.h
new file mode 100644
index 0000000..abf5d0f
--- /dev/null
+++ b/GUI/Renderer/PaintbrushRenderer.h
@@ -0,0 +1,31 @@
+#ifndef PAINTBRUSHRENDERER_H
+#define PAINTBRUSHRENDERER_H
+
+#include "GenericSliceRenderer.h"
+
+class PaintbrushModel;
+
+class PaintbrushRenderer : public SliceRendererDelegate
+{
+public:
+
+  irisITKObjectMacro(PaintbrushRenderer, SliceRendererDelegate)
+
+  irisGetSetMacro(Model, PaintbrushModel *)
+
+  void paintGL();
+
+protected:
+
+
+  PaintbrushRenderer();
+
+  PaintbrushModel *m_Model;
+
+  void BuildBrush();
+
+  // Representation of the brush
+  std::list<Vector2d> m_Walk;
+};
+
+#endif // PAINTBRUSHRENDERER_H
diff --git a/GUI/Renderer/PolygonDrawingRenderer.cxx b/GUI/Renderer/PolygonDrawingRenderer.cxx
new file mode 100644
index 0000000..9cf65da
--- /dev/null
+++ b/GUI/Renderer/PolygonDrawingRenderer.cxx
@@ -0,0 +1,220 @@
+#include "PolygonDrawingRenderer.h"
+#include "PolygonDrawingModel.h"
+#include "SNAPAppearanceSettings.h"
+#include "GlobalUIModel.h"
+
+
+// Default colors
+const float PolygonDrawingRenderer::m_DrawingModeColor[] = { 1.0f, 0.0f, 0.5f };
+const float PolygonDrawingRenderer::m_EditModeNormalColor[] = { 1.0f, 0.0f, 0.0f };
+const float PolygonDrawingRenderer::m_EditModeSelectedColor[] = { 0.0f, 1.0f, 0.0f };
+
+PolygonDrawingRenderer::PolygonDrawingRenderer()
+{
+  m_Model = NULL;
+}
+
+void
+PolygonDrawingRenderer
+::DrawBox(const vnl_vector_fixed<float, 4> &box,
+          float border_x, float border_y)
+{
+  glBegin(GL_LINE_LOOP);
+  glVertex3f(box[0] - border_x, box[2] - border_y, 0.0);
+  glVertex3f(box[1] + border_x, box[2] - border_y, 0.0);
+  glVertex3f(box[1] + border_x, box[3] + border_y, 0.0);
+  glVertex3f(box[0] - border_x, box[3] + border_y, 0.0);
+  glEnd();
+}
+
+void
+PolygonDrawingRenderer
+::paintGL()
+{
+  assert(m_Model);
+  if(m_ParentRenderer->IsThumbnailDrawing())
+    return;
+
+  PolygonDrawingModel::PolygonState state = m_Model->GetState();
+
+  // Get appearance settings, etc
+  GenericSliceModel *parentModel = m_ParentRenderer->GetModel();
+  SNAPAppearanceSettings *as =
+      parentModel->GetParentUI()->GetAppearanceSettings();
+
+  // Must be in active state
+  if (state == PolygonDrawingModel::INACTIVE_STATE)
+    return;
+
+  // Get appearance settings for the drawing
+  OpenGLAppearanceElement *aeDraw = as->GetUIElement(
+        SNAPAppearanceSettings::POLY_DRAW_MAIN);
+
+  OpenGLAppearanceElement *aeClose = as->GetUIElement(
+        SNAPAppearanceSettings::POLY_DRAW_CLOSE);
+
+  OpenGLAppearanceElement *aeEdit = as->GetUIElement(
+        SNAPAppearanceSettings::POLY_EDIT);
+
+
+  // Check if the loop should be highlighted
+  const Vector3d &aeDrawColor = m_Model->IsHoverOverFirstVertex()
+      ? aeDraw->GetActiveColor() : aeDraw->GetActiveColor();
+
+  const Vector3d &aeCloseColor = m_Model->IsHoverOverFirstVertex()
+      ? aeClose->GetActiveColor() : aeClose->GetNormalColor();
+
+  // Push the line state
+  glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
+
+  // Set line and point drawing parameters
+  glPointSize(4);
+
+  // Draw the line segments
+  const PolygonDrawingModel::VertexList &vx = m_Model->GetVertices();
+  const PolygonDrawingModel::VertexList &dvx = m_Model->GetDragVertices();
+
+  // Useful iterators
+  PolygonDrawingModel::VertexList::const_iterator it, itNext;
+
+  if (state == PolygonDrawingModel::EDITING_STATE)
+  {
+    glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
+    aeEdit->ApplyLineSettings();
+
+    glBegin(GL_LINES);
+
+    for(it = vx.begin(); it!=vx.end(); ++it)
+      {
+      // Point to the next vertex, circular
+      itNext = it; ++itNext;
+      if(itNext == vx.end())
+        itNext = vx.begin();
+
+      // Set the color based on the mode
+      if (it->selected && itNext->selected)
+        glColor3dv(aeEdit->GetActiveColor().data_block());
+      else
+        glColor3dv(aeEdit->GetNormalColor().data_block());
+
+      // Draw the line
+      glVertex3f(it->x, it->y, 0);
+      glVertex3f(itNext->x, itNext->y, 0);
+    }
+    glEnd();
+
+    glPopAttrib();
+  }
+  else
+  {
+    // Not editing state
+    glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
+    aeDraw->ApplyLineSettings();
+
+    // Draw the vertices
+    glBegin(GL_LINE_STRIP);
+    glColor3dv(aeDrawColor.data_block());
+    for(it = vx.begin(); it!=vx.end(); ++it)
+      glVertex3f(it->x, it->y, 0);
+    glEnd();
+
+    // Draw the drag vertices
+    if(dvx.size())
+      {
+      glBegin(GL_LINE_STRIP);
+      for(it = dvx.begin(); it != dvx.end(); ++it)
+        glVertex3f(it->x, it->y, 0);
+      glEnd();
+      }
+
+
+    // If hovering over the last point, draw the closing line using
+    // current appearance settings
+    if(m_Model->IsHoverOverFirstVertex())
+      {
+      glBegin(GL_LINES);
+      if(dvx.size())
+        glVertex3f(dvx.back().x, dvx.back().y, 0);
+      else
+        glVertex3f(vx.back().x, vx.back().y, 0);
+      glVertex3f(vx.front().x, vx.front().y, 0);
+      glEnd();
+      }
+
+    else if(dvx.size() + vx.size() > 2 && aeClose->GetVisible())
+      {
+      // Draw the stripped line.
+      glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
+      aeClose->ApplyLineSettings();
+
+      glBegin(GL_LINES);
+      glColor3dv(aeCloseColor.data_block());
+      if(dvx.size())
+        glVertex3f(dvx.back().x, dvx.back().y, 0);
+      else
+        glVertex3f(vx.back().x, vx.back().y, 0);
+      glVertex3f(vx.front().x, vx.front().y, 0);
+      glEnd();
+      glPopAttrib();
+      }
+
+    glPopAttrib();
+
+  }
+
+  // draw the vertices
+  glBegin(GL_POINTS);
+  glPushAttrib(GL_COLOR_BUFFER_BIT);
+  for(it = vx.begin(); it!=vx.end();++it)
+  {
+    if(it->control)
+      {
+      if (it->selected)
+        glColor3dv(aeEdit->GetActiveColor().data_block());
+      else if (state == PolygonDrawingModel::DRAWING_STATE)
+        glColor3dv(aeDrawColor.data_block());
+      else
+        glColor3dv(aeEdit->GetNormalColor().data_block());
+
+      glVertex3f(it->x,it->y,0.0f);
+      }
+  }
+
+  // Draw the last dragging vertex point
+  if(dvx.size())
+    {
+    PolygonVertex last = dvx.back();
+    glColor3dv(aeEdit->GetActiveColor().data_block());
+    glVertex3f(last.x, last.y, 0.0f);
+    }
+
+  glEnd();
+  glPopAttrib();
+
+  // draw edit or pick box
+  if(m_Model->IsDraggingPickBox())
+  {
+    glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
+
+    glLineWidth(1);
+    glColor3dv(aeEdit->GetActiveColor().data_block());
+    DrawBox(m_Model->GetSelectionBox());
+
+    glPopAttrib();
+  }
+  else if (m_Model->GetSelectedVertices())
+  {
+    glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
+
+    glLineWidth(1);
+    glColor3dv(aeEdit->GetActiveColor().data_block());
+    Vector2f border = m_Model->GetPixelSize() * 4.0f;
+    glLineWidth(1);
+    glColor3fv(m_EditModeSelectedColor);
+    DrawBox(m_Model->GetEditBox(), border[0], border[1]);
+    glPopAttrib();
+  }
+
+  glPopAttrib();
+}
+
diff --git a/GUI/Renderer/PolygonDrawingRenderer.h b/GUI/Renderer/PolygonDrawingRenderer.h
new file mode 100644
index 0000000..9339479
--- /dev/null
+++ b/GUI/Renderer/PolygonDrawingRenderer.h
@@ -0,0 +1,37 @@
+#ifndef POLYGONDRAWINGRENDERER_H
+#define POLYGONDRAWINGRENDERER_H
+
+#include "SNAPCommon.h"
+#include "GenericSliceRenderer.h"
+
+class PolygonDrawingModel;
+
+class PolygonDrawingRenderer : public SliceRendererDelegate
+{
+public:
+
+  irisITKObjectMacro(PolygonDrawingRenderer, SliceRendererDelegate)
+
+  void paintGL();
+
+  irisGetMacro(Model, PolygonDrawingModel *)
+  irisSetMacro(Model, PolygonDrawingModel *)
+
+
+protected:
+
+  PolygonDrawingRenderer();
+  virtual ~PolygonDrawingRenderer() {}
+
+  void DrawBox(const vnl_vector_fixed<float, 4> &box,
+               float border_x = 0.0f, float border_y = 0.0f);
+
+  PolygonDrawingModel *m_Model;
+
+  // Colors used to draw polygon
+  const static float m_DrawingModeColor[];
+  const static float m_EditModeSelectedColor[];
+  const static float m_EditModeNormalColor[];
+};
+
+#endif // POLYGONDRAWINGRENDERER_H
diff --git a/GUI/Renderer/PolygonScanConvert.cxx b/GUI/Renderer/PolygonScanConvert.cxx
new file mode 100644
index 0000000..f8b5e4c
--- /dev/null
+++ b/GUI/Renderer/PolygonScanConvert.cxx
@@ -0,0 +1,177 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: PolygonScanConvert.cxx,v $
+  Language:  C++
+  Date:      $Date: 2009/01/23 20:09:38 $
+  Version:   $Revision: 1.8 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#include "PolygonScanConvert.h"
+#include "SNAPCommon.h"
+#include "itkImage.h"
+
+#include <iostream>
+
+// Typecast for the callback functions
+#ifdef WIN32
+typedef void (CALLBACK *TessCallback)();
+#elif defined (__APPL__)
+typedef GLvoid (*TessCallback)(...);
+#else
+typedef void (*TessCallback)();
+#endif
+
+void 
+PolygonScanConvertBase
+::RasterizeFilled(double *vArray, unsigned int nVertices, 
+  unsigned int width, unsigned int height, GLenum glType, void *buffer)
+{
+  // Push the GL attributes to preserve everything
+  glPushAttrib(GL_ALL_ATTRIB_BITS);
+
+  // Tesselate the polygon and save the tesselation as a display list
+  GLint dl = glGenLists(1);
+  glNewList(dl, GL_COMPILE);
+
+  // Set the background to black
+  glClearColor(0,0,0,1);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  // Paint in white
+  glColor3d(1.0, 1.0, 1.0);
+
+  // Start the tesselation
+  GLUtesselator *tess = gluNewTess();
+  gluTessCallback(tess,(GLenum) GLU_TESS_VERTEX, (TessCallback) &glVertex3dv);
+  gluTessCallback(tess,(GLenum) GLU_TESS_BEGIN, (TessCallback) &glBegin); 
+  gluTessCallback(tess,(GLenum) GLU_TESS_END, (TessCallback) &glEnd);
+  gluTessCallback(tess,(GLenum) GLU_TESS_ERROR, 
+    (TessCallback) &PolygonScanConvertBase::ErrorCallback);     
+  gluTessCallback(tess,(GLenum) GLU_TESS_COMBINE, 
+    (TessCallback) &PolygonScanConvertBase::CombineCallback);
+  gluTessProperty(tess,(GLenum) GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);  
+  gluTessNormal(tess,0.0,0.0,1.0);
+
+  gluTessBeginPolygon(tess,NULL);
+  gluTessBeginContour(tess);
+
+  // Add the vertices
+  for(unsigned int i=0; i < nVertices; i++)
+    { gluTessVertex(tess, vArray + 3*i, vArray + 3*i); }
+    
+  // End the tesselation
+  gluTessEndContour(tess);
+  gluTessEndPolygon(tess);
+
+  // End the display list
+  glEndList();
+
+  // Draw polygon into back buffer - back buffer should get redrawn
+  // anyway before it gets swapped to the screen.
+  glDrawBuffer(GL_BACK);
+  glReadBuffer(GL_BACK);
+
+  // We will perform a tiled drawing, because the backbuffer may be smaller
+  // than the size of the image. First get the viewport size, i.e., tile size
+  GLint xViewport[4]; glGetIntegerv(GL_VIEWPORT, xViewport);
+  unsigned int wTile = (unsigned int) xViewport[2];
+  unsigned int hTile = (unsigned int) xViewport[3];
+
+  // Figure out the number of tiles in x and y dimension
+  unsigned int nTilesX = (unsigned int) ceil( width * 1.0 / wTile );
+  unsigned int nTilesY = (unsigned int) ceil( height * 1.0 / hTile );
+
+  // Draw and retrieve each tile
+  for(unsigned int iTileX = 0; iTileX < nTilesX; iTileX++)
+    {
+    for(unsigned int iTileY = 0; iTileY < nTilesY; iTileY++)
+      {
+      // Get the corner of the tile
+      unsigned int xTile = iTileX * wTile, yTile = iTileY * hTile;
+
+      // Set the projection matrix
+      glMatrixMode(GL_PROJECTION);
+      glPushMatrix();
+      glLoadIdentity();
+      gluOrtho2D(xTile, xTile + wTile, yTile, yTile + hTile);
+
+      // Set the model view matrix
+      glMatrixMode(GL_MODELVIEW);
+      glPushMatrix();
+      glLoadIdentity();
+
+      // Draw the triangles
+      glCallList(dl);
+
+      // Figure out the size of the data chunk to copy
+      unsigned int wCopy = width - xTile < wTile ? width - xTile : wTile;
+      unsigned int hCopy = height - yTile < hTile ? height - yTile : hTile;
+      
+      // Set up the copy so that the strides are correct
+      glPixelStorei(GL_PACK_ALIGNMENT, 1);
+      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+      glPixelStorei(GL_PACK_ROW_LENGTH, width);
+      glPixelStorei(GL_PACK_SKIP_PIXELS, xTile);
+      glPixelStorei(GL_PACK_SKIP_ROWS, yTile);
+
+      // Copy the pixels to the buffer
+      glReadPixels(0, 0, wCopy, hCopy, GL_RED, glType, buffer);
+
+      // Restore the GL state
+      glPopMatrix();
+      glMatrixMode(GL_PROJECTION);
+      glPopMatrix();
+      }
+    }
+
+  // Get rid of the display list
+  glDeleteLists(dl,1);
+
+  // Delete the tesselator
+  gluDeleteTess(tess);
+
+  // Restore the GL state
+  glPopAttrib();
+}
+
+void PolygonScanConvertBase::ErrorCallback(GLenum errorCode)
+{ 
+  std::cerr << "Tesselation Error: " << gluErrorString(errorCode) << std::endl; 
+}
+
+void PolygonScanConvertBase::CombineCallback(GLdouble coords[3], 
+                GLdouble **vertex_data,  
+                GLfloat *weight, 
+                GLdouble **dataOut) 
+{
+  GLdouble *vertex = new GLdouble[3];
+  vertex[0] = coords[0]; vertex[1] = coords[1]; vertex[2] = coords[2];
+  *dataOut = vertex;
+}
+
diff --git a/GUI/Renderer/PolygonScanConvert.h b/GUI/Renderer/PolygonScanConvert.h
new file mode 100644
index 0000000..a4c9bb8
--- /dev/null
+++ b/GUI/Renderer/PolygonScanConvert.h
@@ -0,0 +1,94 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: PolygonScanConvert.h,v $
+  Language:  C++
+  Date:      $Date: 2009/01/23 20:09:38 $
+  Version:   $Revision: 1.3 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#ifndef __PolygonScanConvert_h_
+#define __PolygonScanConvert_h_
+
+#include "SNAPOpenGL.h"
+#include "itkImage.h"
+
+class PolygonScanConvertBase
+{
+public:
+  // Private version of the method, takes a flattened array of coordinates
+  // and is not templated
+  static void RasterizeFilled(
+    double *vArray, unsigned int nVertices, 
+    unsigned int width, unsigned int height, 
+    GLenum glType, void *buffer);
+
+  // Callbacks for tesselation
+  static void ErrorCallback(GLenum errorCode);
+  static void CombineCallback(
+    GLdouble coords[3], GLdouble **vertex_data,  
+    GLfloat *weight, GLdouble **dataOut);
+};
+
+template<class TPixel, GLenum VGlPixelType, class TVertexIterator>
+class PolygonScanConvert : public PolygonScanConvertBase
+{
+public:
+  typedef itk::Image<TPixel, 2> ImageType;
+
+  /** 
+   * This method uses OpenGL to scan-convert a polygonal curve. The input is a pair 
+   * of iterators (begin, end) to a list/array of double arrays or vectors, i.e., 
+   * objects for which indices [0] and [1] are supported.
+   */
+  static void RasterizeFilled(
+    TVertexIterator first, unsigned int n, ImageType *image)
+    {
+    double *vArray = new double[3 * (n + 1)], *vPointer = vArray;
+    for (unsigned int i = 0; i < n; ++i, ++first)
+      {
+      *vPointer++ = (double) (*first)[0];
+      *vPointer++ = (double) (*first)[1];
+      *vPointer++ = 0.0;
+      }
+  
+    // Set up the image properties
+    unsigned int width  = image->GetBufferedRegion().GetSize()[0];
+    unsigned int height = image->GetBufferedRegion().GetSize()[1];
+    PolygonScanConvertBase::RasterizeFilled(
+      vArray, n, width, height, VGlPixelType, image->GetBufferPointer());
+    delete vArray;
+    }
+
+private:
+
+
+};
+
+#endif
+
diff --git a/GUI/Renderer/SliceWindowDecorationRenderer.cxx b/GUI/Renderer/SliceWindowDecorationRenderer.cxx
new file mode 100644
index 0000000..b10ef75
--- /dev/null
+++ b/GUI/Renderer/SliceWindowDecorationRenderer.cxx
@@ -0,0 +1,280 @@
+#include "SliceWindowDecorationRenderer.h"
+#include "GenericSliceModel.h"
+#include "SNAPAppearanceSettings.h"
+#include "GlobalUIModel.h"
+#include "GenericSliceRenderer.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "DisplayLayoutModel.h"
+
+SliceWindowDecorationRenderer::SliceWindowDecorationRenderer()
+{
+}
+
+SliceWindowDecorationRenderer::~SliceWindowDecorationRenderer()
+{
+
+}
+
+void SliceWindowDecorationRenderer::paintGL()
+{
+  DrawOrientationLabels();
+  DrawRulers();
+  DrawNicknames();
+
+}
+
+void SliceWindowDecorationRenderer::DrawOrientationLabels()
+{
+  GenericSliceModel *parentModel = this->GetParentRenderer()->GetModel();
+  SNAPAppearanceSettings *as =
+      parentModel->GetParentUI()->GetAppearanceSettings();
+
+  // The letter labels
+  static const char *letters[3][2] = {{"R","L"},{"A","P"},{"I","S"}};
+  const char *labels[2][2];
+
+  // Get the properties for the labels
+  const OpenGLAppearanceElement *elt =
+      as->GetUIElement(SNAPAppearanceSettings::MARKERS);
+
+  // Leave if the labels are disabled
+  if(!elt->GetVisible()) return;
+
+  // Repeat for X and Y directions
+  for(unsigned int i=0;i<2;i++)
+    {
+    // Which axis are we on in anatomy space?
+    unsigned int anatomyAxis =
+        parentModel->GetDisplayToAnatomyTransform().GetCoordinateIndexZeroBased(i);
+
+    // Which direction is the axis facing (returns -1 or 1)
+    unsigned int anatomyAxisDirection =
+        parentModel->GetDisplayToAnatomyTransform().GetCoordinateOrientation(i);
+
+    // Map the direction onto 0 or 1
+    unsigned int letterIndex = (1 + anatomyAxisDirection) >> 1;
+
+    // Compute the two labels for this axis
+    labels[i][0] = letters[anatomyAxis][1-letterIndex];
+    labels[i][1] = letters[anatomyAxis][letterIndex];
+    }
+
+  double vppr = parentModel->GetSizeReporter()->GetViewportPixelRatio();
+  Vector2ui vp = parentModel->GetSizeReporter()->GetLogicalViewportSize();
+
+  glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
+  glPushMatrix();
+  glLoadIdentity();
+  glScaled(vppr, vppr, 1.0);
+
+  glEnable(GL_BLEND);
+  glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+  // Get the various sizes and offsets
+  int offset = 4 + elt->GetFontSize();
+  int margin = elt->GetFontSize() / 3;
+  int w = vp[0], h = vp[1];
+
+  // Create the font info
+  AbstractRendererPlatformSupport::FontInfo font_info =
+        { AbstractRendererPlatformSupport::TYPEWRITER, elt->GetFontSize() * vppr, true };
+
+  // Use the delegate to draw text
+  this->m_PlatformSupport->RenderTextInOpenGL(
+        labels[0][0], margin, (h-offset)/2, offset, offset, font_info, -1, 0, elt->GetNormalColor());
+
+  this->m_PlatformSupport->RenderTextInOpenGL(
+        labels[0][1], w - (offset+margin), (h-offset)/2, offset, offset, font_info, 1, 0, elt->GetNormalColor());
+
+  this->m_PlatformSupport->RenderTextInOpenGL(
+        labels[1][0], (w-offset)/2, 0, offset, offset, font_info, 0, -1, elt->GetNormalColor());
+
+  this->m_PlatformSupport->RenderTextInOpenGL(
+        labels[1][1], (w-offset)/2, h - (offset+1), offset, offset, font_info, 0, 1, elt->GetNormalColor());
+
+  glPopMatrix();
+  glPopAttrib();
+}
+
+void SliceWindowDecorationRenderer::DrawNicknames()
+{
+  // Draw the nicknames
+  GenericSliceModel *parentModel = this->GetParentRenderer()->GetModel();
+  DisplayLayoutModel *dlm = parentModel->GetParentUI()->GetDisplayLayoutModel();
+  Vector2ui layout = dlm->GetSliceViewLayerTilingModel()->GetValue();
+  int nrows = (int) layout[0];
+  int ncols = (int) layout[1];
+
+  if(nrows * ncols == 1)
+    return;
+
+  // Get the properties for the labels
+  SNAPAppearanceSettings *as =
+      parentModel->GetParentUI()->GetAppearanceSettings();
+
+  const OpenGLAppearanceElement *elt =
+      as->GetUIElement(SNAPAppearanceSettings::RULER);
+
+  // Leave if the labels are disabled
+  if(!elt->GetVisible()) return;
+
+  // Viewport properties (retina-related)
+  double vppr = parentModel->GetSizeReporter()->GetViewportPixelRatio();
+  Vector2ui vp = parentModel->GetSizeReporter()->GetLogicalViewportSize();
+
+  // Apply the label properties
+  glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
+  glPushMatrix();
+  glLoadIdentity();
+  glScaled(vppr, vppr, 1.0);
+
+  elt->ApplyLineSettings();
+  glColor4d( elt->GetNormalColor()[0], elt->GetNormalColor()[1], elt->GetNormalColor()[2], 1.0 );
+
+  // Get the viewport size
+  int w = vp[0] / ncols, h = vp[1] / nrows;
+
+  AbstractRendererPlatformSupport::FontInfo font_info =
+        { AbstractRendererPlatformSupport::SANS, elt->GetFontSize() * vppr, false };
+
+  // Find the longest nickname
+  int maxwidth = 0;
+  for(int i = 0; i < nrows; i++)
+    {
+    for(int j = 0; j < ncols; j++)
+      {
+      // Define the ROI for this label
+      ImageWrapperBase *layer =
+          this->GetParentRenderer()->GetLayerForNthTile(i, j);
+
+      if(layer)
+        {
+        int fw = this->m_PlatformSupport->MeasureTextWidth(
+              layer->GetNickname().c_str(), font_info);
+        if(fw > maxwidth)
+          maxwidth = fw;
+        }
+      }
+    }
+
+  // Adjust the font size
+  if(maxwidth > 0.92 * w)
+    {
+    font_info.pixel_size = (int) (font_info.pixel_size * w * 0.92 / maxwidth);
+    }
+
+  // Draw each nickname
+  for(int i = 0; i < nrows; i++)
+    {
+    for(int j = 0; j < ncols; j++)
+      {
+      // Define the ROI for this label
+      ImageWrapperBase *layer =
+          this->GetParentRenderer()->GetLayerForNthTile(i, j);
+      if(layer)
+        {
+        this->m_PlatformSupport->RenderTextInOpenGL(
+              layer->GetNickname().c_str(),
+              w * j, h * (nrows - i) - 20, w, 15, font_info,
+              AbstractRendererPlatformSupport::HCENTER,
+              AbstractRendererPlatformSupport::TOP,
+              elt->GetNormalColor());
+        }
+      }
+    }
+
+
+  glPopMatrix();
+  glPopAttrib();
+}
+
+void SliceWindowDecorationRenderer::DrawRulers()
+{
+  GenericSliceModel *parentModel = this->GetParentRenderer()->GetModel();
+  SNAPAppearanceSettings *as =
+      parentModel->GetParentUI()->GetAppearanceSettings();
+
+  // Get the properties for the labels
+  const OpenGLAppearanceElement *elt =
+      as->GetUIElement(SNAPAppearanceSettings::RULER);
+
+  // Leave if the labels are disabled
+  if(!elt->GetVisible()) return;
+
+  // Get the viewport properties (retina-capable)
+  float vppr = parentModel->GetSizeReporter()->GetViewportPixelRatio();
+  Vector2ui vp = parentModel->GetSizeReporter()->GetLogicalViewportSize();
+
+  glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
+  glPushMatrix();
+  glLoadIdentity();
+  glScaled(vppr, vppr, 1.0);
+
+  elt->ApplyLineSettings();
+  glColor4d( elt->GetNormalColor()[0], elt->GetNormalColor()[1], elt->GetNormalColor()[2], 1.0 );
+
+  // The ruler bar should be as large as possible but less than one half
+  // of the screen width (not to go over the markers)
+  double maxw = 0.5 * vp[0] - 20.0;
+  maxw = maxw < 5 ? 5 : maxw;
+
+  double zoom = parentModel->GetViewZoom();
+  double scale = 1.0;
+  while(zoom * scale > maxw) scale /= 10.0;
+  while(zoom * scale < 0.1 * maxw) scale *= 10.0;
+
+  // Draw a zoom bar
+  double bw = scale * zoom;
+  glBegin(GL_LINES);
+  glVertex2d(vp[0] - 5,5);
+  glVertex2d(vp[0] - 5,15);
+  glVertex2d(vp[0] - 5,10);
+  glVertex2d(vp[0] - (5 + bw),10);
+  glVertex2d(vp[0] - (5 + bw),5);
+  glVertex2d(vp[0] - (5 + bw),15);
+  glEnd();
+
+  // Based on the log of the scale, determine the unit
+  string unit = "mm";
+  if(scale >= 10 && scale < 1000)
+    { unit = "cm"; scale /= 10; }
+  else if(scale >= 1000)
+    { unit = "m"; scale /= 1000; }
+  else if(scale >= 1000000)
+    { unit = "km"; scale /= 1000000; }
+  else if(scale < 1 && scale > 0.001)
+    { unit = "\xb5m"; scale *= 1000; }
+  else if(scale < 0.001)
+    { unit = "nm"; scale *= 1000000; }
+
+  std::ostringstream oss;
+  oss << scale << " " << unit;
+
+  // Get the fontsize in GL pixels
+  int font_size = elt->GetFontSize();
+
+  // Create the font info
+  AbstractRendererPlatformSupport::FontInfo font_info =
+        { AbstractRendererPlatformSupport::SANS, font_size * vppr, false };
+
+  // See if we can squeeze the label under the ruler
+  if(bw > font_size * 4)
+    {
+    this->m_PlatformSupport->RenderTextInOpenGL(
+        oss.str().c_str(),
+        vp[0]-(bw+10), 12, (int) bw, font_size+8,
+        font_info, 0, -1, elt->GetNormalColor());
+    }
+  else
+    {
+    this->m_PlatformSupport->RenderTextInOpenGL(
+          oss.str().c_str(),
+          vp[0] - (int) (2 * bw + font_size * 4 + 20), 5,
+          (int) (bw + font_size * 4+10), font_size,
+          font_info, 1, 0, elt->GetNormalColor());
+    }
+
+  glPopMatrix();
+  glPopAttrib();
+}
diff --git a/GUI/Renderer/SliceWindowDecorationRenderer.h b/GUI/Renderer/SliceWindowDecorationRenderer.h
new file mode 100644
index 0000000..ffd0768
--- /dev/null
+++ b/GUI/Renderer/SliceWindowDecorationRenderer.h
@@ -0,0 +1,30 @@
+#ifndef SLICEWINDOWDECORATIONRENDERER_H
+#define SLICEWINDOWDECORATIONRENDERER_H
+
+#include "SNAPCommon.h"
+#include "GenericSliceRenderer.h"
+
+class GenericSliceRenderer;
+class GenericSliceModel;
+
+class SliceWindowDecorationRenderer : public SliceRendererDelegate
+{
+public:
+
+  irisITKObjectMacro(SliceWindowDecorationRenderer, SliceRendererDelegate)
+
+  virtual void paintGL();
+
+protected:
+
+  void DrawOrientationLabels();
+
+  void DrawRulers();
+
+  void DrawNicknames();
+
+  SliceWindowDecorationRenderer();
+  virtual ~SliceWindowDecorationRenderer();
+};
+
+#endif // SLICEWINDOWDECORATIONRENDERER_H
diff --git a/GUI/Renderer/SnakeModeRenderer.cxx b/GUI/Renderer/SnakeModeRenderer.cxx
new file mode 100644
index 0000000..0c230e4
--- /dev/null
+++ b/GUI/Renderer/SnakeModeRenderer.cxx
@@ -0,0 +1,162 @@
+#include "SnakeModeRenderer.h"
+#include "SnakeWizardModel.h"
+#include "GenericSliceModel.h"
+#include "GlobalUIModel.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "SNAPImageData.h"
+#include "GlobalState.h"
+#include "itkImage.h"
+
+SnakeModeRenderer::SnakeModeRenderer()
+{
+  m_Model = NULL;
+}
+
+void SnakeModeRenderer::paintGL()
+{
+  IRISApplication *app = m_Model->GetParent()->GetDriver();
+
+  if(app->IsSnakeModeActive()
+     && !this->GetParentRenderer()->IsThumbnailDrawing())
+    {
+    // Bubbles are drawn only when on the bubbles page
+    if(m_Model->CheckState(SnakeWizardModel::UIF_BUBBLE_MODE))
+      {
+      // Draw the bubbles before segmentation starts
+      this->DrawBubbles();
+      }
+    }
+}
+
+void SnakeModeRenderer::DrawBubbles()
+{
+  const GLubyte stipple[] = {
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55 };
+
+  IRISApplication *app = m_Model->GetParent()->GetDriver();
+  GlobalState *gs = app->GetGlobalState();
+  GenericSliceModel *sliceModel = GetParentRenderer()->GetModel();
+
+  // Get the list of bubbles
+  IRISApplication::BubbleArray &bubbles = app->GetBubbleArray();
+
+  // draw bubbles
+  int numBubbles = bubbles.size();
+  int activeBubble = gs->GetActiveBubble();
+
+  if (numBubbles > 0)
+    {
+    // Get the active color label
+    int currentcolor =  gs->GetDrawingColorLabel();
+    ColorLabel cl = app->GetColorLabelTable()->GetColorLabel(currentcolor);
+
+    // Get the current alpha blending factor for displaying overlays
+    unsigned char alpha = (unsigned char)(255 * gs->GetSegmentationAlpha());
+
+    // Get the color of the active color label
+    unsigned char rgb[3];
+    cl.GetRGBVector(rgb);
+
+    // Get the current crosshairs position
+    Vector3f cursorImage = to_float(app->GetCursorPosition()) + Vector3f(0.5f);
+
+    // Get the image space dimension that corresponds to this window
+    int iid = sliceModel->GetSliceDirectionInImageSpace();
+
+    // Get the other essentials from the parent
+    Vector3f scaling = sliceModel->GetSliceSpacing();
+
+    // Turn on alpha blending
+    glPushAttrib(GL_POLYGON_BIT | GL_COLOR_BUFFER_BIT);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    // Create a filled circle object
+    GLUquadricObj *object = gluNewQuadric();
+    gluQuadricDrawStyle(object,GLU_FILL);
+
+    // Draw each bubble
+    for (int i = 0; i < numBubbles; i++)
+      {
+
+      // Get the center and radius of the i-th bubble
+      Vector3f ctrImage = to_float(bubbles[i].center) + Vector3f(0.5f);
+      double radius = bubbles[i].radius;
+
+      // Remap the center into slice coordinates
+      Vector3f ctrSlice = sliceModel->MapImageToSlice(to_float(ctrImage));
+
+      // Compute the offset from the center along the slice z-direction
+      // in physical coordinates
+      double dcenter = scaling(2) * (cursorImage(iid) - ctrImage(iid));
+
+      // Check if the bubble is intersected by the current slice plane
+      if (dcenter >= radius || -dcenter >= radius) continue;
+
+      // Compute the radius of the bubble in the cut plane
+      double diskradius = sqrt(fabs(radius*radius - dcenter*dcenter));
+
+      // Draw the bubble
+      glColor4ub(rgb[0],rgb[1],rgb[2],alpha);
+      glPushMatrix();
+
+      if(activeBubble == i)
+        {
+        glEnable(GL_POLYGON_STIPPLE);
+        glPolygonStipple(stipple);
+        }
+
+      glTranslatef(ctrSlice[0], ctrSlice[1], 0.0f);
+      glScalef(1.0f / scaling(0),1.0f / scaling(1),1.0f);
+      gluDisk(object,0,diskradius,100,1);
+
+      // If the bubble is active, draw an outline around the bubble
+      if(activeBubble == i)
+        {
+        glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
+
+        glEnable(GL_BLEND);
+        glEnable(GL_LINE_SMOOTH);
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+        glLineWidth(1.5);
+
+        glColor4ub(
+              255 - (255 - rgb[0]) / 2,
+              255 - (255 - rgb[1]) / 2,
+              255 - (255 - rgb[2]) / 2, 255);
+
+        glBegin(GL_LINE_LOOP);
+        for(unsigned int d = 0; d < 360; d+=2)
+          {
+          double rad = d * vnl_math::pi / 180.0;
+          glVertex2f(diskradius * cos(rad), diskradius * sin(rad));
+          }
+        glEnd();
+        glPopAttrib();
+        }
+
+      glPopMatrix();
+
+      }
+
+    gluDeleteQuadric(object);
+    glDisable(GL_BLEND);
+    glPopAttrib();
+    }
+}
diff --git a/GUI/Renderer/SnakeModeRenderer.h b/GUI/Renderer/SnakeModeRenderer.h
new file mode 100644
index 0000000..084176e
--- /dev/null
+++ b/GUI/Renderer/SnakeModeRenderer.h
@@ -0,0 +1,31 @@
+#ifndef SNAKEMODERENDERER_H
+#define SNAKEMODERENDERER_H
+
+#include "SNAPCommon.h"
+#include "GenericSliceRenderer.h"
+
+class SnakeWizardModel;
+
+/**
+  This renderer draws SNAP-specific overlays
+  */
+class SnakeModeRenderer : public SliceRendererDelegate
+{
+public:
+
+  irisITKObjectMacro(SnakeModeRenderer, SliceRendererDelegate)
+  irisGetSetMacro(Model, SnakeWizardModel *)
+
+  void paintGL();
+
+protected:
+
+  SnakeModeRenderer();
+  virtual ~SnakeModeRenderer() {}
+
+  SnakeWizardModel *m_Model;
+
+  void DrawBubbles();
+};
+
+#endif // SNAKEMODERENDERER_H
diff --git a/GUI/Renderer/SnakeParameterPreviewRenderer.cxx b/GUI/Renderer/SnakeParameterPreviewRenderer.cxx
new file mode 100644
index 0000000..e8a7d62
--- /dev/null
+++ b/GUI/Renderer/SnakeParameterPreviewRenderer.cxx
@@ -0,0 +1,189 @@
+#include "SnakeParameterPreviewRenderer.h"
+#include "SnakeParametersPreviewPipeline.h"
+#include "OpenGLSliceTexture.h"
+#include "SnakeParameterModel.h"
+
+SnakeParameterPreviewRenderer::SnakeParameterPreviewRenderer()
+{
+  // Initialize the texture object
+  m_Texture = new OpenGLSliceTexture<RGBAType>;
+  m_Texture->SetGlComponents(4);
+  m_Texture->SetGlFormat(GL_RGBA);
+}
+
+SnakeParameterPreviewRenderer::~SnakeParameterPreviewRenderer()
+{
+  delete m_Texture;
+}
+
+void SnakeParameterPreviewRenderer::initializeGL()
+{
+}
+
+void SnakeParameterPreviewRenderer::resizeGL(int w, int h)
+{
+  // The window will have coordinates (0,0) to (1,1)
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  gluOrtho2D(0.0,1.0,0.0,1.0);
+  glViewport(0,0,w,h);
+
+  // Establish the model view matrix
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+
+  m_ViewportWidth = w;
+}
+
+void SnakeParameterPreviewRenderer::SetModel(SnakeParameterModel *model)
+{
+  m_Model = model;
+  m_Pipeline = model->GetPreviewPipeline();
+  m_Texture->SetImage(m_Pipeline->GetDisplayImage());
+
+  Rebroadcast(m_Model, ModelUpdateEvent(), ModelUpdateEvent());
+  Rebroadcast(m_Model->GetAnimateDemoModel(), ValueChangedEvent(), ModelUpdateEvent());
+
+  Rebroadcast(m_Model, SnakeParameterModel::DemoLoopEvent(), ModelUpdateEvent());
+}
+
+void SnakeParameterPreviewRenderer::paintGL()
+{
+  // Update everything
+  m_Pipeline->Update();
+
+  // Clear the display
+  glClearColor(0.0,0.0,0.0,1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  // Set up the line drawing attributes
+  glPushAttrib(GL_LIGHTING_BIT | GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
+
+  // Set up the model matrix
+  glPushMatrix();
+  glScaled(1.0 / m_Pipeline->GetSpeedImage()->GetBufferedRegion().GetSize(0),
+           1.0 / m_Pipeline->GetSpeedImage()->GetBufferedRegion().GetSize(1),
+           1.0);
+
+  // Draw the speed image
+  m_Texture->Draw(Vector3d(1.0));
+
+  // Set up the line drawing mode
+  glEnable(GL_LINE_SMOOTH);
+  glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
+  glEnable(GL_BLEND);
+  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  glLineWidth(2.0);
+  glColor3d(1.0, 0.0, 0.0);
+
+  // Draw the evolving contour if it's available
+  if(m_Model->GetAnimateDemo())
+    {
+    std::vector<Vector2d> &points = m_Pipeline->GetDemoLoopContour();
+    glColor3d(1.0, 0.0, 0.0);
+    glBegin(GL_LINES);
+    std::vector<Vector2d>::iterator it = points.begin();
+    for(; it != points.end(); ++it)
+      {
+      glVertex(*it);
+      }
+    glEnd();
+
+    glLineWidth(1.0);
+    glColor4d(1.0, 0.0, 0.0, 0.5);
+    }
+
+
+  // Draw the vectors
+  //glLineWidth(1.0);
+
+  // No more image scaling
+  glPopMatrix();
+  glPushMatrix();
+
+  // Get the point collection
+  const SnakeParametersPreviewPipeline::SampledPointList
+      &list = m_Pipeline->GetSampledPoints();
+
+  // Draw the spline
+  glBegin(GL_LINE_LOOP);
+  for(unsigned int j=0;j<list.size();j++)
+    {
+    glVertex2d(list[j].x[0],list[j].x[1]);
+    }
+  glEnd();
+
+  // Draw the forces on the spline
+  // Draw the vectors from the curve
+  glColor3d(1.0,0.0,0.0);
+  glBegin(GL_LINES);
+  for(unsigned int i=0;i<list.size();i+=4)
+    {
+    // A reference so we can access the point in shorthand
+    const SnakeParametersPreviewPipeline::SampledPoint &p = list[i];
+
+    // Decide which force to draw, depending on the current state
+    double force = 0;
+    switch(m_ForceToDisplay)
+      {
+      case PROPAGATION_FORCE :
+        force = p.PropagationForce;
+        break;
+      case CURVATURE_FORCE :
+        force = p.CurvatureForce;
+        break;
+      case ADVECTION_FORCE :
+        force = p.AdvectionForce;
+        break;
+      case TOTAL_FORCE :
+        force = p.PropagationForce + p.CurvatureForce + p.AdvectionForce;
+        break;
+      }
+
+    // Scale the force for effect
+    force *= 10;
+
+    // Draw the forces
+    glVertex2d(p.x[0],p.x[1]);
+    glVertex2d(p.x[0] + force * p.n[0] / m_ViewportWidth,
+               p.x[1] + force * p.n[1] / m_ViewportWidth);
+    }
+
+  glEnd();
+
+  /*
+    const SnakeParametersPreviewPipeline::ImagePointList
+      &plist = m_Pipeline->GetImagePoints();
+
+    glBegin(GL_LINES);
+    for(unsigned int j=0;j<plist.size();j++)
+      {
+      const SnakeParametersPreviewPipeline::PointInfo &point = plist[j];
+
+      float length = 10.0f;
+      switch(m_ForceToDisplay)
+        {
+        case CURVATURE_FORCE   : length *= point.CurvatureForce; break;
+        case ADVECTION_FORCE   : length *= point.AdvectionForce; break;
+        case PROPAGATION_FORCE : length *= point.PropagationForce; break;
+        case TOTAL_FORCE       :
+          length *= (point.CurvatureForce + point.AdvectionForce +
+                     point.PropagationForce); break;
+        }
+
+      SnakeParametersPreviewPipeline::SampledPoint p = point.point;
+      glVertex2d(p.x[0],p.x[1]);
+      glVertex2d(p.x[0] + length * p.n[0],p.x[1] + length * p.n[1]);
+      }
+    glEnd();
+  */
+
+  // TODO: Draw the interactor
+
+  // Pop the matrix
+  glPopMatrix();
+
+  // Restore the attribute state
+  glPopAttrib();
+}
diff --git a/GUI/Renderer/SnakeParameterPreviewRenderer.h b/GUI/Renderer/SnakeParameterPreviewRenderer.h
new file mode 100644
index 0000000..8eb1467
--- /dev/null
+++ b/GUI/Renderer/SnakeParameterPreviewRenderer.h
@@ -0,0 +1,58 @@
+#ifndef SNAKEPARAMETERPREVIEWRENDERER_H
+#define SNAKEPARAMETERPREVIEWRENDERER_H
+
+#include "AbstractRenderer.h"
+#include "itkRGBAPixel.h"
+
+class SnakeParametersPreviewPipeline;
+class SnakeParameterModel;
+template <class TPixel> class OpenGLSliceTexture;
+
+class SnakeParameterPreviewRenderer : public AbstractRenderer
+{
+public:
+
+  irisITKObjectMacro(SnakeParameterPreviewRenderer, AbstractRenderer)
+
+  irisGetMacro(Pipeline, SnakeParametersPreviewPipeline *)
+
+  void SetModel(SnakeParameterModel *model);
+
+  /** An enumeration of different display modes for this widget */
+  enum DisplayMode
+    {
+    PROPAGATION_FORCE=0,CURVATURE_FORCE,ADVECTION_FORCE,TOTAL_FORCE
+    };
+
+  /** Set the display mode */
+  irisSetMacro(ForceToDisplay,DisplayMode)
+
+  virtual void paintGL();
+
+  virtual void initializeGL();
+  virtual void resizeGL(int w, int h);
+
+protected:
+
+  // Texture type for drawing speed images
+  typedef itk::RGBAPixel<unsigned char> RGBAType;
+
+  /** Model */
+  SnakeParameterModel *m_Model;
+
+  /** Preview pipeline logic */
+  SnakeParametersPreviewPipeline *m_Pipeline;
+
+  /** A texture object used to store the image */
+  OpenGLSliceTexture<RGBAType> *m_Texture;
+
+  /** Which force is being displayed? */
+  DisplayMode m_ForceToDisplay;
+
+  int m_ViewportWidth;
+
+  SnakeParameterPreviewRenderer();
+  virtual ~SnakeParameterPreviewRenderer();
+};
+
+#endif // SNAKEPARAMETERPREVIEWRENDERER_H
diff --git a/GUI/Renderer/SnakeROIRenderer.cxx b/GUI/Renderer/SnakeROIRenderer.cxx
new file mode 100644
index 0000000..65eb745
--- /dev/null
+++ b/GUI/Renderer/SnakeROIRenderer.cxx
@@ -0,0 +1,79 @@
+#include "SnakeROIRenderer.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "GlobalState.h"
+#include "SnakeROIModel.h"
+#include "SNAPAppearanceSettings.h"
+#include "GlobalUIModel.h"
+
+SnakeROIRenderer::SnakeROIRenderer()
+{
+}
+
+void SnakeROIRenderer::paintGL()
+{
+  // Get some global information
+  GenericSliceModel *parentModel = m_ParentRenderer->GetModel();
+  IRISApplication *app = parentModel->GetDriver();
+  GlobalState *gs = app->GetGlobalState();
+  SNAPAppearanceSettings *as =
+      parentModel->GetParentUI()->GetAppearanceSettings();
+
+  // Check the current state
+  assert(m_Model);
+  if(m_ParentRenderer->IsThumbnailDrawing())
+    return;
+
+  // The region of interest should be in effect
+  assert(gs->isSegmentationROIValid());
+
+  // Compute the corners in slice coordinates
+  Vector3f corner[2];
+  m_Model->GetSystemROICorners(corner);
+
+  // Check that the current slice is actually within the bounding box
+  // int slice = m_Parent->m_SliceIndex;
+  int dim = parentModel->GetSliceDirectionInImageSpace();
+  int slice = parentModel->GetSliceIndex();
+  int bbMin = gs->GetSegmentationROI().GetIndex(dim);
+  int bbMax = bbMin + gs->GetSegmentationROI().GetSize(dim);
+
+  // And if so, return without painting anything
+  if(bbMin > slice || bbMax <= slice)
+    return;
+
+  // Get the line color, thickness and dash spacing
+  const OpenGLAppearanceElement *elt =
+      as->GetUIElement(SNAPAppearanceSettings::ROI_BOX);
+
+  // Set line properties
+  glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
+
+  // Apply the line properties
+  elt->ApplyLineSettings();
+
+  // Start drawing the lines
+  glBegin(GL_LINES);
+
+  // Draw each of the edges
+  for(unsigned int dir=0;dir<2;dir++)
+  {
+    for(unsigned int i=0;i<2;i++)
+    {
+    // Select color according to edge state
+    glColor3dv( m_Model->m_Highlight.Highlighted[dir][i] ?
+      elt->GetActiveColor().data_block() : elt->GetNormalColor().data_block() );
+
+    // Compute the vertices of the edge
+    Vector2f x0,x1;
+    m_Model->GetEdgeVertices(dir,i,x0,x1,corner);
+
+    // Draw the line
+    glVertex2f(x0[0],x0[1]);
+    glVertex2f(x1[0],x1[1]);
+    }
+  }
+
+  glEnd();
+  glPopAttrib();
+}
diff --git a/GUI/Renderer/SnakeROIRenderer.h b/GUI/Renderer/SnakeROIRenderer.h
new file mode 100644
index 0000000..7445c75
--- /dev/null
+++ b/GUI/Renderer/SnakeROIRenderer.h
@@ -0,0 +1,27 @@
+#ifndef SNAKEROIRENDERER_H
+#define SNAKEROIRENDERER_H
+
+#include "SNAPCommon.h"
+#include "GenericSliceRenderer.h"
+
+class SnakeROIModel;
+
+class SnakeROIRenderer : public SliceRendererDelegate
+{
+public:
+
+  irisITKObjectMacro(SnakeROIRenderer, SliceRendererDelegate)
+
+  irisGetSetMacro(Model, SnakeROIModel *)
+
+  void paintGL();
+
+protected:
+
+  SnakeROIRenderer();
+  virtual ~SnakeROIRenderer() {}
+
+  SnakeROIModel *m_Model;
+};
+
+#endif // SNAKEROIRENDERER_H
diff --git a/GUI/Renderer/ThresholdSettingsRenderer.cxx b/GUI/Renderer/ThresholdSettingsRenderer.cxx
new file mode 100644
index 0000000..7ddcd6b
--- /dev/null
+++ b/GUI/Renderer/ThresholdSettingsRenderer.cxx
@@ -0,0 +1,115 @@
+#include "ThresholdSettingsRenderer.h"
+#include <vtkChartXY.h>
+#include <vtkPlot.h>
+#include <vtkPlotBar.h>
+#include <vtkFloatArray.h>
+#include <vtkTable.h>
+#include <vtkContextView.h>
+#include <vtkContextScene.h>
+#include <vtkAxis.h>
+#include <SnakeWizardModel.h>
+#include "LayerHistogramPlotAssembly.h"
+#include "ImageWrapperBase.h"
+#include "ScalarImageHistogram.h"
+
+#include <vtkRenderWindow.h>
+#include <vtkRenderWindowInteractor.h>
+#include "vtkGenericOpenGLRenderWindow.h"
+
+const unsigned int ThresholdSettingsRenderer::NUM_POINTS = 256;
+
+ThresholdSettingsRenderer::ThresholdSettingsRenderer()
+  : AbstractVTKSceneRenderer()
+{
+  m_Model = NULL;
+
+  // Set up the scene for rendering
+  m_Chart = vtkSmartPointer<vtkChartXY>::New();
+
+  // Add the chart to the renderer
+  m_ContextView->GetScene()->AddItem(m_Chart);
+
+  // Set up the data
+  m_DataX = vtkSmartPointer<vtkFloatArray>::New();
+  m_DataX->SetName("Grayscale Intensity");
+  m_DataY = vtkSmartPointer<vtkFloatArray>::New();
+  m_DataY->SetName("Speed Image Value");
+
+  // Set up the table
+  m_PlotTable = vtkSmartPointer<vtkTable>::New();
+  m_PlotTable->AddColumn(m_DataX);
+  m_PlotTable->AddColumn(m_DataY);
+  m_PlotTable->SetNumberOfRows(NUM_POINTS);
+
+  // Create the histogram assembly
+  m_HistogramAssembly = new LayerHistogramPlotAssembly();
+  m_HistogramAssembly->AddToChart(m_Chart);
+
+  // Set up the plot
+  m_Plot = m_Chart->AddPlot(vtkChart::LINE);
+  m_Plot->SetInputData(m_PlotTable, 0, 1);
+  m_Plot->SetColor(1, 0, 0);
+  m_Plot->SetWidth(2.0);
+  m_Plot->GetYAxis()->SetBehavior(vtkAxis::FIXED);
+  m_Plot->GetYAxis()->SetMinimum(-0.05);
+  m_Plot->GetYAxis()->SetMaximum(1.05);
+  m_Plot->GetXAxis()->SetTitle("Input image intensity");
+  m_Plot->GetXAxis()->SetBehavior(vtkAxis::FIXED);
+  m_Plot->GetYAxis()->SetTitle("Threshold function");
+
+  // Set the background to white
+  m_BackgroundColor.fill(1.0);
+
+  // Customize the render window
+  this->m_RenderWindow->SetMultiSamples(0);
+  this->m_RenderWindow->SetLineSmoothing(1);
+  this->m_RenderWindow->SetPolygonSmoothing(1);
+}
+
+ThresholdSettingsRenderer::~ThresholdSettingsRenderer()
+{
+  // Create the histogram assembly
+  delete m_HistogramAssembly;
+}
+
+void ThresholdSettingsRenderer::SetModel(SnakeWizardModel *model)
+{
+  this->m_Model = model;
+
+  // Rebroadcast the relevant events from the model in order for the
+  // widget that uses this renderer to cause an update
+  Rebroadcast(model, SnakeWizardModel::ThresholdSettingsUpdateEvent(),
+              ModelUpdateEvent());
+
+  // TODO: We also need to listen to appearance changes....
+}
+
+void ThresholdSettingsRenderer::UpdatePlotValues()
+{
+  if(m_Model->CheckState(SnakeWizardModel::UIF_THESHOLDING_ENABLED))
+    {
+    m_Model->EvaluateThresholdFunction(NUM_POINTS,
+                                       m_DataX->GetPointer(0),
+                                       m_DataY->GetPointer(0));
+
+    ScalarImageWrapperBase *layer = m_Model->GetActiveScalarLayer(PREPROCESS_THRESHOLD);
+    const ScalarImageHistogram *hist = layer->GetHistogram(0);
+    m_HistogramAssembly->PlotWithFixedLimits(hist, 0.0, 1.0);
+
+    m_Plot->GetXAxis()->SetRange(
+          layer->GetImageMinNative() - hist->GetBinWidth(),
+          layer->GetImageMaxNative() + hist->GetBinWidth());
+
+    m_PlotTable->Modified();
+    m_Chart->RecalculateBounds();
+    }
+}
+
+
+void ThresholdSettingsRenderer::OnUpdate()
+{
+  // Update if any events took place
+  this->UpdatePlotValues();
+
+}
+
diff --git a/GUI/Renderer/ThresholdSettingsRenderer.h b/GUI/Renderer/ThresholdSettingsRenderer.h
new file mode 100644
index 0000000..ca7dc53
--- /dev/null
+++ b/GUI/Renderer/ThresholdSettingsRenderer.h
@@ -0,0 +1,47 @@
+#ifndef THRESHOLDSETTINGSRENDERER_H
+#define THRESHOLDSETTINGSRENDERER_H
+
+#include "AbstractVTKSceneRenderer.h"
+#include "vtkSmartPointer.h"
+
+class vtkActor;
+class vtkPropAssembly;
+class vtkChartXY;
+class vtkFloatArray;
+class vtkPlot;
+class vtkTable;
+
+class SnakeWizardModel;
+class LayerHistogramPlotAssembly;
+
+class ThresholdSettingsRenderer : public AbstractVTKSceneRenderer
+{
+public:
+  irisITKObjectMacro(ThresholdSettingsRenderer, AbstractVTKSceneRenderer)
+
+  void SetModel(SnakeWizardModel *model);
+
+  void OnUpdate();
+
+  void UpdatePlotValues();
+protected:
+
+  ThresholdSettingsRenderer();
+  virtual ~ThresholdSettingsRenderer();
+
+  SnakeWizardModel *m_Model;
+
+  // Number of data points
+  static const unsigned int NUM_POINTS;
+
+  // Rendering stuff
+  vtkSmartPointer<vtkChartXY> m_Chart;
+  vtkSmartPointer<vtkTable> m_PlotTable;
+  vtkSmartPointer<vtkPlot> m_Plot;
+  vtkSmartPointer<vtkFloatArray> m_DataX, m_DataY;
+
+  // Histogram rendering
+  LayerHistogramPlotAssembly *m_HistogramAssembly;
+};
+
+#endif // THRESHOLDSETTINGSRENDERER_H
diff --git a/GUI/Renderer/Window3DPicker.cxx b/GUI/Renderer/Window3DPicker.cxx
new file mode 100644
index 0000000..4ff4800
--- /dev/null
+++ b/GUI/Renderer/Window3DPicker.cxx
@@ -0,0 +1,119 @@
+#include "Window3DPicker.h"
+#include "GlobalUIModel.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "ColorLabelTable.h"
+#include "SNAPImageData.h"
+#include "ImageRayIntersectionFinder.h"
+#include "Generic3DModel.h"
+#include "vtkObjectFactory.h"
+
+/** These classes are used internally for m_Ray intersection testing */
+class LabelImageHitTester
+{
+public:
+  LabelImageHitTester(const ColorLabelTable *table = NULL)
+  {
+    m_LabelTable = table;
+  }
+
+  int operator()(LabelType label) const
+  {
+    assert(m_LabelTable);
+    if(m_LabelTable->IsColorLabelValid(label))
+      {
+      const ColorLabel &cl = m_LabelTable->GetColorLabel(label);
+      return (cl.IsVisible() && cl.IsVisibleIn3D()) ? 1 : 0;
+      }
+    else return 0;
+  }
+
+private:
+  const ColorLabelTable *m_LabelTable;
+};
+
+class SnakeImageHitTester
+{
+public:
+  int operator()(float levelSetValue) const
+  {
+    return levelSetValue <= 0 ? 1 : 0;
+  }
+};
+
+
+double Window3DPicker::IntersectWithLine(
+    double pt1[], double pt2[], double tol,
+    vtkAssemblyPath *path, vtkProp3D *prop, vtkAbstractMapper3D *mapper)
+{
+  // This method will be called once for every prop in the Renderer. We only
+  // need to compute the intersection once. So we cache the input point
+  // parameters
+  static Vector3d p1_cache(0.0), p2_cache(0.0);
+  Vector3d p1(pt1), p2(pt2);
+
+  if(p1 == p1_cache && p2 == p2_cache)
+    return VTK_DOUBLE_MAX;
+
+
+  IRISApplication *app = m_Model->GetParentUI()->GetDriver();
+  ImageWrapperBase *main = app->GetCurrentImageData()->GetMain();
+
+  // Transform the points into voxel space
+  Vector3d x0 = main->TransformNIFTICoordinatesToVoxelIndex(Vector3d(p1));
+  Vector3d x1 = main->TransformNIFTICoordinatesToVoxelIndex(Vector3d(p2));
+
+  Vector3i pos;
+  int result = -1;
+  double t = VTK_DOUBLE_MAX;
+
+  // Intersect with the correct wrapper
+  if(app->IsSnakeModeActive() && app->GetSNAPImageData()->IsSnakeLoaded())
+    {
+    typedef ImageRayIntersectionFinder<float, SnakeImageHitTester> RayCasterType;
+    RayCasterType caster;
+
+    result = caster.FindIntersection(
+          app->GetSNAPImageData()->GetSnake()->GetImage(), x0, x1 - x0, pos);
+    }
+  else
+    {
+    LabelImageWrapper *layer = app->GetCurrentImageData()->GetSegmentation();
+    typedef ImageRayIntersectionFinder<LabelType, LabelImageHitTester> Finder;
+    Finder finder;
+    LabelImageHitTester tester(app->GetColorLabelTable());
+    finder.SetHitTester(tester);
+
+    result = finder.FindIntersection(layer->GetImage(), x0, x1 - x0, pos);
+    }
+
+  // Apply
+  if(result > 0)
+    {
+    // Set the cursor position at the right place
+    m_PickSuccessful = true;
+    m_PickPosition = pos;
+
+    // Find the closest point along the ray and return it
+    t = dot_product(x0-x1, x0-to_double(pos)) / dot_product(x0-x1, x0-x1);
+    }
+  else
+    {
+    m_PickSuccessful = false;
+    }
+
+  p1_cache = p1;
+  p2_cache = p2;
+
+  return t;
+}
+
+Window3DPicker::Window3DPicker()
+{
+  m_PickSuccessful = false;
+  m_Model = NULL;
+}
+
+vtkCxxRevisionMacro(Window3DPicker, "$Revision: 1.1 $")
+vtkStandardNewMacro(Window3DPicker)
+
diff --git a/GUI/Renderer/Window3DPicker.h b/GUI/Renderer/Window3DPicker.h
new file mode 100644
index 0000000..eb86663
--- /dev/null
+++ b/GUI/Renderer/Window3DPicker.h
@@ -0,0 +1,34 @@
+#ifndef WINDOW3DPICKER_H
+#define WINDOW3DPICKER_H
+
+#include "vtkPicker.h"
+#include "SNAPCommon.h"
+
+class Generic3DModel;
+
+class Window3DPicker : public vtkPicker
+{
+public:
+  static Window3DPicker *New();
+
+  vtkTypeRevisionMacro(Window3DPicker, vtkPicker)
+
+  irisGetSetMacro(Model, Generic3DModel *)
+
+  irisIsMacro(PickSuccessful)
+
+  irisGetMacro(PickPosition, Vector3i)
+
+protected:
+  virtual double IntersectWithLine(double p1[3], double p2[3], double tol, vtkAssemblyPath *, vtkProp3D *, vtkAbstractMapper3D *);
+
+  Window3DPicker();
+
+  Generic3DModel *m_Model;
+  bool m_PickSuccessful;
+  Vector3i m_PickPosition;
+};
+
+
+
+#endif // WINDOW3DPICKER_H
diff --git a/Logic/Common/ColorLabel.h b/Logic/Common/ColorLabel.h
index 23ef344..f8783f7 100644
--- a/Logic/Common/ColorLabel.h
+++ b/Logic/Common/ColorLabel.h
@@ -36,11 +36,11 @@
 #define __ColorLabel_h_
 
 #include "SNAPCommon.h"
+#include "itkTimeStamp.h"
 
 #include <assert.h>
 #include <list>
     
-
 /**
  * \class ColorLabel
  * \brief Information about a label used for segmentation.
@@ -51,9 +51,21 @@
 class ColorLabel {
 public:
   // Dummy constructor and destructor (to make gcc happy)
-  ColorLabel() {}
+  ColorLabel() { m_TimeStamp.Modified(); }
   virtual ~ColorLabel() {}
 
+  // Copy constructor
+  ColorLabel(const ColorLabel &cl)
+    : m_Label(cl.m_Label), m_Value(cl.m_Value), m_DatabaseId(cl.m_DatabaseId),
+      m_Id(cl.m_Id), m_Visible(cl.m_Visible), m_VisibleIn3D(cl.m_VisibleIn3D),
+      m_UpdateTime(cl.m_UpdateTime), m_Alpha(cl.m_Alpha)
+  {
+    m_RGB[0] = cl.m_RGB[0];
+    m_RGB[1] = cl.m_RGB[1];
+    m_RGB[2] = cl.m_RGB[2];
+    m_TimeStamp = cl.m_TimeStamp;
+  }
+
   // Read the Visible attribute
   irisIsMacro(Visible);
 
@@ -61,10 +73,10 @@ public:
   irisSetMacro(Visible,bool);
 
   // Read the Valid attribute
-  irisIsMacro(Valid);
+  // irisIsMacro(Valid);
 
   // Set the Valid attribute
-  irisSetMacro(Valid,bool);
+  // irisSetMacro(Valid,bool);
 
   // Read the DoMesh attribute
   irisIsMacro(VisibleIn3D);
@@ -111,6 +123,12 @@ public:
     m_RGB[2] = in_Blue;
   }
 
+  // Get the RGB values as a double vector (range 0-1)
+  Vector3d GetRGBAsDoubleVector() const
+  {
+    return Vector3d(m_RGB[0] / 255., m_RGB[1] / 255., m_RGB[2] / 255.);
+  }
+
   // Copy RGB into an array
   void GetRGBVector(unsigned char array[3]) const {
     array[0] = m_RGB[0];
@@ -155,6 +173,9 @@ public:
     m_RGB[2] = lSource.m_RGB[2];
     }
 
+  const itk::TimeStamp &GetTimeStamp() const { return m_TimeStamp; }
+  itk::TimeStamp &GetTimeStamp() { return m_TimeStamp; }
+
 private:
   // The descriptive text of the label
   std::string m_Label;
@@ -178,7 +199,7 @@ private:
   unsigned long m_UpdateTime;
 
   // Whether the label is valid (has been added)
-  bool m_Valid;
+  // bool m_Valid;
 
   // The transparency level of the label
   unsigned char m_Alpha;
@@ -191,6 +212,9 @@ private:
 
   // A list of labels that this label contains
   std::list< unsigned int > m_Children;
+
+  // An itk TimeStamp, allows tracking of changes to the label appearance
+  itk::TimeStamp m_TimeStamp;
 };
 
 
diff --git a/Logic/Common/ColorLabelTable.cxx b/Logic/Common/ColorLabelTable.cxx
index 0283f6e..b8e40b5 100644
--- a/Logic/Common/ColorLabelTable.cxx
+++ b/Logic/Common/ColorLabelTable.cxx
@@ -7,8 +7,32 @@
 
 using namespace std;
 
-extern int fl_parse_color(
-  const char* p, unsigned char& r, unsigned char& g, unsigned char& b);
+int parse_color(
+  const char* p, unsigned char& r, unsigned char& g, unsigned char& b)
+{
+  // Must be a seven-character string
+  if(strlen(p) != 7)
+    return -1;
+
+  int val[6];
+  for(int i = 0; i < 6; i++)
+    {
+    char c = p[i+1];
+    if(c >= 'A' && c <= 'F')
+      val[i] = 10 + (c - 'A');
+    else if(c >= 'a' && c <= 'f')
+      val[i] = 10 + (c - 'a');
+    else if(c >= '0' && c <= '9')
+      val[i] = c - '0';
+    else return -1;
+    }
+
+  r = 16 * val[0] + val[1];
+  g = 16 * val[2] + val[3];
+  b = 16 * val[4] + val[5];
+  return 0;
+}
+
 
 // Some randomly ordered colors
 const size_t ColorLabelTable::m_ColorListSize = 130;
@@ -39,34 +63,6 @@ const char *ColorLabelTable::m_ColorList[ColorLabelTable::m_ColorListSize] = {
 ColorLabelTable
 ::ColorLabelTable()
 {
-  // Initialize the default labels
-  const unsigned int INIT_VALID_LABELS = 7;
-
-  // Set up the clear color
-  m_DefaultLabel[0].SetRGB(0,0,0);
-  m_DefaultLabel[0].SetAlpha(0);
-  m_DefaultLabel[0].SetValid(true);
-  m_DefaultLabel[0].SetVisible(false);
-  m_DefaultLabel[0].SetVisibleIn3D(false);
-  m_DefaultLabel[0].SetLabel("Clear Label");
-
-  // Set the colors from the table
-  for(size_t i = 1; i < MAX_COLOR_LABELS; i++)
-    {
-    unsigned char r,g,b;
-    fl_parse_color(m_ColorList[(i-1) % m_ColorListSize],r,g,b);
-    
-    m_DefaultLabel[i].SetRGB(r,g,b);
-    m_DefaultLabel[i].SetAlpha(255);
-    m_DefaultLabel[i].SetValid(i < INIT_VALID_LABELS);
-    m_DefaultLabel[i].SetVisible(true);
-    m_DefaultLabel[i].SetVisibleIn3D(true);
-
-    IRISOStringStream sout;
-    sout << "Label " << i;
-    m_DefaultLabel[i].SetLabel(sout.str().c_str());
-    }
-
   // Copy default labels to active labels
   InitializeToDefaults();
 }
@@ -80,9 +76,12 @@ ColorLabelTable
   ifstream fin(file);
   string line;
 
-  // Create a temporary array of color labels
-  vector<ColorLabel> xTempLabels;
-  vector<size_t> xTempLabelIds;
+  // Create a temporary map of labels (to discard in case there is a problem
+  // reading the file later)
+  ValidLabelMap inputMap;
+
+  // Set the clear label in the input map
+  inputMap[0] = this->GetDefaultColorLabel(0);
 
   // Check that the file is readable
   if(!fin.good())
@@ -108,7 +107,8 @@ ColorLabelTable
     try 
       {
       // Read in the elements of the file
-      int idx, red, green, blue, visible, mesh;
+      LabelType idx;
+      int red, green, blue, visible, mesh;
       float alpha;
       iss >> idx;
       iss >> red;
@@ -131,7 +131,7 @@ ColorLabelTable
       ColorLabel cl;
 
       // Store the results
-      cl.SetValid(true);
+      // cl.SetValid(true);
       cl.SetRGB(0,(unsigned char) red);
       cl.SetRGB(1,(unsigned char) green);
       cl.SetRGB(2,(unsigned char) blue);
@@ -140,12 +140,13 @@ ColorLabelTable
       cl.SetVisibleIn3D(mesh != 0);
       cl.SetLabel(label);
 
-      // Add the color label to the list
-      xTempLabels.push_back(cl);
-      xTempLabelIds.push_back(idx);
+      // Add the color label to the list, but not zero, because we can't allow
+      // the clear label to be modified.
+      if(idx > 0)
+        inputMap[idx] = cl;
 
       // Clean up the label
-      delete label;      
+      delete label;
       }
     catch( std::exception )
       {
@@ -164,20 +165,17 @@ ColorLabelTable
 
   fin.close();
 
-  // Ok, we should have a list of color labels. Now initalize the color label array
-  // the blank state
-  RemoveAllLabels();
+  // Use the labels that we have loaded
+  m_LabelMap = inputMap;
 
-  // Now, add all the labels
-  for(size_t iLabel = 0; iLabel < xTempLabels.size(); iLabel++)
-    if(xTempLabelIds[iLabel] > 0)
-      SetColorLabel(xTempLabelIds[iLabel], xTempLabels[iLabel]);
+  // Fire the event
+  this->Modified();
+  InvokeEvent(SegmentationLabelConfigurationChangeEvent());
 }
 
-
 void
 ColorLabelTable
-::SaveToFile(const char *file)
+::SaveToFile(const char *file) const
   throw(itk::ExceptionObject)
 {
   // Open the file for writing
@@ -207,21 +205,20 @@ ColorLabelTable
   fout << "################################################"<< endl;
 
   // Print out the labels
-  for(unsigned int i=0;i<MAX_COLOR_LABELS;i++)
+  for(ValidLabelMap::const_iterator it = m_LabelMap.begin();
+      it != m_LabelMap.end(); it++)
     {
-    const ColorLabel &cl = GetColorLabel(i);
-    if(cl.IsValid())
-      {
-      fout << "  "  << right << setw(3) << i;
-      fout << "   " << right << setw(3) << (int) cl.GetRGB(0);
-      fout << "  "  << right << setw(3) << (int) cl.GetRGB(1);
-      fout << "  "  << right << setw(3) << (int) cl.GetRGB(2);
-      fout << "  "  << right << setw(7) 
-        << setprecision(2) << (cl.GetAlpha() / 255.0f);
-      fout << "  "  << right << setw(1) << (cl.IsVisible() ? 1 : 0);
-      fout << "  "  << right << setw(1) << (cl.IsVisibleIn3D() ? 1 : 0);
-      fout << "    \"" << cl.GetLabel() << "\"" << endl;
-      }
+    LabelType index = it->first;
+    const ColorLabel &cl = it->second;
+    fout << "  "  << right << setw(3) << index;
+    fout << "   " << right << setw(3) << (int) cl.GetRGB(0);
+    fout << "  "  << right << setw(3) << (int) cl.GetRGB(1);
+    fout << "  "  << right << setw(3) << (int) cl.GetRGB(2);
+    fout << "  "  << right << setw(7)
+      << setprecision(2) << (cl.GetAlpha() / 255.0f);
+    fout << "  "  << right << setw(1) << (cl.IsVisible() ? 1 : 0);
+    fout << "  "  << right << setw(1) << (cl.IsVisibleIn3D() ? 1 : 0);
+    fout << "    \"" << cl.GetLabel() << "\"" << endl;
     }
 
   fout.close();
@@ -231,8 +228,8 @@ void
 ColorLabelTable
 ::LoadFromRegistry(Registry &registry)
 {
-  // Clear the table of labels
-  RemoveAllLabels();
+  // Clear the table of labels, except the clear label
+  this->RemoveAllLabels();
 
   // Read the number of color labels
   unsigned int nColorLabels = 
@@ -245,21 +242,21 @@ ColorLabelTable
     Registry &folder = registry.Folder(registry.Key("Element[%d]",i));
 
     // Get the index
-    int index = folder["Index"][0];
+    LabelType index = (LabelType) folder["Index"][0];
 
     // If index is valid, proceed to load the label
     if(index > 0 && index < MAX_COLOR_LABELS) 
       {
       // Get current color label 
-      ColorLabel &cl = m_Label[index];
+      ColorLabel cl, def = this->GetDefaultColorLabel(index);
 
       // Read the color label properties
-      cl.SetAlpha(folder["Alpha"][(int) cl.GetAlpha()]);
-      cl.SetLabel(folder["Label"][cl.GetLabel()]);
-      
+      cl.SetAlpha(folder["Alpha"][(int) def.GetAlpha()]);
+      cl.SetLabel(folder["Label"][def.GetLabel()]);
+
       // Read the color property
       Vector3i color = 
-        folder["Color"][Vector3i(cl.GetRGB(0),cl.GetRGB(1),cl.GetRGB(2))];
+        folder["Color"][Vector3i(def.GetRGB(0),def.GetRGB(1),def.GetRGB(2))];
       cl.SetRGB((unsigned char)color[0],(unsigned char)color[1],
                 (unsigned char)color[2]);
       
@@ -267,37 +264,47 @@ ColorLabelTable
       Vector2i flags = folder["Flags"][Vector2i(0,0)];
       cl.SetVisibleIn3D(flags[0] > 0);
       cl.SetVisible(flags[1] > 0);
-      cl.SetValid(true);
+      // cl.SetValid(true);
+
+      // Store
+      m_LabelMap[index] = cl;
       }
     }
+
+  // Fire the event
+  this->Modified();
+  InvokeEvent(SegmentationLabelConfigurationChangeEvent());
 }
 
 void
 ColorLabelTable
-::SaveToRegistry(Registry &registry)
+::SaveToRegistry(Registry &registry) const
 {
   // Write the labels themselves
   unsigned int validLabels = 0;
-  for(unsigned int i=1;i < MAX_COLOR_LABELS; i++)
+
+  for(ValidLabelMap::const_iterator it = m_LabelMap.begin();
+      it != m_LabelMap.end(); it++)
     {
     // Get the i-th color label
-    const ColorLabel &cl = m_Label[i];
-    
-    // Only write valid color labels (otherwise, what's the point?)
-    if(!cl.IsValid()) continue;
-    
-    // Create a folder for the color label
-    Registry &folder = 
-      registry.Folder(registry.Key("Element[%d]",validLabels));    
-    
-    folder["Index"] << i;
-    folder["Alpha"] << (int) cl.GetAlpha();
-    folder["Label"] << cl.GetLabel();
-    folder["Color"] << Vector3i(cl.GetRGB(0),cl.GetRGB(1),cl.GetRGB(2));
-    folder["Flags"] << Vector2i(cl.IsVisibleIn3D(),cl.IsVisible());
-
-    // Increment the valid label counter
-    validLabels++;
+    LabelType id = it->first;
+    if(id > 0)
+      {
+      const ColorLabel &cl = it->second;
+
+      // Create a folder for the color label
+      Registry &folder =
+        registry.Folder(registry.Key("Element[%d]",validLabels));
+
+      folder["Index"] << (int) id;
+      folder["Alpha"] << (int) cl.GetAlpha();
+      folder["Label"] << cl.GetLabel();
+      folder["Color"] << Vector3i(cl.GetRGB(0),cl.GetRGB(1),cl.GetRGB(2));
+      folder["Flags"] << Vector2i(cl.IsVisibleIn3D(),cl.IsVisible());
+
+      // Increment the valid label counter
+      validLabels++;
+      }
     }
 
   registry["NumberOfElements"] << validLabels;
@@ -308,53 +315,181 @@ ColorLabelTable
 ::RemoveAllLabels()
 {
   // Invalidate all the labels
-  for(size_t iLabel = 1; iLabel < MAX_COLOR_LABELS; iLabel++)
-    { m_Label[iLabel].SetValid(false); }
-}
+  m_LabelMap.clear();
+  m_LabelMap[0] = this->GetDefaultColorLabel(0);
 
-size_t
-ColorLabelTable
-::GetFirstValidLabel() const
-{
-  for(size_t iLabel = 1; iLabel < MAX_COLOR_LABELS; iLabel++)
-    if(m_Label[iLabel].IsValid())
-      return iLabel;
-  return 0;
+  // Fire the event
+  this->Modified();
+  InvokeEvent(SegmentationLabelConfigurationChangeEvent());
 }
 
 void
 ColorLabelTable
 ::InitializeToDefaults()
 {
-  // Set the properties of all non-clear labels
-  for (size_t i=0; i<MAX_COLOR_LABELS; i++)
-    m_Label[i] = m_DefaultLabel[i];
+  // Remove all the labels
+  m_LabelMap.clear();
+
+  // Add the first six default labels
+  for(LabelType l = 0; l <= NUM_INITIAL_COLOR_LABELS; l++)
+    {
+    m_LabelMap[l] = this->GetDefaultColorLabel(l);
+    }
+
+  // Fire the event
+  this->Modified();
+  InvokeEvent(SegmentationLabelConfigurationChangeEvent());
 }
 
 
 void 
 ColorLabelTable
-::SetColorLabelValid(size_t id, bool flag)
-  {
+::SetColorLabelValid(LabelType id, bool flag)
+{
   assert(id < MAX_COLOR_LABELS);
+
+  ValidLabelMap::iterator it = m_LabelMap.find(id);
   
-  // Labels that are invalidated are reset to defaults
-  if(!flag && m_Label[id].IsValid())
-    m_Label[id] = m_DefaultLabel[id];
+  if(flag && it == m_LabelMap.end())
+    {
+    // Label is being validated. If it does not exist, insert the default
+    m_LabelMap[id] = this->GetDefaultColorLabel(id);
+    this->Modified();
+    InvokeEvent(SegmentationLabelConfigurationChangeEvent());
+    }
+  else if (!flag && it != m_LabelMap.end())
+    {
+    // The label is being invalidated - just delete it
+    m_LabelMap.erase(it);
+    this->Modified();
+    InvokeEvent(SegmentationLabelConfigurationChangeEvent());
+    }
+}
 
-  // Set the flag
-  m_Label[id].SetValid(flag); 
-  }
+bool
+ColorLabelTable
+::IsColorLabelValid(LabelType id) const
+{
+  assert(id < MAX_COLOR_LABELS);
+  return (m_LabelMap.find(id) != m_LabelMap.end());
+}
 
 
 size_t 
 ColorLabelTable
-::GetNumberOfValidLabels()
+::GetNumberOfValidLabels() const
 {
-  size_t n = 0;
-  for(size_t i = 0; i < MAX_COLOR_LABELS; i++)
-    if(m_Label[i].IsValid())
-      ++n;
-  return n;
+  return m_LabelMap.size();
+}
+
+ColorLabel ColorLabelTable::GetDefaultColorLabel(LabelType id)
+{
+  assert(id < MAX_COLOR_LABELS);
+
+  ColorLabel deflab;
+
+  // Special case of the clear label
+  if(id == 0)
+    {
+    // Set up the clear color
+    deflab.SetRGB(0,0,0);
+    deflab.SetAlpha(0);
+    // deflab.SetValid(true);
+    deflab.SetVisible(false);
+    deflab.SetVisibleIn3D(false);
+    deflab.SetLabel("Clear Label");
+    }
+  else
+    {
+    unsigned char r = 0, g = 0, b = 0;
+    parse_color(m_ColorList[(id-1) % m_ColorListSize],r,g,b);
+
+    deflab.SetRGB(r,g,b);
+    deflab.SetAlpha(255);
+    // deflab.SetValid(true);
+    deflab.SetVisible(true);
+    deflab.SetVisibleIn3D(true);
+
+    IRISOStringStream sout;
+    sout << "Label " << id;
+    deflab.SetLabel(sout.str().c_str());
+    }
+
+  return deflab;
+}
+
+void ColorLabelTable::SetColorLabel(size_t id, const ColorLabel &label)
+{
+  // Find the label
+  ValidLabelMap::iterator it = m_LabelMap.find(id);
+
+  // The current behavior is to make the label valid without the user explicitly
+  // calling the SetValid method
+  if(it == m_LabelMap.end())
+    {
+    m_LabelMap[id] = label;
+    InvokeEvent(SegmentationLabelConfigurationChangeEvent());    
+    }
+  else
+    {
+    it->second = label;
+    it->second.GetTimeStamp().Modified();
+    InvokeEvent(SegmentationLabelPropertyChangeEvent());
+    }
+
+
+
+  this->Modified();
+ }
+
+const ColorLabel ColorLabelTable::GetColorLabel(size_t id) const
+{
+  // If the label exists, return it
+  ValidLabelConstIterator it = m_LabelMap.find(id);
+  if(it == m_LabelMap.end())
+    return this->GetDefaultColorLabel(id);
+  else
+    return it->second;
+}
+
+LabelType ColorLabelTable::GetFirstValidLabel() const
+{
+  if(m_LabelMap.size() > 1)
+    {
+    ValidLabelConstIterator it = m_LabelMap.begin();
+    it++;
+    return it->first;
+    }
+  else return 0;
+}
+
+LabelType ColorLabelTable::GetInsertionSpot(LabelType pos)
+{
+  // Search for an available position
+  for(int i = 0; i < MAX_COLOR_LABELS; i++)
+    {
+    LabelType testpos = (pos + i) % MAX_COLOR_LABELS;
+    if(!this->IsColorLabelValid(testpos))
+      return testpos;
+    }
+
+  // Nothing found - return 0
+  return 0;
+}
+
+LabelType ColorLabelTable::FindNextValidLabel(
+    LabelType pos, bool includeClearInSearch)
+{
+  // Search for an available position. This may be a little inefficient
+  // but this is a rarely used operation.
+  for(int i = 1; i < MAX_COLOR_LABELS; i++)
+    {
+    LabelType testpos = (pos + i) % MAX_COLOR_LABELS;
+    if(IsColorLabelValid(testpos) && (testpos > 0 || includeClearInSearch))
+      return testpos;
+    }
+
+  // Nothing found - return 0
+  return 0;
 }
 
diff --git a/Logic/Common/ColorLabelTable.h b/Logic/Common/ColorLabelTable.h
index a1cf1d7..062e5a5 100644
--- a/Logic/Common/ColorLabelTable.h
+++ b/Logic/Common/ColorLabelTable.h
@@ -38,23 +38,31 @@
 #include "Registry.h"
 #include "ColorLabel.h"
 #include "itkExceptionObject.h"
+#include "itkDataObject.h"
+#include "SNAPEvents.h"
+#include "itkObjectFactory.h"
+#include "itkTimeStamp.h"
 
 /**
  * \class ColorLabelTable
  * \brief A table for managing color labels
  */
-class ColorLabelTable
+class ColorLabelTable : public itk::DataObject
 {
 public:
-  ColorLabelTable();
+  // Standard ITK macros
+  irisITKObjectMacro(ColorLabelTable, Object)
+
+  // Events that we fire
+  FIRES(SegmentationLabelChangeEvent)
 
   // Flat file IO
   void LoadFromFile(const char *file) throw(itk::ExceptionObject);
-  void SaveToFile(const char *file) throw(itk::ExceptionObject);
+  void SaveToFile(const char *file) const throw(itk::ExceptionObject);
 
   // Registry IO
   void LoadFromRegistry(Registry &registry);
-  void SaveToRegistry(Registry &registry);
+  void SaveToRegistry(Registry &registry) const;
 
   /** Initialize the labels to a default state */
   void InitializeToDefaults();
@@ -63,45 +71,76 @@ public:
   void RemoveAllLabels();
 
   /** Get the number of valid color labels */
-  size_t GetNumberOfValidLabels();
-
-  /** Get the i'th label, i between 0 and 255 */
-  const ColorLabel &GetColorLabel(size_t id) const
-    {
-    assert(id < MAX_COLOR_LABELS);
-    return m_Label[id];
-    } 
+  size_t GetNumberOfValidLabels() const;
+
+  /** Get the first valid non-zero color label (or zero if there are none)  */
+  LabelType GetFirstValidLabel() const;
+
+  /**
+    Get the first insertion spot after the specified color label. Return of
+    0 signifies no room left for insertion. The method wraps around the list
+    of labels.
+   */
+  LabelType GetInsertionSpot(LabelType pos);
+
+  /**
+    Find the next valid label, given the selected label. If all else fails,
+    this will return label 0. The method wraps around.
+    */
+  LabelType FindNextValidLabel(LabelType pos, bool includeClearInSearch);
+
+  /**
+    Get the color label corresponding to the given value. If the requested
+    label is not valid, a default value is returned
+  */
+  const ColorLabel GetColorLabel(size_t id) const;
 
   /** Set the i'th color label, i between 0 and 255 */
-  void SetColorLabel(size_t id, const ColorLabel &label)
-    { 
-    assert(id < MAX_COLOR_LABELS);
-    m_Label[id] = label; 
-    }
+  void SetColorLabel(size_t id, const ColorLabel &label);
 
   /** Generate a default color label at index i */
-  ColorLabel GetDefaultColorLabel(size_t id)
-    { 
-    assert(id < MAX_COLOR_LABELS);
-    return m_DefaultLabel[id]; 
-    }
+  static ColorLabel GetDefaultColorLabel(LabelType id);
 
-  bool IsColorLabelValid(size_t id) const
-    { return GetColorLabel(id).IsValid(); }
+  bool IsColorLabelValid(LabelType id) const;
 
   /** Sets the color label valid or invalid. During invalidation, the label
    * reverts to default values */
-  void SetColorLabelValid(size_t id, bool flag);
+  void SetColorLabelValid(LabelType id, bool flag);
+
+  // Map between valid label IDS and label descriptors
+  typedef std::map<LabelType, ColorLabel> ValidLabelMap;
+  typedef ValidLabelMap::const_iterator ValidLabelConstIterator;
+
+  /** Get the iterator over the valid labels */
+  ValidLabelConstIterator begin() const { return m_LabelMap.begin(); }
+  ValidLabelConstIterator end() const { return m_LabelMap.end(); }
 
-  /** Return the first valid color label, or zero if there aren't any */
-  size_t GetFirstValidLabel() const;
+  /** Get the collection of defined/valid labels */
+  const ValidLabelMap &GetValidLabels() const { return m_LabelMap; }
+
+protected:
+
+  ColorLabelTable();
+  virtual ~ColorLabelTable() {}
+
+  // The main data array
+  ValidLabelMap m_LabelMap;
 
-private:
   // A flat array of color labels
-  ColorLabel m_Label[MAX_COLOR_LABELS], m_DefaultLabel[MAX_COLOR_LABELS];
+  // ColorLabel m_Label[MAX_COLOR_LABELS], m_DefaultLabel[MAX_COLOR_LABELS];
 
   static const char *m_ColorList[];
   static const size_t m_ColorListSize;
 };
 
+
+
+
+
+
+
+
+
+
+
 #endif
diff --git a/Logic/Common/ColorMap.cxx b/Logic/Common/ColorMap.cxx
index cc7d453..0e68edd 100644
--- a/Logic/Common/ColorMap.cxx
+++ b/Logic/Common/ColorMap.cxx
@@ -35,6 +35,7 @@
 #include "ColorMap.h"
 #include "IRISException.h"
 #include <algorithm>
+#include <cstdio>
 
 bool
 ColorMap::CMPoint
@@ -55,6 +56,13 @@ ColorMap::CMPoint
   return true;
 }
 
+bool
+ColorMap::CMPoint
+::operator!=(const ColorMap::CMPoint& rhs) const
+{
+  return !(*this == rhs);
+}
+
 ColorMap::CMPoint
 ::CMPoint()
 {
@@ -132,27 +140,25 @@ ColorMap
 ::ColorMap()
 {
   SetToSystemPreset(COLORMAP_GREY);
-}
 
-ColorMap
-::ColorMap(SystemPreset preset)
-{
-  SetToSystemPreset(preset);
+  // Set up the enum map
+  if(!m_ColorMapPresetEnumMap.Size())
+    {
+    for(int i = 0; i <= COLORMAP_CUSTOM; i++)
+      {
+      SystemPreset preset = static_cast<SystemPreset>(i);
+      m_ColorMapPresetEnumMap.AddPair(preset, this->GetPresetName(preset));
+      }
+    }
 }
 
 ColorMap
-::ColorMap(const ColorMap& rhs)
+::~ColorMap()
 {
-  CMPointConstIterator it = rhs.m_CMPoints.begin();
-  m_CMPreset = rhs.m_CMPreset;
-  while (it != rhs.m_CMPoints.end())
-    {
-    m_CMPoints.push_back( *it );
-    ++it;
-    }
-  this->UpdateInterpolants(); 
 }
 
+RegistryEnumMap<ColorMap::SystemPreset> ColorMap::m_ColorMapPresetEnumMap;
+
 bool
 ColorMap
 ::operator==(const ColorMap& rhs) const
@@ -189,6 +195,8 @@ ColorMap
 
   this->UpdateInterpolants(); 
 
+  m_CMPreset = COLORMAP_CUSTOM;
+
   return itnew - m_CMPoints.begin();
 }
 
@@ -229,6 +237,9 @@ ColorMap
         }
       }
     }
+
+  // Update state
+  this->Modified();
 }
 
 ColorMap::RGBAType
@@ -239,8 +250,18 @@ ColorMap
   // are tiny and the overhead of binary search is not worth it
   size_t n = m_CMPoints.size(), lb;
   for(lb = 0; lb < n; lb++)
-    if(j < m_CMPoints[lb].m_Index)
+    {
+    double t = m_CMPoints[lb].m_Index;
+
+    // The right side of this conditional expression is the special case when
+    // j equals to the index in the last control point. In that case we want
+    // to use the left-side value of the last control point, not the right
+    // hand side. Otherwise, the maximum value in the image is treated as
+    // being "outside" of the colormap, and for most colormaps is assigned
+    // a transparent value. That's undesirable
+    if(j < t || (lb == (n-1) && j == t))
       break;
+    }
 
   // Get the interpolants
   const InterpolantData &ic = m_Interpolants[lb];
@@ -256,19 +277,26 @@ ColorMap
 
 void
 ColorMap
-::PrintSelf()
+::PrintSelf(std::ostream & os, itk::Indent indent) const
 {
+  char buffer[256];
   for(size_t i = 0; i < m_CMPoints.size(); i++)
     {
     CMPoint p = m_CMPoints[i];
     if(p.m_Type == CONTINUOUS)
       {
-      printf("%02d-C %7.2f   (%03d %03d %03d %03d)\n", (int) i, p.m_Index, p.m_RGBA[0][0], p.m_RGBA[0][1], p.m_RGBA[0][2], p.m_RGBA[0][3]);
+      sprintf(buffer,
+              "%02d-C %7.2f   (%03d %03d %03d %03d)\n", (int) i, p.m_Index, p.m_RGBA[0][0], p.m_RGBA[0][1], p.m_RGBA[0][2], p.m_RGBA[0][3]);
+      os << indent << buffer;
       }
     else
       {
-      printf("%02d-L %7.2f   (%03d %03d %03d %03d)\n", (int) i, p.m_Index, p.m_RGBA[0][0], p.m_RGBA[0][1], p.m_RGBA[0][2], p.m_RGBA[0][3]);
-      printf("%02d-R %7.2f   (%03d %03d %03d %03d)\n", (int) i, p.m_Index, p.m_RGBA[1][0], p.m_RGBA[1][1], p.m_RGBA[1][2], p.m_RGBA[1][3]);
+      sprintf(buffer,
+             "%02d-L %7.2f   (%03d %03d %03d %03d)\n", (int) i, p.m_Index, p.m_RGBA[0][0], p.m_RGBA[0][1], p.m_RGBA[0][2], p.m_RGBA[0][3]);
+      os << indent << buffer;
+      sprintf(buffer,
+              "%02d-R %7.2f   (%03d %03d %03d %03d)\n", (int) i, p.m_Index, p.m_RGBA[1][0], p.m_RGBA[1][1], p.m_RGBA[1][2], p.m_RGBA[1][3]);
+      os << indent << buffer;
       }
     }
 }
@@ -276,8 +304,14 @@ void
 ColorMap
 ::SetToSystemPreset(SystemPreset preset)
 {
-  m_CMPoints.clear();
   m_CMPreset = preset;
+
+  // Handle the special case of COLORMAP_CUSTOM, in which case we don't mess
+  // mess with the colormap
+  if(preset == COLORMAP_CUSTOM)
+    return;
+
+  m_CMPoints.clear();
   switch(preset)
   {
     case COLORMAP_GREY:
@@ -371,108 +405,201 @@ ColorMap
       m_CMPoints.push_back( CMPoint(1.0,    0x00, 0x00, 0xff, 0xff, 0x00) );
       break;
 
-    case COLORMAP_SIZE:
-      // to suppress compiler warning
-      std::cerr << "COLORMAP_SIZE: should never get there ..." << std::endl;
+    case COLORMAP_SPEED:
+      m_CMPoints.push_back( CMPoint(0.0,    0x00, 0x00, 0xff, 0xff) );
+      m_CMPoints.push_back( CMPoint(0.5,    0x00, 0x00, 0x00, 0xff) );
+      m_CMPoints.push_back( CMPoint(1.0,    0xff, 0xff, 0xff, 0xff) );
+      break;
+
+    case COLORMAP_SPEED_OVERLAY:
+      m_CMPoints.push_back( CMPoint(0.0,    0xff, 0xff, 0xff, 0x00) );
+      m_CMPoints.push_back( CMPoint(0.4,    0xff, 0xff, 0xff, 0x00) );
+      m_CMPoints.push_back( CMPoint(0.6,    0xff, 0x00, 0x00, 0xff) );
+      m_CMPoints.push_back( CMPoint(1.0,    0xff, 0x00, 0x00, 0xff) );
+      break;
+
+    case COLORMAP_LEVELSET:
+      m_CMPoints.push_back( CMPoint(0.0,    0xff, 0x00, 0x00, 0xff) );
+      m_CMPoints.push_back( CMPoint(0.4,    0xff, 0x00, 0x00, 0xff) );
+      m_CMPoints.push_back( CMPoint(0.6,    0xff, 0xff, 0xff, 0x00) );
+      m_CMPoints.push_back( CMPoint(1.0,    0xff, 0xff, 0xff, 0x00) );
+
+    case COLORMAP_CUSTOM:
       break;
    }
 
-  this->UpdateInterpolants(); 
+  this->UpdateInterpolants();
+}
+
+void ColorMap::UpdateCMPoint(size_t j, const ColorMap::CMPoint &p)
+{
+  if(m_CMPoints[j] != p)
+    {
+    m_CMPoints[j] = p;
+    this->UpdateInterpolants();
+    m_CMPreset = COLORMAP_CUSTOM;
+    }
 }
 
+void ColorMap::DeleteCMPoint(size_t j)
+{
+  m_CMPoints.erase(m_CMPoints.begin() + j);
+  this->UpdateInterpolants();
+  m_CMPreset = COLORMAP_CUSTOM;
+}
+
+
 void ColorMap
 ::SaveToRegistry(Registry &reg)
 {
-  // Store the number of control points
-  reg["NumberOfControlPoints"] << m_CMPoints.size();
+  // Save what system preset we are using (if any)
+  reg.Entry("Preset").PutEnum(m_ColorMapPresetEnumMap, m_CMPreset);
 
-  RegistryEnumMap<CMPointType> emap;
-  emap.AddPair(CONTINUOUS,"Continuous");
-  emap.AddPair(DISCONTINUOUS,"Discontinuous");
-
-  // Save each control point
-  for(size_t iPoint = 0; iPoint < m_CMPoints.size(); iPoint++)
+  // For custom colormaps, save them
+  if(m_CMPreset == COLORMAP_CUSTOM)
     {
-    // Get the current values, just in case
-    CMPoint p = m_CMPoints[iPoint];
-
-    // Create a folder in the registry
-    std::string key = reg.Key("ControlPoint[%04d]",iPoint);
-    Registry &folder = reg.Folder(key);
-    folder["Index"] << p.m_Index;
-    folder["Type"].PutEnum(emap, p.m_Type);
-    folder["Left.R"] << (int) p.m_RGBA[0][0];
-    folder["Left.G"] << (int) p.m_RGBA[0][1];
-    folder["Left.B"] << (int) p.m_RGBA[0][2];
-    folder["Left.A"] << (int) p.m_RGBA[0][3];
-    folder["Right.R"] << (int) p.m_RGBA[1][0];
-    folder["Right.G"] << (int) p.m_RGBA[1][1];
-    folder["Right.B"] << (int) p.m_RGBA[1][2];
-    folder["Right.A"] << (int) p.m_RGBA[1][3];
+    // Store the number of control points
+    reg["NumberOfControlPoints"] << m_CMPoints.size();
+
+    RegistryEnumMap<CMPointType> emap;
+    emap.AddPair(CONTINUOUS,"Continuous");
+    emap.AddPair(DISCONTINUOUS,"Discontinuous");
+
+    // Save each control point
+    for(size_t iPoint = 0; iPoint < m_CMPoints.size(); iPoint++)
+      {
+      // Get the current values, just in case
+      CMPoint p = m_CMPoints[iPoint];
+
+      // Create a folder in the registry
+      std::string key = reg.Key("ControlPoint[%04d]",iPoint);
+      Registry &folder = reg.Folder(key);
+      folder["Index"] << p.m_Index;
+      folder["Type"].PutEnum(emap, p.m_Type);
+      folder["Left.R"] << (int) p.m_RGBA[0][0];
+      folder["Left.G"] << (int) p.m_RGBA[0][1];
+      folder["Left.B"] << (int) p.m_RGBA[0][2];
+      folder["Left.A"] << (int) p.m_RGBA[0][3];
+      folder["Right.R"] << (int) p.m_RGBA[1][0];
+      folder["Right.G"] << (int) p.m_RGBA[1][1];
+      folder["Right.B"] << (int) p.m_RGBA[1][2];
+      folder["Right.A"] << (int) p.m_RGBA[1][3];
+      }
     }
 }
 
-
- void ColorMap
+// TODO: the colormap should know if it is in a given system preset or not, and if
+// so, only save the preset name.
+void ColorMap
 ::LoadFromRegistry(Registry &reg)
 {
-  // Store the number of control points
-  size_t n = reg["NumberOfControlPoints"][0];
-  if(n == 0)
-    throw IRISException("Can not read color map. No entries found");
+  // See what system preset we are using (if any)
+  SystemPreset preset =
+      reg.Entry("Preset").GetEnum(m_ColorMapPresetEnumMap, COLORMAP_GREY);
 
-  // Read each control point
-  CMPointList newpts;
+  // If system preset, apply it and we're done
+  if(preset != COLORMAP_CUSTOM)
+    {
+    SetToSystemPreset(preset);
+    }
+  else
+    {
+    // Store the number of control points
+    size_t n = reg["NumberOfControlPoints"][0];
+    if(n == 0)
+      return;
 
-  RegistryEnumMap<CMPointType> emap;
-  emap.AddPair(CONTINUOUS,"Continuous");
-  emap.AddPair(DISCONTINUOUS,"Discontinuous");
+    // Read each control point
+    CMPointList newpts;
 
-  // Save each control point
-  for(size_t iPoint = 0; iPoint < n; iPoint++)
-    {
-    // Get the current values, just in case
-    CMPoint p;
-
-    // Create a folder in the registry
-    std::string key = reg.Key("ControlPoint[%04d]",iPoint);
-    Registry &folder = reg.Folder(key);
-
-    p.m_Index = folder["Index"][-1.0];
-    p.m_Type = folder["Type"].GetEnum(emap, CONTINUOUS);
-    p.m_RGBA[0][0] = (unsigned char) folder["Left.R"][0];
-    p.m_RGBA[0][1] = (unsigned char) folder["Left.G"][0];
-    p.m_RGBA[0][2] = (unsigned char) folder["Left.B"][0];
-    p.m_RGBA[0][3] = (unsigned char) folder["Left.A"][0];
-    if(p.m_Type == CONTINUOUS)
-      {
-      p.m_RGBA[1][0] = p.m_RGBA[0][0];
-      p.m_RGBA[1][1] = p.m_RGBA[0][1];
-      p.m_RGBA[1][2] = p.m_RGBA[0][2];
-      p.m_RGBA[1][3] = p.m_RGBA[0][3];
-      }
-    else
+    RegistryEnumMap<CMPointType> emap;
+    emap.AddPair(CONTINUOUS,"Continuous");
+    emap.AddPair(DISCONTINUOUS,"Discontinuous");
+
+    // Save each control point
+    for(size_t iPoint = 0; iPoint < n; iPoint++)
       {
-      p.m_RGBA[1][0] = (unsigned char) folder["Right.R"][0];
-      p.m_RGBA[1][1] = (unsigned char) folder["Right.G"][0];
-      p.m_RGBA[1][2] = (unsigned char) folder["Right.B"][0];
-      p.m_RGBA[1][3] = (unsigned char) folder["Right.A"][0];
-      }
+      // Get the current values, just in case
+      CMPoint p;
+
+      // Create a folder in the registry
+      std::string key = reg.Key("ControlPoint[%04d]",iPoint);
+      Registry &folder = reg.Folder(key);
+
+      p.m_Index = folder["Index"][-1.0];
+      p.m_Type = folder["Type"].GetEnum(emap, CONTINUOUS);
+      p.m_RGBA[0][0] = (unsigned char) folder["Left.R"][0];
+      p.m_RGBA[0][1] = (unsigned char) folder["Left.G"][0];
+      p.m_RGBA[0][2] = (unsigned char) folder["Left.B"][0];
+      p.m_RGBA[0][3] = (unsigned char) folder["Left.A"][0];
+      if(p.m_Type == CONTINUOUS)
+        {
+        p.m_RGBA[1][0] = p.m_RGBA[0][0];
+        p.m_RGBA[1][1] = p.m_RGBA[0][1];
+        p.m_RGBA[1][2] = p.m_RGBA[0][2];
+        p.m_RGBA[1][3] = p.m_RGBA[0][3];
+        }
+      else
+        {
+        p.m_RGBA[1][0] = (unsigned char) folder["Right.R"][0];
+        p.m_RGBA[1][1] = (unsigned char) folder["Right.G"][0];
+        p.m_RGBA[1][2] = (unsigned char) folder["Right.B"][0];
+        p.m_RGBA[1][3] = (unsigned char) folder["Right.A"][0];
+        }
+
+      // Check validity
+      if(iPoint == 0 && p.m_Index != 0.0)
+        throw IRISException("Can not read color map. First point has non-zero index.");
+
+      if(iPoint == n-1 && p.m_Index != 1.0)
+        throw IRISException("Can not read color map. Last point has index not equal to 1.");
 
-    // Check validity
-    if(iPoint == 0 && p.m_Index != 0.0)
-      throw IRISException("Can not read color map. First point has non-zero index.");
+      if(iPoint > 0 && p.m_Index < newpts[iPoint-1].m_Index)
+        throw IRISException("Can not read color map. Indices are not stored in order.");
 
-    if(iPoint == n-1 && p.m_Index != 1.0)
-      throw IRISException("Can not read color map. Last point has index not equal to 1.");
+      newpts.push_back(p);
+      }
 
-    if(iPoint > 0 && p.m_Index < newpts[iPoint-1].m_Index)
-      throw IRISException("Can not read color map. Indices are not stored in order.");
+    // Got this far? store the new map
+    m_CMPoints = newpts;
+    this->UpdateInterpolants();
 
-    newpts.push_back(p);
+    m_CMPreset = COLORMAP_CUSTOM;
     }
+ }
 
-  // Got this far? store the new map
-  m_CMPoints = newpts;
-  this->UpdateInterpolants();
+void ColorMap::CopyInformation(const itk::DataObject *source)
+{
+  const ColorMap *cm_source = dynamic_cast<const ColorMap *>(source);
+  m_CMPreset = cm_source->m_CMPreset;
+  m_CMPoints = cm_source->m_CMPoints;
+  m_Interpolants = cm_source->m_Interpolants;
+  this->Modified();
 }
+
+ const char * ColorMap::GetPresetName(ColorMap::SystemPreset preset)
+ {
+   static const char *preset_names[] = {
+     "Grayscale",
+     "Jet",
+     "Hot",
+     "Cool",
+     "Black to red",
+     "Black to green",
+     "Black to blue",
+     "Spring",
+     "Summer",
+     "Autumn",
+     "Winter",
+     "Copper",
+     "HSV",
+     "Blue to white to red",
+     "Red to white to blue",
+     "Speed image (blue to black to white)",
+     "Speed image (semi-transparent overlay)",
+     "Level set image",
+     "Custom"
+   };
+
+   return preset_names[preset];
+ }
diff --git a/Logic/Common/ColorMap.h b/Logic/Common/ColorMap.h
index 2b798de..376fb9f 100644
--- a/Logic/Common/ColorMap.h
+++ b/Logic/Common/ColorMap.h
@@ -7,7 +7,7 @@
   Version:   $Revision: 1.7 $
   Copyright (c) 2007 Paul A. Yushkevich
   
-  This file is part of ITK-SNAP 
+  This file is part of ITK-SNAP
 
   ITK-SNAP is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
   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, see <http://www.gnu.org/licenses/>.
 
@@ -29,7 +29,7 @@
 
   This software is distributed WITHOUT ANY WARRANTY; without even
   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
+  PURPOSE.  See the above copyright notices for more information.
 
 =========================================================================*/
 
@@ -39,130 +39,157 @@
 #include "itkRGBAPixel.h"
 #include "Registry.h"
 #include <vector>
+#include "itkDataObject.h"
+#include "itkObjectFactory.h"
+#include "SNAPEvents.h"
 
 /**
  * \class ColorMap
- * \brief This class provides a representation of color maps. 
+ * \brief This class provides a representation of color maps.
  * A color map is a mapping from the interval [0,1] to the RGBA space. The
  * mapping is piecewise continuous. Where it is continuous, it is linear.
  *
  * The color map is represented as an ordered list of points. Each point has
  * an index value (between 0 and 1). CMPoints may be continuous (i.e., the color
- * map is continuous at the point) and discontinuous. A continuous point has 
+ * map is continuous at the point) and discontinuous. A continuous point has
  * one RGBA value, and discontinuous points have two values. In between points,
  * the color map is interpolated linearly.
  */
-class ColorMap 
+class ColorMap : public itk::DataObject
 {
+public:
+
+  irisITKObjectMacro(ColorMap, itk::Object)
+
+  /** RGBA type */
+  typedef unsigned char EltType;
+  typedef itk::RGBAPixel<EltType> RGBAType;
+
+  /** Type of point */
+  enum CMPointType { CONTINUOUS=0, DISCONTINUOUS };
+
+  /** System presets */
+  enum SystemPreset {
+    COLORMAP_GREY = 0,
+    COLORMAP_JET, COLORMAP_HOT, COLORMAP_COOL,
+    COLORMAP_RED, COLORMAP_GREEN, COLORMAP_BLUE,
+    COLORMAP_SPRING, COLORMAP_SUMMER,
+    COLORMAP_AUTUMN, COLORMAP_WINTER, COLORMAP_COPPER, COLORMAP_HSV,
+    COLORMAP_BWR, COLORMAP_RWB, COLORMAP_SPEED, COLORMAP_SPEED_OVERLAY,
+    COLORMAP_LEVELSET,
+    COLORMAP_CUSTOM
+    };
+
+  /** CMPoint representation */
+  class CMPoint
+  {
   public:
 
-    /** RGBA type */
-    typedef unsigned char EltType;
-    typedef itk::RGBAPixel<EltType> RGBAType;
-
-    /** Type of point */
-    enum CMPointType { CONTINUOUS, DISCONTINUOUS };
-
-    /** System presets */
-    enum SystemPreset {
-      COLORMAP_GREY = 0, 
-      COLORMAP_JET, COLORMAP_HOT, COLORMAP_COOL,
-      COLORMAP_RED, COLORMAP_GREEN, COLORMAP_BLUE, 
-      COLORMAP_SPRING, COLORMAP_SUMMER, 
-      COLORMAP_AUTUMN, COLORMAP_WINTER, COLORMAP_COPPER, COLORMAP_HSV, 
-      COLORMAP_BWR, COLORMAP_RWB, COLORMAP_SIZE
-    };
+    double m_Index;
+    CMPointType m_Type;
+    RGBAType m_RGBA[2];
 
-    /** CMPoint representation */
-    class CMPoint 
-    {
-      public:
-      
-        double m_Index;
-        CMPointType m_Type;
-        RGBAType m_RGBA[2];
+    bool operator==(const CMPoint& rhs) const;
+    bool operator!=(const CMPoint& rhs) const;
 
-        bool operator==(const CMPoint& rhs) const;
+    CMPoint();
 
-        CMPoint();
-      
-        // Continuous point
-        CMPoint(double, EltType r, EltType g, EltType b, EltType a);
+    // Continuous point
+    CMPoint(double, EltType r, EltType g, EltType b, EltType a);
 
-        // CMPoint with alpha discontinuity
-        CMPoint(double, EltType r, EltType g, EltType b, EltType a1, EltType a2);
+    // CMPoint with alpha discontinuity
+    CMPoint(double, EltType r, EltType g, EltType b, EltType a1, EltType a2);
 
-        // CMPoint with full discontinuity
-        CMPoint(double, 
-          EltType r1, EltType g1, EltType b1, EltType a1, 
-          EltType r2, EltType g2, EltType b2, EltType a2);
+    // CMPoint with full discontinuity
+    CMPoint(double,
+            EltType r1, EltType g1, EltType b1, EltType a1,
+            EltType r2, EltType g2, EltType b2, EltType a2);
 
-        // CMPoint copy constructor
-        CMPoint(const CMPoint& rhs);
-    };
+    // CMPoint copy constructor
+    CMPoint(const CMPoint& rhs);
+  };
 
-    /** 
+  /**
      * This method maps a value to an RGBA tuple. Values less than 0 and greater
-     * than one are accepted, and are mapped to 0 and 1, respecitively. 
+     * than one are accepted, and are mapped to 0 and 1, respecitively.
      */
-    RGBAType MapIndexToRGBA(double j) const;
+  RGBAType MapIndexToRGBA(double j) const;
 
-    /** This method initializes the color map to one of the system presets */
-    void SetToSystemPreset(SystemPreset preset);
+  /**
+   * This method initializes the color map to one of the system presets. It
+   * is also possible to call this method with COLORMAP_CUSTOM as the parameter,
+   * in which case the colormap itself will be unchanged, but will be treated
+   * as a custom color map.
+   */
+  void SetToSystemPreset(SystemPreset preset);
 
-    size_t GetNumberOfCMPoints()
-      { return m_CMPoints.size(); }
 
-    CMPoint GetCMPoint(size_t j)
-      { return m_CMPoints[j]; }
+  size_t GetNumberOfCMPoints() const
+  { return m_CMPoints.size(); }
 
-    void UpdateCMPoint(size_t j, const CMPoint &p)
-      { m_CMPoints[j] = p; this->UpdateInterpolants(); }
+  CMPoint GetCMPoint(size_t j) const
+  { return m_CMPoints[j]; }
 
-    void DeleteCMPoint(size_t j)
-      { m_CMPoints.erase(m_CMPoints.begin() + j); this->UpdateInterpolants(); }
+  void UpdateCMPoint(size_t j, const CMPoint &p);
 
-    /** 
+  void DeleteCMPoint(size_t j);
+
+  /**
      * This method inserts a new control point, which is interpolated
      * using the values of the existing points
      */
-    size_t InsertInterpolatedCMPoint(double j);
+  size_t InsertInterpolatedCMPoint(double j);
+
+  bool operator==(const ColorMap& rhs) const;
+
+  SystemPreset GetSystemPreset() const
+  { return m_CMPreset; }
+
+  /** Get the name of the system preset */
+  static const char *GetPresetName(SystemPreset preset);
+
+  void PrintSelf(std::ostream & os, itk::Indent indent) const;
 
-    bool operator==(const ColorMap& rhs) const;
+  void SaveToRegistry(Registry &reg);
+  void LoadFromRegistry(Registry &reg);
 
-    SystemPreset GetSystemPreset() const
-      { return m_CMPreset; }
+  /**
+    * Copy the colormap properties from another colormap into the current
+    * colormap.
+    */
+  void CopyInformation(const itk::DataObject *source);
 
-    ColorMap();
+protected:
 
-    ColorMap (SystemPreset preset);
+  ColorMap();
+  virtual ~ColorMap();
 
-    ColorMap (const ColorMap& rhs);
 
-    void PrintSelf();
+private:
 
-    void SaveToRegistry(Registry &reg);
-    void LoadFromRegistry(Registry &reg);
+  ColorMap(const Self&); //purposely not implemented
+  void operator=(const Self&); //purposely not implemented
 
-  private:
+  typedef std::vector<CMPoint> CMPointList;
+  typedef CMPointList::iterator CMPointIterator;
+  typedef CMPointList::const_iterator CMPointConstIterator;
 
-    typedef std::vector<CMPoint> CMPointList;
-    typedef CMPointList::iterator CMPointIterator;
-    typedef CMPointList::const_iterator CMPointConstIterator;
+  // Array of points, which must always be sorted by the index
+  CMPointList m_CMPoints;
 
-    // Array of points, which must always be sorted by the index
-    CMPointList m_CMPoints;
+  // Preset
+  SystemPreset m_CMPreset;
 
-    // Preset
-    SystemPreset m_CMPreset;
+  // Recomputes internal interpolation terms
+  void UpdateInterpolants();
 
-    // Recomputes internal interpolation terms
-    void UpdateInterpolants();
+  struct InterpolantData
+  { float slope[4], intercept[4]; };
+  typedef std::vector<InterpolantData> InterpolantVector;
+  InterpolantVector m_Interpolants;
 
-    struct InterpolantData 
-      { float slope[4], intercept[4]; };
-    typedef std::vector<InterpolantData> InterpolantVector;
-    InterpolantVector m_Interpolants;
+  // Enum for saving presets
+  static RegistryEnumMap<SystemPreset> m_ColorMapPresetEnumMap;
 };
 
 
diff --git a/Logic/Common/ColorMapPresetManager.cxx b/Logic/Common/ColorMapPresetManager.cxx
new file mode 100644
index 0000000..bf6e428
--- /dev/null
+++ b/Logic/Common/ColorMapPresetManager.cxx
@@ -0,0 +1,5 @@
+#include "ColorMapPresetManager.h"
+#include "PresetManager.hxx"
+
+// Insantiate the template
+template class PresetManager<ColorMapPresetTraits>;
diff --git a/Logic/Common/ColorMapPresetManager.h b/Logic/Common/ColorMapPresetManager.h
new file mode 100644
index 0000000..7cc26e8
--- /dev/null
+++ b/Logic/Common/ColorMapPresetManager.h
@@ -0,0 +1,38 @@
+#ifndef COLORMAPPRESETMANAGER_H
+#define COLORMAPPRESETMANAGER_H
+
+#include "ColorMap.h"
+#include "PresetManager.h"
+
+/**
+ * @brief The traits class describing ColorMap for preset management
+ */
+class ColorMapPresetTraits
+{
+public:
+  typedef ColorMap ManagedType;
+  typedef int SystemPresetIterator;
+
+  static std::string GetPresetCategoryName() { return std::string("ColorMaps"); }
+
+  static SystemPresetIterator SystemPresetBegin() { return (int) ColorMap::COLORMAP_GREY; }
+
+  static SystemPresetIterator SystemPresetEnd() { return (int) ColorMap::COLORMAP_CUSTOM; }
+
+  static void SetToSystemPreset(ManagedType *cmap, const SystemPresetIterator &preset)
+    { cmap->SetToSystemPreset((ColorMap::SystemPreset) preset); }
+
+  static std::string GetSystemPresetName(const SystemPresetIterator &preset)
+    { return ColorMap::GetPresetName((ColorMap::SystemPreset) preset); }
+
+  static void ReadFromRegistry(ManagedType *cmap, Registry &folder)
+    { cmap->LoadFromRegistry(folder); }
+
+  static void WriteToRegistry(ManagedType *cmap, Registry &folder)
+    { cmap->SaveToRegistry(folder); }
+};
+
+// The color map preset manager
+typedef PresetManager<ColorMapPresetTraits> ColorMapPresetManager;
+
+#endif // COLORMAPPRESETMANAGER_H
diff --git a/Logic/Common/IRISDisplayGeometry.cxx b/Logic/Common/IRISDisplayGeometry.cxx
new file mode 100644
index 0000000..d2a255f
--- /dev/null
+++ b/Logic/Common/IRISDisplayGeometry.cxx
@@ -0,0 +1,66 @@
+#include "IRISDisplayGeometry.h"
+
+IRISDisplayGeometry::IRISDisplayGeometry()
+{
+  DisplayToAnatomyRAI[0] = "RPS";
+  DisplayToAnatomyRAI[1] = "AIR";
+  DisplayToAnatomyRAI[2] = "RIP";
+}
+
+IRISDisplayGeometry::IRISDisplayGeometry(
+    const std::string &rai0, const std::string &rai1, const std::string &rai2)
+{
+  DisplayToAnatomyRAI[0] = rai0;
+  DisplayToAnatomyRAI[1] = rai1;
+  DisplayToAnatomyRAI[2] = rai2;
+}
+
+IRISDisplayGeometry::IRISDisplayGeometry(const IRISDisplayGeometry &other)
+{
+  DisplayToAnatomyRAI[0] = other.DisplayToAnatomyRAI[0];
+  DisplayToAnatomyRAI[1] = other.DisplayToAnatomyRAI[1];
+  DisplayToAnatomyRAI[2] = other.DisplayToAnatomyRAI[2];
+}
+
+IRISDisplayGeometry &IRISDisplayGeometry::operator =(const IRISDisplayGeometry &other)
+{
+  DisplayToAnatomyRAI[0] = other.DisplayToAnatomyRAI[0];
+  DisplayToAnatomyRAI[1] = other.DisplayToAnatomyRAI[1];
+  DisplayToAnatomyRAI[2] = other.DisplayToAnatomyRAI[2];
+  return *this;
+}
+
+int
+IRISDisplayGeometry
+::GetDisplayWindowForAnatomicalDirection(AnatomicalDirection iAnat) const
+{
+  std::string rai1 = "SRA", rai2 = "ILP";
+  char c1 = rai1[iAnat], c2 = rai2[iAnat];
+  for(int j = 0; j < 3; j++)
+    {
+    char sd = DisplayToAnatomyRAI[j][2];
+    if(sd == c1 || sd == c2)
+      return j;
+    }
+
+  assert(0);
+  return 0;
+}
+
+AnatomicalDirection
+IRISDisplayGeometry
+::GetAnatomicalDirectionForDisplayWindow(int iWin) const
+{
+  char sd = DisplayToAnatomyRAI[iWin][2];
+  if(sd == 'S' || sd == 'I')
+    return ANATOMY_AXIAL;
+  else if (sd == 'R' || sd == 'L')
+    return ANATOMY_SAGITTAL;
+  else if (sd == 'A' || sd == 'P')
+    return ANATOMY_CORONAL;
+
+  assert(0);
+  return(ANATOMY_NONSENSE);
+}
+
+
diff --git a/Logic/Common/IRISDisplayGeometry.h b/Logic/Common/IRISDisplayGeometry.h
new file mode 100644
index 0000000..9f0f479
--- /dev/null
+++ b/Logic/Common/IRISDisplayGeometry.h
@@ -0,0 +1,41 @@
+#ifndef IRISDISPLAYGEOMETRY_H
+#define IRISDISPLAYGEOMETRY_H
+
+#include "SNAPCommon.h"
+
+/**
+ * \class IRISDisplayGeometry
+ * \brief This structure encapsulates the coordinate mapping between
+ * the three orthogonal slices in ITK-SNAP and the patient coordinate system.
+ * It is characterized by three 3-character strings, which define how the
+ * directions in the display space map to the directions in the anatomical
+ * space.
+ */
+struct IRISDisplayGeometry
+{
+  /** Three strings of 3 characters each (RAILPS) defining the mapping */
+  std::string DisplayToAnatomyRAI[3];
+
+  /** Constructor: creates default mapping */
+  IRISDisplayGeometry();
+
+  /** Constructor taking three strings */
+  IRISDisplayGeometry(const std::string &rai0,
+                      const std::string &rai1,
+                      const std::string &rai2);
+
+  /** Copy constructor */
+  IRISDisplayGeometry(const IRISDisplayGeometry &other);
+
+  /** Assignment operator */
+  IRISDisplayGeometry &operator = (const IRISDisplayGeometry &other);
+
+  /** Get the display window corresponding to an anatomical direction */
+  int GetDisplayWindowForAnatomicalDirection(AnatomicalDirection iAnat) const;
+
+  /** Get the anatomical direction in the i-th display window */
+  AnatomicalDirection GetAnatomicalDirectionForDisplayWindow(int iWin) const;
+
+};
+
+#endif // IRISDISPLAYGEOMETRY_H
diff --git a/Logic/Common/ImageCoordinateGeometry.cxx b/Logic/Common/ImageCoordinateGeometry.cxx
index ea7f291..06e0a10 100644
--- a/Logic/Common/ImageCoordinateGeometry.cxx
+++ b/Logic/Common/ImageCoordinateGeometry.cxx
@@ -33,6 +33,15 @@
 
 =========================================================================*/
 #include "ImageCoordinateGeometry.h"
+#include "IRISException.h"
+
+const char ImageCoordinateGeometry::m_RAICodes[3][2] = {
+  {'R', 'L'},
+  {'A', 'P'},
+  {'I', 'S'}};
+
+ImageCoordinateGeometry::AxisDirectionDescriptionMap
+ImageCoordinateGeometry::m_AxisDirectionDescriptionMap;
 
 ImageCoordinateGeometry
 ::ImageCoordinateGeometry()
@@ -42,26 +51,34 @@ ImageCoordinateGeometry
 
 ImageCoordinateGeometry
 ::ImageCoordinateGeometry(DirectionMatrix imageDirection,
-                          std::string displayAnatomyRAICode[3],
+                          const IRISDisplayGeometry &dispGeom,
                           const Vector3ui &imageSize)
 {
-  SetGeometry(imageDirection,displayAnatomyRAICode,imageSize);
+  SetGeometry(imageDirection,dispGeom,imageSize);
 }
 
 
 void
 ImageCoordinateGeometry
 ::SetGeometry(DirectionMatrix imageDirection,
-              std::string displayAnatomyRAICode[3],
+              const IRISDisplayGeometry &dispGeom,
               const Vector3ui &imageSize)
 {
   // Store the image direction matrix
   m_ImageDirectionCosineMatrix = imageDirection; 
 
+  // Keep a copy of the display-to-anatomy geometry
+  m_DisplayGeometry = dispGeom;
+
   // Remap the direction matrix to an RAI code
   std::string imageAnatomyRAICode = 
     ConvertDirectionMatrixToClosestRAICode(m_ImageDirectionCosineMatrix);  
 
+  // Check the code
+  if(!IsRAICodeValid(imageAnatomyRAICode))
+    throw IRISException("Image has an invalid orientation (code %s)",
+                        imageAnatomyRAICode.c_str());
+
   // We can easily compute the image to anatomy transform
   m_ImageToAnatomyTransform.SetTransform(
     ConvertRAIToCoordinateMapping(imageAnatomyRAICode.c_str()),imageSize);
@@ -72,13 +89,15 @@ ImageCoordinateGeometry
   // Compute the anatomy to display transform
   for(unsigned int slice=0;slice < 3;slice++)
     {
+    // Get the display to anatomy RAI code for this slice
+    const char *displayAnatomyRAICode = m_DisplayGeometry.DisplayToAnatomyRAI[slice].c_str();
+
     // Make sure the code is valid
-    assert(IsRAICodeValid(displayAnatomyRAICode[slice].c_str()));
-    
+    assert(IsRAICodeValid(displayAnatomyRAICode));
+
     m_AnatomyToDisplayTransform[slice].SetTransform(
-      InvertMappingVector(
-        ConvertRAIToCoordinateMapping(displayAnatomyRAICode[slice].c_str())),
-      szAnatomy);
+          InvertMappingVector(ConvertRAIToCoordinateMapping(displayAnatomyRAICode)),
+          szAnatomy);
 
     // Compute the combined transform
     m_ImageToDisplayTransform[slice] = 
@@ -92,9 +111,9 @@ ImageCoordinateGeometry
 
 bool 
 ImageCoordinateGeometry
-::IsRAICodeValid(const char *rai)
+::IsRAICodeValid(const std::string &rai)
 {
-  if(rai == NULL)
+  if(rai.size() != 3)
     return false;
 
   // Check the validity of the RAI code - no repetition
@@ -128,9 +147,66 @@ ImageCoordinateGeometry
   return rl && ap && is;
 }
 
+ImageCoordinateGeometry::AxisDirectionDescriptionMap
+&ImageCoordinateGeometry::GetAxisDirectionDescriptionMap()
+{
+  if(m_AxisDirectionDescriptionMap.size() == 0)
+    {
+    m_AxisDirectionDescriptionMap[R_TO_L] = "Right to Left";
+    m_AxisDirectionDescriptionMap[L_TO_R] = "Left to Right";
+    m_AxisDirectionDescriptionMap[A_TO_P] = "Anterior to Posterior";
+    m_AxisDirectionDescriptionMap[P_TO_A] = "Posterior to Anterior";
+    m_AxisDirectionDescriptionMap[I_TO_S] = "Inferior to Superior";
+    m_AxisDirectionDescriptionMap[S_TO_I] = "Superior to Inferior";
+    }
+
+  return m_AxisDirectionDescriptionMap;
+}
+
+ImageCoordinateGeometry::AxisDirection
+ImageCoordinateGeometry::ConvertRAILetterToAxisDirection(char letter)
+{
+  ImageCoordinateGeometry::AxisDirection axisDirection;
+
+  switch(letter)
+    {
+    case 'r' :
+    case 'R' : axisDirection = R_TO_L;break;
+    case 'l' :
+    case 'L' : axisDirection = L_TO_R;break;
+    case 'a' :
+    case 'A' : axisDirection = A_TO_P;break;
+    case 'p' :
+    case 'P' : axisDirection = P_TO_A;break;
+    case 'i' :
+    case 'I' : axisDirection = I_TO_S;break;
+    case 's' :
+    case 'S' : axisDirection = S_TO_I;break;
+    default  : axisDirection = INVALID_DIRECTION;
+    }
+  return(axisDirection);
+}
+
+char ImageCoordinateGeometry
+::ConvertAxisDirectionToRAILetter(ImageCoordinateGeometry::AxisDirection dir)
+{
+  switch(dir)
+    {
+    case R_TO_L: return 'R';
+    case L_TO_R: return 'L';
+    case A_TO_P: return 'A';
+    case P_TO_A: return 'P';
+    case I_TO_S: return 'I';
+    case S_TO_I: return 'S';
+    default:
+      assert(0);
+      return (char) 0;
+    }
+}
+
 Vector3i
 ImageCoordinateGeometry
-::ConvertRAIToCoordinateMapping(const char *rai)
+::ConvertRAIToCoordinateMapping(const std::string &rai)
 {
   assert(IsRAICodeValid(rai));
   
@@ -138,22 +214,8 @@ ImageCoordinateGeometry
 
   for(unsigned int i=0;i<3;i++)
     {
-    switch(rai[i]) 
-      {
-      case 'r' :
-      case 'R' : result[i] =  1;break;
-      case 'l' :
-      case 'L' : result[i] = -1;break;
-      case 'a' :
-      case 'A' : result[i] =  2;break;
-      case 'p' :
-      case 'P' : result[i] = -2;break;
-      case 'i' :
-      case 'I' : result[i] =  3;break;
-      case 's' :
-      case 'S' : result[i] = -3;break;
-      default: assert(0);
-      }
+    result[i] = (int) ConvertRAILetterToAxisDirection(rai[i]);
+    assert(result[i] != INVALID_DIRECTION);
     }
 
   return result;
@@ -191,7 +253,39 @@ ImageCoordinateGeometry
       }
     }
       
-  return rai_out;  
+  return rai_out;
+}
+
+ImageCoordinateGeometry::DirectionMatrix
+ImageCoordinateGeometry::ConvertRAICodeToDirectionMatrix(
+    const std::string &rai)
+{
+  // Check the RAI code
+  assert(IsRAICodeValid(rai.c_str()));
+
+  // An identity matrix, for pulling out rows
+  Matrix3d eye;
+  eye.set_identity();
+
+  // Create the output direction matrix
+  DirectionMatrix dm(3, 3);
+
+  // Apply the RAI code
+  for(size_t i = 0; i < 3; i++)
+    {
+    for(size_t j = 0; j < 3; j++)
+      {
+      for(size_t k = 0; k < 2; k++)
+        {
+        if(toupper(rai[i]) == m_RAICodes[j][k])
+          {
+          dm.set_column(i, (k==0 ? 1.0 : -1.0) * eye.get_row(j));
+          }
+        }
+      }
+    }
+
+  return dm;
 }
 
 bool
diff --git a/Logic/Common/ImageCoordinateGeometry.h b/Logic/Common/ImageCoordinateGeometry.h
index 3fa32ff..b10350f 100644
--- a/Logic/Common/ImageCoordinateGeometry.h
+++ b/Logic/Common/ImageCoordinateGeometry.h
@@ -36,6 +36,9 @@
 #define __ImageCoordinateGeometry_h_
 
 #include "ImageCoordinateTransform.h"
+#include "IRISDisplayGeometry.h"
+#include <map>
+
 
 /**
  * \class ImageCoordinateGeometry
@@ -48,12 +51,25 @@ class ImageCoordinateGeometry
 public:
   typedef vnl_matrix<double> DirectionMatrix;
 
+  /**
+   * @brief Enum describing the directions of image axes in anatomical space
+   */
+  enum AxisDirection {
+    INVALID_DIRECTION = 0,
+    R_TO_L = 1, L_TO_R = -1,
+    A_TO_P = 2, P_TO_A = -2,
+    I_TO_S = 3, S_TO_I = -3
+  };
+
+  /** A map from AxisDirection enum to user readable strings */
+  typedef std::map<AxisDirection, std::string> AxisDirectionDescriptionMap;
+
   /** Constructor initializes geometry with default identity transforms */
   ImageCoordinateGeometry();
 
   /** Constructor that calls GetGeometry */
   ImageCoordinateGeometry(DirectionMatrix imageDirection,
-                          std::string displayAnatomyRAICode[3],
+                          const IRISDisplayGeometry &dispGeom,
                           const Vector3ui &imageSize);
 
   /** Virtual destructor */
@@ -63,42 +79,60 @@ public:
    * RAI codes for the image-anatomy and display-anatomy transforms and the 
    * image size */
   void SetGeometry(DirectionMatrix imageDirection,
-                   std::string displayAnatomyRAICode[3],
+                   const IRISDisplayGeometry &dispGeom,
                    const Vector3ui &imageSize);
 
   /** Get the transform from image to patient coordinate system */
-  irisGetMacro(ImageToAnatomyTransform,const ImageCoordinateTransform &);
+  irisGetMacro(ImageToAnatomyTransform,const ImageCoordinateTransform &)
 
   /** Get the image to anatomy direction matrix */
-  irisGetMacro(ImageDirectionCosineMatrix, DirectionMatrix);
+  irisGetMacro(ImageDirectionCosineMatrix, DirectionMatrix)
 
   /** Get the transform from patient to display coordinate system */
-  const ImageCoordinateTransform & GetAnatomyToDisplayTransform(unsigned int i)
+  const ImageCoordinateTransform & GetAnatomyToDisplayTransform(unsigned int i) const
   {
     return m_AnatomyToDisplayTransform[i];
   }
 
   /** Get the transform from image to display coordinate system */
-  const ImageCoordinateTransform & GetImageToDisplayTransform(unsigned int i)
+  const ImageCoordinateTransform & GetImageToDisplayTransform(unsigned int i) const
   {
     return m_ImageToDisplayTransform[i];
   }
 
   /** Get the transform from display to image coordinate system */  
-  const ImageCoordinateTransform & GetDisplayToImageTransform(unsigned int i)
+  const ImageCoordinateTransform & GetDisplayToImageTransform(unsigned int i) const
   {
     return m_DisplayToImageTransform[i];
   }
 
+  /** Get the display to anatomy RAIs */
+  const std::string & GetDisplayToAnatomyRAI(unsigned int i) const
+  {
+    return m_DisplayGeometry.DisplayToAnatomyRAI[i];
+  }
+
   /** Check an RAI orientation code for validity */
-  static bool IsRAICodeValid(const char *code);
+  static bool IsRAICodeValid(const std::string &rai);
+
+  /** Get the descriptions of the axis directions */
+  static AxisDirectionDescriptionMap &GetAxisDirectionDescriptionMap();
+
+  /** Convert an RAI code letter to a axis direction */
+  static AxisDirection ConvertRAILetterToAxisDirection(char letter);
+
+  /** Convert axis direction to RAI letter */
+  static char ConvertAxisDirectionToRAILetter(AxisDirection dir);
 
   /** Map an RAI code to a mapping vector of positive or negative 1,2,3 */
-  static Vector3i ConvertRAIToCoordinateMapping(const char *code);  
+  static Vector3i ConvertRAIToCoordinateMapping(const std::string &rai);
 
   /** Map ITK direction cosines matrix to the closest RAI code */
   static std::string ConvertDirectionMatrixToClosestRAICode(DirectionMatrix mat);
 
+  /** Map RAI code to an ITK direction cosines matrix */
+  static DirectionMatrix ConvertRAICodeToDirectionMatrix(const std::string &rai);
+
   /** Check if the direction cosines are oblique (not parallel to coord system) */
   static bool IsDirectionMatrixOblique(DirectionMatrix mat);
 
@@ -115,8 +149,17 @@ private:
   ImageCoordinateTransform m_ImageToDisplayTransform[3];
   ImageCoordinateTransform m_DisplayToImageTransform[3];
 
+  // The string representation of the display to anatomy RAI codes
+  IRISDisplayGeometry m_DisplayGeometry;
+
   // Image to anatomy direction matrix
-  DirectionMatrix m_ImageDirectionCosineMatrix;
-  };
+  DirectionMatrix m_ImageDirectionCosineMatrix;  
+
+  // RAI codes
+  static const char m_RAICodes[3][2];
+
+  // The axis direction to string map
+  static AxisDirectionDescriptionMap m_AxisDirectionDescriptionMap;
+};
 
 #endif
diff --git a/Logic/Common/ImageRayIntersectionFinder.h b/Logic/Common/ImageRayIntersectionFinder.h
index 4350ea0..41a3ccc 100644
--- a/Logic/Common/ImageRayIntersectionFinder.h
+++ b/Logic/Common/ImageRayIntersectionFinder.h
@@ -51,7 +51,7 @@ class ImageRayIntersectionFinder
 public:
     virtual ~ImageRayIntersectionFinder() {}
   /** Image type */
-  typedef itk::OrientedImage<TPixel,3> ImageType;
+  typedef itk::Image<TPixel,3> ImageType;
 
   /** Set the hit-test functor to evaluate for hits */
   irisSetMacro(HitTester,THitTester);
diff --git a/Logic/Common/ImageRayIntersectionFinder.txx b/Logic/Common/ImageRayIntersectionFinder.txx
index d8e0ed4..b3a2220 100644
--- a/Logic/Common/ImageRayIntersectionFinder.txx
+++ b/Logic/Common/ImageRayIntersectionFinder.txx
@@ -33,7 +33,7 @@
 
 =========================================================================*/
 
-#include "itkOrientedImage.h"
+#include "itkImage.h"
 
 template <class TPixel, class THitTester>
 int
diff --git a/Logic/Common/LabelUseHistory.cxx b/Logic/Common/LabelUseHistory.cxx
new file mode 100644
index 0000000..a6fa998
--- /dev/null
+++ b/Logic/Common/LabelUseHistory.cxx
@@ -0,0 +1,153 @@
+#include "LabelUseHistory.h"
+#include "ColorLabelTable.h"
+#include <algorithm>
+
+LabelUseHistory::LabelUseHistory()
+{
+  m_History.reserve(this->GetMaximumSize());
+  m_Counter = 0;
+  m_ReconfigureActive = false;
+}
+
+void LabelUseHistory::SetColorLabelTable(ColorLabelTable *clt)
+{
+  m_ColorLabelTable = clt;
+  this->Reset();
+}
+
+void LabelUseHistory::RecordLabelUse(LabelType fore, DrawOverFilter back)
+{
+  // We always want to make sure we are ahead of the label table
+  if(m_ColorLabelTable->GetTimeStamp() > this->GetTimeStamp()
+     && !m_ReconfigureActive)
+    this->OnLabelTableReconfiguration();
+
+  // We should ignore the clear label / draw over all
+  if(fore == 0 && back.CoverageMode == PAINT_OVER_ALL)
+    return;
+
+  // Create an entry
+  Entry p = std::make_pair(fore, back);
+
+  // See if the label is already contained in the table. If it is, we just
+  // update the timestamp on the label in the history, but don't change the
+  // order of any of the entries.
+  for(EntryRecordIter it = m_History.begin(); it != m_History.end(); ++it)
+    {
+    EntryRecord &rec = *it;
+    if(rec.first == p)
+      {
+      rec.second = m_Counter++;
+      return;
+      }
+    }
+
+  // No, the new Entry was not in the history. In this case, we either append
+  // the new entry (if there is room), or replace another entry with it
+
+  // Create an entry record with a time stamp
+  EntryRecord prec = std::make_pair(p, m_Counter++);
+
+  if(m_History.size() < GetMaximumSize())
+    {
+    m_History.push_back(prec);
+    }
+  else
+    {
+    // Search for the oldest element
+    int oldest = 0, pos_oldest = -1;
+    for(int i = 0; i < m_History.size(); ++i)
+      {
+      if(oldest == 0 || m_History[i].second < oldest)
+        {
+        oldest = m_History[i].second;
+        pos_oldest = i;
+        }
+      }
+
+    // Replace the oldest element
+    m_History[pos_oldest] = prec;
+    }
+
+  // As far as the world is concerned, we have been modified
+  this->Modified();
+}
+
+void LabelUseHistory::OnLabelTableReconfiguration()
+{
+  // Avoid recursive calls between this method and RecordLabelUse();
+  m_ReconfigureActive = true;
+
+  // Go through all the labels in the history and make sure they still
+  // exist. If they don't, delete them
+  EntryRecordIter it = m_History.begin();
+  while(it != m_History.end())
+    {
+    Entry p = (*it).first;
+    if(!m_ColorLabelTable->IsColorLabelValid(p.first) ||
+       !m_ColorLabelTable->IsColorLabelValid(p.second.DrawOverLabel))
+      {
+      it = m_History.erase(it);
+      }
+    else
+      ++it;
+    }
+
+  // Now add labels until the list is full
+  ColorLabelTable::ValidLabelConstIterator vlcit = m_ColorLabelTable->begin();
+  while(m_History.size() < GetMaximumSize() && vlcit != m_ColorLabelTable->end())
+    {
+    RecordLabelUse(vlcit->first, DrawOverFilter());
+    ++vlcit;
+    }
+
+  // Modified
+  this->Modified();
+
+  // Avoid recursive calls between this method and RecordLabelUse();
+  m_ReconfigureActive = false;
+}
+
+void LabelUseHistory::Reset()
+{
+  // Clear history
+  m_History.clear();
+
+  // Add labels until the list is full
+  ColorLabelTable::ValidLabelConstIterator vlcit = m_ColorLabelTable->begin();
+  while(m_History.size() < GetMaximumSize() && vlcit != m_ColorLabelTable->end())
+    {
+    // We don't add the clear label to the history
+    if(vlcit->first != 0)
+      {
+      Entry p = std::make_pair(vlcit->first, DrawOverFilter());
+      m_History.push_back(std::make_pair(p, m_Counter++));
+      }
+
+    ++vlcit;
+    }
+
+  this->Modified();
+}
+
+int LabelUseHistory::GetSize()
+{
+  // We always want to make sure we are ahead of the label table
+  if(m_ColorLabelTable->GetTimeStamp() > this->GetTimeStamp())
+    this->OnLabelTableReconfiguration();
+
+  return m_History.size();
+}
+
+const LabelUseHistory::Entry &LabelUseHistory::GetHistoryEntry(int i)
+{
+  // We always want to make sure we are ahead of the label table
+  if(m_ColorLabelTable->GetTimeStamp() > this->GetTimeStamp())
+    this->OnLabelTableReconfiguration();
+
+  return m_History[i].first;
+}
+
+
+
+
diff --git a/Logic/Common/LabelUseHistory.h b/Logic/Common/LabelUseHistory.h
new file mode 100644
index 0000000..5ee07e7
--- /dev/null
+++ b/Logic/Common/LabelUseHistory.h
@@ -0,0 +1,73 @@
+#ifndef LABELUSEHISTORY_H
+#define LABELUSEHISTORY_H
+
+#include <utility>
+#include <vector>
+#include "SNAPCommon.h"
+#include <itkDataObject.h>
+#include <itkObjectFactory.h>
+
+class ColorLabelTable;
+
+
+/**
+ * This class keeps track of the labels used during segmentation. It should
+ * be updated whenever a new set of labels is used, and cleared when a new
+ * label set is loaded.
+ */
+class LabelUseHistory : public itk::DataObject
+{
+public:
+  irisITKObjectMacro(LabelUseHistory, DataObject)
+
+  /** Type describing a foreground/background combination */
+  typedef std::pair<LabelType, DrawOverFilter> Entry;
+
+  /** Initialize to refer to a label table */
+  void SetColorLabelTable(ColorLabelTable *clt);
+
+  /** Record that a pair of labels has been used, i.e., to update segmentation */
+  void RecordLabelUse(LabelType fore, DrawOverFilter back);
+
+  /** Reset completely (initialize to use the first K labels) */
+  void Reset();
+
+  /** Get the number of labels in history (limited by max) */
+  int GetSize();
+
+  /** Get the maximum number of entries (hard-coded) */
+  static int GetMaximumSize() { return 6; }
+
+  /** Get the n-th entry */
+  const Entry &GetHistoryEntry(int i);
+
+protected:
+
+  LabelUseHistory();
+  ~LabelUseHistory() {}
+
+  // Data structure keeping track of the labels
+  typedef std::pair<Entry, unsigned long> EntryRecord;
+
+  // The list of records
+  typedef std::vector<EntryRecord> EntryRecordList;
+  typedef EntryRecordList::iterator EntryRecordIter;
+  typedef EntryRecordList::const_iterator EntryRecordCIter;
+
+  // The actual list
+  EntryRecordList m_History;
+
+  // Pointer to the color label table
+  ColorLabelTable *m_ColorLabelTable;
+
+  // Flag to prevent infinite recursion
+  bool m_ReconfigureActive;
+
+  // A timestamp counter - updated each time RecordLabelUse is called
+  unsigned long m_Counter;
+
+  /** When the label table changes (labels added, deleted), update */
+  void OnLabelTableReconfiguration();
+};
+
+#endif // LABELUSEHISTORY_H
diff --git a/Logic/Common/MetaDataAccess.cxx b/Logic/Common/MetaDataAccess.cxx
new file mode 100644
index 0000000..1cb7ba5
--- /dev/null
+++ b/Logic/Common/MetaDataAccess.cxx
@@ -0,0 +1,159 @@
+#include "MetaDataAccess.h"
+#include <itkImageBase.h>
+#include <itkMetaDataDictionary.h>
+#include <itkMetaDataObject.h>
+#include <itkGDCMImageIO.h>
+#include <iostream>
+#include <map>
+
+using namespace itk;
+using namespace std;
+
+MetaDataAccess::MetaDataAccess(itk::ImageBase<3> *image)
+{
+  m_Image = image;
+}
+
+
+std::vector<std::string> MetaDataAccess::GetKeysAsArray()
+{
+  return m_Image->GetMetaDataDictionary().GetKeys();
+}
+
+template<class AnyType>
+bool
+try_get_metadata(itk::MetaDataDictionary &mdd,
+                 const string &key, string &output, AnyType deflt)
+{
+  AnyType v = deflt;
+  if(itk::ExposeMetaData<AnyType>(mdd, key, v))
+    {
+    ostringstream oss;
+    oss << v << endl;
+    output = oss.str();
+    return true;
+    }
+  else return false;
+}
+
+std::string MetaDataAccess::GetValueAsString(const std::string &key)
+{
+  std::string value;
+  itk::MetaDataDictionary &mdd = m_Image->GetMetaDataDictionary();
+
+  // Orientation flag object
+  itk::SpatialOrientation::ValidCoordinateOrientationFlags v_oflags =
+    itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_INVALID;
+
+  // Is the value a string?
+  if(itk::ExposeMetaData<string>(mdd, key, value))
+    {
+    // For some weird reason, some of the strings returned by this method
+    // contain '\0' characters. We will replace them by spaces
+    ostringstream sout("");
+    for(unsigned int i=0;i<value.length();i++)
+      if(value[i] >= ' ') sout << value[i];
+    value = sout.str();
+
+    // Make sure the value has more than blanks
+    if(value.find_first_not_of(" ") == string::npos)
+      value="";
+    }
+  else if(itk::ExposeMetaData(mdd, key, v_oflags))
+    {
+    value = GetRAICode(v_oflags);
+    }
+  else
+    {
+    bool rc = false;
+    if(!rc) rc |= try_get_metadata<double>(mdd, key, value, 0);
+    if(!rc) rc |= try_get_metadata<float>(mdd, key, value, 0);
+    if(!rc) rc |= try_get_metadata<int>(mdd, key, value, 0);
+    if(!rc) rc |= try_get_metadata<unsigned int>(mdd, key, value, 0);
+    if(!rc) rc |= try_get_metadata<long>(mdd, key, value, 0);
+    if(!rc) rc |= try_get_metadata<unsigned long>(mdd, key, value, 0);
+    if(!rc) rc |= try_get_metadata<short>(mdd, key, value, 0);
+    if(!rc) rc |= try_get_metadata<unsigned short>(mdd, key, value, 0);
+    if(!rc) rc |= try_get_metadata<char>(mdd, key, value, 0);
+    if(!rc) rc |= try_get_metadata<unsigned char>(mdd, key, value, 0);
+
+    if(!rc)
+      {
+      ostringstream oss;
+      oss << "Object of type "
+        << mdd[key]->GetMetaDataObjectTypeName();
+      value = oss.str();
+      }
+    }
+
+  return value;
+}
+
+std::string MetaDataAccess::MapKeyToDICOM(std::string key)
+{
+  // Try to remap the key to DICOM
+  string dcm_label;
+  if(itk::GDCMImageIO::GetLabelFromTag(key, dcm_label))
+    return dcm_label;
+  else
+    return key;
+}
+
+
+std::string MetaDataAccess::GetRAICode(
+    itk::SpatialOrientation::ValidCoordinateOrientationFlags code)
+  {
+  std::map<itk::SpatialOrientation::ValidCoordinateOrientationFlags, string> cmap;
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RIP] = "RIP";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LIP] = "LIP";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RSP] = "RSP";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LSP] = "LSP";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RIA] = "RIA";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LIA] = "LIA";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RSA] = "RSA";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LSA] = "LSA";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IRP] = "IRP";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ILP] = "ILP";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SRP] = "SRP";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SLP] = "SLP";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IRA] = "IRA";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ILA] = "ILA";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SRA] = "SRA";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SLA] = "SLA";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RPI] = "RPI";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LPI] = "LPI";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAI] = "RAI";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LAI] = "LAI";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RPS] = "RPS";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LPS] = "LPS";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAS] = "RAS";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LAS] = "LAS";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PRI] = "PRI";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PLI] = "PLI";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ARI] = "ARI";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ALI] = "ALI";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PRS] = "PRS";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PLS] = "PLS";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ARS] = "ARS";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ALS] = "ALS";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IPR] = "IPR";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SPR] = "SPR";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IAR] = "IAR";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SAR] = "SAR";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IPL] = "IPL";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SPL] = "SPL";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IAL] = "IAL";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SAL] = "SAL";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PIR] = "PIR";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PSR] = "PSR";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIR] = "AIR";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ASR] = "ASR";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PIL] = "PIL";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PSL] = "PSL";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIL] = "AIL";
+  cmap[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ASL] = "ASL";
+  return cmap[code];
+}
+
+
+
diff --git a/Logic/Common/MetaDataAccess.h b/Logic/Common/MetaDataAccess.h
new file mode 100644
index 0000000..408f39a
--- /dev/null
+++ b/Logic/Common/MetaDataAccess.h
@@ -0,0 +1,35 @@
+#ifndef METADATAACCESS_H
+#define METADATAACCESS_H
+
+#include <SNAPCommon.h>
+#include <itkSpatialOrientation.h>
+#include <string>
+#include <vector>
+
+namespace itk
+{
+template <unsigned int VDim> class ImageBase;
+}
+
+class MetaDataAccess
+{
+public:
+  MetaDataAccess(itk::ImageBase<3> *image);
+
+  std::vector<std::string> GetKeysAsArray();
+  std::string GetValueAsString(const std::string &key);
+
+  // Useful routine for mapping orientation strings to text
+  static std::string GetRAICode(
+      itk::SpatialOrientation::ValidCoordinateOrientationFlags code);
+
+  // Another utility for mapping keys via DICOM dictionary
+  static std::string MapKeyToDICOM(std::string key);
+
+private:
+  itk::ImageBase<3> *m_Image;
+
+
+};
+
+#endif // METADATAACCESS_H
diff --git a/Logic/Common/SNAPAppearanceSettings.cxx b/Logic/Common/SNAPAppearanceSettings.cxx
new file mode 100644
index 0000000..c51cc98
--- /dev/null
+++ b/Logic/Common/SNAPAppearanceSettings.cxx
@@ -0,0 +1,401 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: SNAPAppearanceSettings.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/19 20:28:56 $
+  Version:   $Revision: 1.13 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 of the License, or
+  (at your option) any later version.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even 
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     PURPOSE.  See the above copyright notices for more information.
+=========================================================================*/
+#include "SNAPAppearanceSettings.h"
+#include "Registry.h"
+
+#include <SNAPOpenGL.h>
+
+using namespace std;
+
+// Columns: NORMAL_COLOR, ACTIVE_COLOR, LINE_THICKNESS, DASH_SPACING, 
+//          FONT_SIZE,    VISIBLE,      ALPHA_BLEND,    FEATURE_COUNT
+const int 
+SNAPAppearanceSettings
+::m_Applicable[SNAPAppearanceSettings::ELEMENT_COUNT][OpenGLAppearanceElement::FEATURE_COUNT] = {
+    { 1, 0, 1, 1, 0, 1, 1 },    // Crosshairs
+    { 1, 0, 0, 0, 1, 1, 1 },    // Markers
+    { 1, 1, 1, 1, 0, 0, 1 },    // ROI
+    { 1, 0, 0, 0, 0, 0, 0 },    // Slice Background
+    { 1, 0, 0, 0, 0, 0, 0 },    // 3D Background
+    { 1, 1, 1, 1, 0, 1, 1 },    // Zoom thumbnail
+    { 1, 0, 1, 1, 0, 1, 1 },    // 3D Crosshairs
+    { 1, 0, 1, 1, 0, 1, 1 },    // Thumbnail Crosshairs
+    { 1, 1, 1, 1, 0, 1, 1 },    // 3D Image Box
+    { 1, 1, 1, 1, 0, 1, 1 },    // 3D ROI Box
+    { 1, 1, 1, 1, 0, 1, 1 },    // Paintbrush outline
+    { 1, 0, 1, 0, 1, 1, 1 },    // Rulers
+    { 1, 0, 1, 1, 0, 0, 1 },    // POLY_DRAW_MAIN
+    { 1, 0, 1, 1, 0, 1, 1 },    // POLY_DRAW_CLOSE
+    { 1, 1, 1, 1, 0, 0, 1 }     // POLY_EDIT
+    };
+
+void 
+SNAPAppearanceSettings
+::InitializeDefaultSettings()
+{
+  // Initialize all the elements
+  for(int i = 0; i < ELEMENT_COUNT; i++)
+    {
+    m_DefaultElementSettings[i] = OpenGLAppearanceElement::New();
+    m_DefaultElementSettings[i]->SetValid(m_Applicable[i]);
+    }
+
+  // An element pointer for setting properties
+  OpenGLAppearanceElement *elt;
+  
+  // Crosshairs
+  elt = m_DefaultElementSettings[CROSSHAIRS];
+  elt->SetNormalColor(Vector3d(0.3, 0.3, 1.0));
+  elt->SetActiveColor(Vector3d(0.0, 0.0, 0.0));
+  elt->SetLineThickness(1.0);
+  elt->SetDashSpacing(1.0);
+  elt->SetFontSize(0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(false);
+
+  // Markers
+  elt = m_DefaultElementSettings[MARKERS];
+  elt->SetNormalColor(Vector3d(1.0, 0.75, 0.0));
+  elt->SetActiveColor(Vector3d(0.0, 0.0, 0.0));
+  elt->SetLineThickness(0.0);
+  elt->SetDashSpacing(0.0);
+  elt->SetFontSize(16);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(false);
+
+  // ROI
+  elt = m_DefaultElementSettings[ROI_BOX];
+  elt->SetNormalColor(Vector3d(1.0, 0.0, 0.2));
+  elt->SetActiveColor(Vector3d(1.0, 1.0, 0.2));
+  elt->SetLineThickness(1.0);
+  elt->SetDashSpacing(3.0);
+  elt->SetFontSize(0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(false);
+
+  // Slice background
+  elt = m_DefaultElementSettings[BACKGROUND_3D];
+  elt->SetNormalColor(Vector3d(0.0, 0.0, 0.0));
+  elt->SetActiveColor(Vector3d(0.0, 0.0, 0.0));
+  elt->SetLineThickness(0.0);
+  elt->SetDashSpacing(0.0);
+  elt->SetFontSize(0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(false);
+
+  // 3D Window background
+  elt = m_DefaultElementSettings[BACKGROUND_3D];
+  elt->SetNormalColor(Vector3d(0.0, 0.0, 0.0));
+  elt->SetActiveColor(Vector3d(0.0, 0.0, 0.0));
+  elt->SetLineThickness(0.0);
+  elt->SetDashSpacing(0.0);
+  elt->SetFontSize(0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(false);
+
+  // Zoom thumbail
+  elt = m_DefaultElementSettings[ZOOM_THUMBNAIL];
+  elt->SetNormalColor(Vector3d(1.0, 1.0, 0.0));
+  elt->SetActiveColor(Vector3d(1.0, 1.0, 1.0));
+  elt->SetLineThickness(1.0);
+  elt->SetDashSpacing(0.0);
+  elt->SetFontSize(0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(false);
+
+  // 3D crosshairs
+  elt = m_DefaultElementSettings[CROSSHAIRS_3D];
+  elt->SetNormalColor(Vector3d(0.3, 0.3, 1.0));
+  elt->SetActiveColor(Vector3d(0.0, 0.0, 0.0));
+  elt->SetLineThickness(1.0);
+  elt->SetDashSpacing(1.0);
+  elt->SetFontSize(0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(true);
+
+  // Thumbnail crosshairs
+  elt = m_DefaultElementSettings[CROSSHAIRS_THUMB];
+  elt->SetNormalColor(Vector3d(0.3, 0.3, 1.0));
+  elt->SetActiveColor(Vector3d(0.0, 0.0, 0.0));
+  elt->SetLineThickness(1.0);
+  elt->SetDashSpacing(1.0);
+  elt->SetFontSize(0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(false);
+
+  // Thumbnail crosshairs
+  elt = m_DefaultElementSettings[IMAGE_BOX_3D];
+  elt->SetNormalColor(Vector3d(0.2, 0.2, 0.2));
+  elt->SetActiveColor(Vector3d(0.4, 0.4, 0.4));
+  elt->SetLineThickness(1.0);
+  elt->SetDashSpacing(1.0);
+  elt->SetFontSize(0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(false);
+
+  // Thumbnail crosshairs
+  elt = m_DefaultElementSettings[ROI_BOX_3D];
+  elt->SetNormalColor(Vector3d(1.0, 0.0, 0.2));
+  elt->SetActiveColor(Vector3d(1.0, 1.0, 0.2));
+  elt->SetLineThickness(1.0);
+  elt->SetDashSpacing(3.0);
+  elt->SetFontSize(0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(false);
+   
+  // Paintbrush outline
+  elt = m_DefaultElementSettings[PAINTBRUSH_OUTLINE];
+  elt->SetNormalColor(Vector3d(1.0, 0.0, 0.2));
+  elt->SetActiveColor(Vector3d(1.0, 1.0, 0.2));
+  elt->SetLineThickness(1.0);
+  elt->SetDashSpacing(1.0);
+  elt->SetFontSize(0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(false);
+
+  // Markers
+  elt = m_DefaultElementSettings[RULER];
+  elt->SetNormalColor(Vector3d(0.3, 1.0, 0.0));
+  elt->SetActiveColor(Vector3d(0.0, 0.0, 0.0));
+  elt->SetLineThickness(1.0);
+  elt->SetDashSpacing(0.0);
+  elt->SetFontSize(12);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(true);
+
+  // Polygon outline (drawing)
+  elt = m_DefaultElementSettings[POLY_DRAW_MAIN];
+  elt->SetNormalColor(Vector3d(1.0, 0.0, 0.5));
+  elt->SetActiveColor(Vector3d(1.0, 0.8, 0.9));
+  elt->SetLineThickness(2.0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(true);
+
+  // Polygon outline (drawing)
+  elt = m_DefaultElementSettings[POLY_DRAW_CLOSE];
+  elt->SetNormalColor(Vector3d(1.0, 0.0, 0.5));
+  elt->SetActiveColor(Vector3d(1.0, 0.8, 0.9));
+  elt->SetLineThickness(2.0);
+  elt->SetVisible(false);
+  elt->SetDashSpacing(1.0);
+  elt->SetAlphaBlending(true);
+
+  // Polygon outline (editing)
+  elt = m_DefaultElementSettings[POLY_EDIT];
+  elt->SetNormalColor(Vector3d(1.0, 0.0, 0.0));
+  elt->SetActiveColor(Vector3d(0.0, 1.0, 0.0));
+  elt->SetLineThickness(2.0);
+  elt->SetVisible(true);
+  elt->SetAlphaBlending(true);
+}
+
+const char *
+SNAPAppearanceSettings
+::m_ElementNames[SNAPAppearanceSettings::ELEMENT_COUNT] = 
+  { "CROSSHAIRS", "MARKERS", "ROI_BOX", "BACKGROUND_2D", "BACKGROUND_3D", 
+    "ZOOM_THUMBNAIL", "CROSSHAIRS_3D", "CROSSHAIRS_THUMB", "IMAGE_BOX_3D",
+    "ROI_BOX_3D", "RULER", "PAINTBRUSH_OUTLINE", 
+    "POLY_DRAW_MAIN", "POLY_DRAW_CLOSE", "POLY_EDIT"};
+
+SNAPAppearanceSettings
+::SNAPAppearanceSettings()
+{
+  // Initialize the default settings the first time this method is called
+  InitializeDefaultSettings();
+
+  // Set the UI elements to their default values  
+  for(unsigned int iElement = 0; iElement < ELEMENT_COUNT; iElement++)
+    {
+    // Create the elements
+    m_Elements[iElement] = OpenGLAppearanceElement::New();
+    m_Elements[iElement]->DeepCopy(m_DefaultElementSettings[iElement]);
+
+    // Rebroadcast modification events from the elements
+    Rebroadcast(m_Elements[iElement], ChildPropertyChangedEvent(), ChildPropertyChangedEvent());
+    }
+
+  // Initial visibility is true
+  m_OverallVisibilityModel = NewSimpleConcreteProperty(true);
+}
+
+void
+SNAPAppearanceSettings
+::LoadFromRegistry(Registry &r)
+{
+
+  // Overall visibility is not saved or loaded (it's a temprary setting)
+
+  // Load the user interface elements
+  for(unsigned int iElement = 0; iElement < ELEMENT_COUNT; iElement++)
+    {
+    // Create a folder to hold the element
+    Registry& f = r.Folder( 
+      r.Key("UserInterfaceElement[%s]", m_ElementNames[iElement]) );
+
+    m_Elements[iElement]->ReadFromRegistry(f);
+    }
+}
+
+void
+SNAPAppearanceSettings
+::SaveToRegistry(Registry &r)
+{
+  // Save each of the screen elements
+  for(unsigned int iElement = 0; iElement < ELEMENT_COUNT; iElement++)
+    {
+    // Create a folder to hold the element
+    Registry& f = r.Folder( 
+      r.Key("UserInterfaceElement[%s]", m_ElementNames[iElement]) );
+
+    // Get the default element
+    m_Elements[iElement]->WriteToRegistry(f);
+    }
+}
+
+GlobalDisplaySettings::GlobalDisplaySettings()
+{
+  // This is needed to read enum of interpolation modes from registry
+  RegistryEnumMap<UIGreyInterpolation> emap_interp;
+  emap_interp.AddPair(NEAREST,"NearestNeighbor");
+  emap_interp.AddPair(LINEAR,"Linear");
+
+  // This is needed to read 2D view layout enums
+  RegistryEnumMap<UISliceLayout> emap_layout;
+  emap_layout.AddPair(LAYOUT_ASC,"ASC");
+  emap_layout.AddPair(LAYOUT_ACS,"ACS");
+  emap_layout.AddPair(LAYOUT_SAC,"SAC");
+  emap_layout.AddPair(LAYOUT_SCA,"SCA");
+  emap_layout.AddPair(LAYOUT_CAS,"CAS");
+  emap_layout.AddPair(LAYOUT_CSA,"CSA");
+
+  // Set the common flags
+  m_FlagDisplayZoomThumbnailModel =
+      NewSimpleProperty("FlagDisplayZoomThumbnail", true);
+
+  m_ZoomThumbnailMaximumSizeModel =
+      NewRangedProperty("ZoomThumbnailMaximumSize", 160, 40, 400, 10);
+
+  m_ZoomThumbnailSizeInPercentModel =
+      NewRangedProperty("ZoomThumbnailSizeInPercent", 30.0, 5.0, 50.0, 1.0);
+
+  m_GreyInterpolationModeModel =
+      NewSimpleEnumProperty("GreyInterpolationMode", NEAREST, emap_interp);
+
+  m_SliceLayoutModel =
+      NewSimpleEnumProperty("SliceLayout", LAYOUT_ASC, emap_layout);
+
+  m_FlagLayoutPatientAnteriorShownLeftModel =
+      NewSimpleProperty("FlagLayoutPatientAnteriorShownLeft", true);
+
+  m_FlagLayoutPatientRightShownLeftModel =
+      NewSimpleProperty("FlagLayoutPatientRightShownLeft", true);
+
+}
+
+void GlobalDisplaySettings
+::GetAnatomyToDisplayTransforms(string &rai1, string &rai2, string &rai3) const
+{
+  unsigned int order[6][3] =
+    {{0,1,2},{0,2,1},{1,0,2},{1,2,0},{2,0,1},{2,1,0}};
+
+  // Start with stock orientations
+  string axes[3] = {string("RPS"),string("AIL"),string("RIP")};
+
+  // Switch the configurable directions
+  if(!GetFlagLayoutPatientRightShownLeft())
+    {
+    axes[0][0] = axes[2][0] = 'L';
+    }
+  if(!GetFlagLayoutPatientAnteriorShownLeft())
+    {
+    axes[1][0] = 'P';
+    }
+
+  // Convert layout index to integer
+  size_t i = (size_t) GetSliceLayout();
+
+  // Set the axes
+  rai1 = axes[order[i][0]];
+  rai2 = axes[order[i][1]];
+  rai3 = axes[order[i][2]];
+}
+
+
+void OpenGLAppearanceElement::SetValid(const int validity[])
+{
+  m_NormalColorModel->SetIsValid(validity[NORMAL_COLOR]);
+  m_ActiveColorModel->SetIsValid(validity[ACTIVE_COLOR]);
+  m_LineThicknessModel->SetIsValid(validity[LINE_THICKNESS]);
+  m_DashSpacingModel->SetIsValid(validity[DASH_SPACING]);
+  m_FontSizeModel->SetIsValid(validity[FONT_SIZE]);
+  m_VisibleModel->SetIsValid(validity[VISIBLE]);
+  m_AlphaBlendingModel->SetIsValid(validity[ALPHA_BLEND]);
+}
+
+void OpenGLAppearanceElement
+::ApplyLineSettings(bool applyThickness, bool applyStipple) const
+{
+  // Apply the thickness properties
+  if(applyThickness)
+    {
+    // Choose whether to use blending or not
+    if(GetAlphaBlending())
+      {
+      glEnable(GL_BLEND);
+      glEnable(GL_LINE_SMOOTH);
+      glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
+      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+      }
+    glLineWidth(GetLineThickness());
+    }
+  if(applyStipple && GetDashSpacing() != 0)
+    {
+    // Set the line thickness and stipple
+    glEnable(GL_LINE_STIPPLE);
+    glLineStipple( static_cast<GLint>(GetDashSpacing()),
+                   0x9999 ); // 0011 0011 0011 0011  // 1001 1001 1001 1001
+    }
+}
+
+OpenGLAppearanceElement::OpenGLAppearanceElement()
+{
+  m_NormalColorModel =
+      NewRangedProperty("NormalColor",
+                        Vector3d(0.0), Vector3d(0.0), Vector3d(1.0), Vector3d(0.01));
+
+  m_ActiveColorModel =
+      NewRangedProperty("ActiveColor",
+                        Vector3d(0.0), Vector3d(0.0), Vector3d(1.0), Vector3d(0.01));
+
+  m_LineThicknessModel =
+      NewRangedProperty("LineThickness", 0.0, 0.0, 5.0, 0.1);
+
+  m_DashSpacingModel =
+      NewRangedProperty("DashSpacing", 0.0, 0.0, 5.0, 0.1);
+
+  m_FontSizeModel =
+      NewRangedProperty("FontSize", 0, 0, 36, 1);
+
+  m_VisibleModel = NewSimpleProperty("Visible", false);
+  m_AlphaBlendingModel = NewSimpleProperty("AlphaBlending", false);
+}
+
+
diff --git a/Logic/Common/SNAPAppearanceSettings.h b/Logic/Common/SNAPAppearanceSettings.h
new file mode 100644
index 0000000..cce12e3
--- /dev/null
+++ b/Logic/Common/SNAPAppearanceSettings.h
@@ -0,0 +1,222 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: SNAPAppearanceSettings.h,v $
+  Language:  C++
+  Date:      $Date: 2010/10/19 20:28:56 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#ifndef __SNAPAppearanceSettings_h_
+#define __SNAPAppearanceSettings_h_
+
+#if defined(_MSC_VER)
+#pragma warning ( disable : 4786 )
+#endif
+
+// Include the common items from the logic part of SNAP
+#include "SNAPCommon.h"
+#include "Registry.h"
+#include <string>
+#include "AbstractPropertyContainerModel.h"
+
+
+/**
+ * A structure that describes the appearance of a screen element
+ */
+struct Element
+{
+  Vector3d NormalColor;
+  Vector3d ActiveColor;
+  double LineThickness;
+  double DashSpacing;
+  int FontSize;
+  bool Visible, AlphaBlending;
+};
+
+
+class OpenGLAppearanceElement : public AbstractPropertyContainerModel
+{
+public:
+  irisITKObjectMacro(OpenGLAppearanceElement, AbstractPropertyContainerModel)
+
+  irisRangedPropertyAccessMacro(NormalColor, Vector3d)
+  irisRangedPropertyAccessMacro(ActiveColor, Vector3d)
+
+  irisRangedPropertyAccessMacro(LineThickness, double)
+  irisRangedPropertyAccessMacro(DashSpacing, double)
+  irisRangedPropertyAccessMacro(FontSize, int)
+
+  irisSimplePropertyAccessMacro(Visible, bool)
+  irisSimplePropertyAccessMacro(AlphaBlending, bool)
+
+  /** An enumeration of the fields that an element may possess */
+  enum UIElementFeatures
+    {
+    NORMAL_COLOR = 0, ACTIVE_COLOR, LINE_THICKNESS, DASH_SPACING,
+    FONT_SIZE, VISIBLE, ALPHA_BLEND, FEATURE_COUNT
+    };
+
+  // Set the validity of all the properties at once using an int array
+  // indexed by the enum UIElementFeatures
+  void SetValid(const int validity[]);
+
+  // Apply the GL line settings in the element
+  void ApplyLineSettings(bool applyThickness = true, bool applyStipple = true) const;
+
+protected:
+
+  SmartPtr<ConcreteRangedDoubleVec3Property> m_NormalColorModel, m_ActiveColorModel;
+  SmartPtr<ConcreteRangedDoubleProperty> m_LineThicknessModel, m_DashSpacingModel;
+  SmartPtr<ConcreteRangedIntProperty> m_FontSizeModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_VisibleModel, m_AlphaBlendingModel;
+
+  OpenGLAppearanceElement();
+
+};
+
+
+class GlobalDisplaySettings : public AbstractPropertyContainerModel
+{
+public:
+  irisITKObjectMacro(GlobalDisplaySettings, AbstractPropertyContainerModel)
+
+  /** Enumeration of interpolation modes */
+  enum UIGreyInterpolation { NEAREST = 0, LINEAR};
+
+  /** Enumeration of 2D display layouts */
+  enum UISliceLayout
+  {
+    LAYOUT_ASC = 0, LAYOUT_ACS, LAYOUT_SAC, LAYOUT_SCA, LAYOUT_CAS, LAYOUT_CSA, LAYOUT_COUNT
+  };
+
+  irisSimplePropertyAccessMacro(FlagDisplayZoomThumbnail, bool)
+  irisRangedPropertyAccessMacro(ZoomThumbnailSizeInPercent, double)
+  irisRangedPropertyAccessMacro(ZoomThumbnailMaximumSize, int)
+  irisSimplePropertyAccessMacro(GreyInterpolationMode, UIGreyInterpolation)
+  irisSimplePropertyAccessMacro(FlagLayoutPatientAnteriorShownLeft, bool)
+  irisSimplePropertyAccessMacro(FlagLayoutPatientRightShownLeft, bool)
+  irisSimplePropertyAccessMacro(SliceLayout, UISliceLayout)
+
+  /**
+   * This method uses SliceLayout, FlagLayoutPatientAnteriorShownLeft and
+   * FlagLayoutPatientRightShownLeft to generate RAI codes for the three
+   * display views.
+   * Use in conjunction with IRISApplication::SetDisplayToAnatomyRAI
+   */
+  void GetAnatomyToDisplayTransforms(
+      std::string &rai1, std::string &rai2, std::string &rai3) const;
+
+protected:
+
+  // Global settings
+  SmartPtr<ConcreteSimpleBooleanProperty> m_FlagDisplayZoomThumbnailModel;
+  SmartPtr<ConcreteRangedDoubleProperty> m_ZoomThumbnailSizeInPercentModel;
+  SmartPtr<ConcreteRangedIntProperty> m_ZoomThumbnailMaximumSizeModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_FlagLayoutPatientAnteriorShownLeftModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_FlagLayoutPatientRightShownLeftModel;
+
+  typedef ConcretePropertyModel<UIGreyInterpolation, TrivialDomain> ConcreteInterpolationModel;
+  SmartPtr<ConcreteInterpolationModel> m_GreyInterpolationModeModel;
+
+  typedef ConcretePropertyModel<UISliceLayout, TrivialDomain> ConcreteSliceLayoutModel;
+  SmartPtr<ConcreteSliceLayoutModel> m_SliceLayoutModel;
+
+  GlobalDisplaySettings();
+};
+
+
+
+/**
+ * \class SNAPAppearanceSettings
+ * \brief User interface settings that the user can configure
+ */
+class SNAPAppearanceSettings : public AbstractModel
+{
+public:
+
+  irisITKObjectMacro(SNAPAppearanceSettings, AbstractModel)
+
+  FIRES(ChildPropertyChangedEvent)
+
+  /** An enumeration of available screen elements */
+  enum UIElements
+    {
+    CROSSHAIRS = 0, MARKERS, ROI_BOX,
+    BACKGROUND_2D, BACKGROUND_3D,
+    ZOOM_THUMBNAIL, CROSSHAIRS_3D, CROSSHAIRS_THUMB,
+    IMAGE_BOX_3D, ROI_BOX_3D, PAINTBRUSH_OUTLINE, RULER, 
+    POLY_DRAW_MAIN, POLY_DRAW_CLOSE, POLY_EDIT,
+    ELEMENT_COUNT
+    };
+
+  void LoadFromRegistry(Registry &registry);
+  void SaveToRegistry(Registry &registry);
+
+  // Access a user interface element
+  OpenGLAppearanceElement *GetUIElement(unsigned int iElement)
+    { return m_Elements[iElement]; }
+
+  // Access a user interface element
+  const OpenGLAppearanceElement *GetUIElementDefaultSettings(unsigned int iElement)
+    { return m_DefaultElementSettings[iElement]; }
+
+  irisSimplePropertyAccessMacro(OverallVisibility, bool)
+
+protected:
+
+  SNAPAppearanceSettings();
+  virtual ~SNAPAppearanceSettings() {}
+
+private:
+  /** Overall visibility - overrides all other flags */
+  SmartPtr<ConcreteSimpleBooleanProperty> m_OverallVisibilityModel;
+
+  /** An array of current user interface elements */
+  SmartPtr<OpenGLAppearanceElement> m_Elements[ELEMENT_COUNT];
+    
+  /** The set of default values for each element */
+  SmartPtr<OpenGLAppearanceElement> m_DefaultElementSettings[ELEMENT_COUNT];
+
+  /** A list of flags that indicate for each element, whether each feature is
+   * applicable or not. This is used to set up the defaults */
+  static const int m_Applicable[ELEMENT_COUNT][OpenGLAppearanceElement::FEATURE_COUNT];
+
+  /** Names of the appearance elements */
+  static const char *m_ElementNames[];
+
+  /** Initialize the default settings */
+  void InitializeDefaultSettings();
+};
+
+
+
+
+
+
+#endif // __SNAPAppearanceSettings_h_
diff --git a/Logic/Common/SNAPRegistryIO.cxx b/Logic/Common/SNAPRegistryIO.cxx
index b513c74..b73d971 100644
--- a/Logic/Common/SNAPRegistryIO.cxx
+++ b/Logic/Common/SNAPRegistryIO.cxx
@@ -34,12 +34,27 @@
 =========================================================================*/
 #include "IRISVectorTypes.h"
 #include "SNAPRegistryIO.h"
+#include "IRISException.h"
 #include "IRISApplication.h"
 #include "IRISImageData.h"
+#include "SNAPImageData.h"
+#include "HistoryManager.h"
 #include <algorithm>
 #include <vector>
 #include <string>
 
+#include "EdgePreprocessingSettings.h"
+#include "ThresholdSettings.h"
+#include "IntensityCurveInterface.h"
+
+RegistryEnumMap<CoverageModeType> SNAPRegistryIO::m_EnumMapCoverage;
+RegistryEnumMap<SnakeParameters::SolverType> SNAPRegistryIO::m_EnumMapSolver;
+RegistryEnumMap<SnakeParameters::SnakeType> SNAPRegistryIO::m_EnumMapSnakeType;
+RegistryEnumMap<SNAPSegmentationROISettings::InterpolationMethod> SNAPRegistryIO::m_EnumMapROI;
+RegistryEnumMap<LayerRole> SNAPRegistryIO::m_EnumMapLayerRole;
+RegistryEnumMap<LayerLayout> SNAPRegistryIO::m_EnumMapLayerLayout;
+
+
 #if defined(_MSC_VER)
 #pragma warning ( disable : 4786 )
 #endif
@@ -49,30 +64,7 @@ using namespace std;
 SNAPRegistryIO
 ::SNAPRegistryIO()
 {
-  // Set up the enum objects
-  m_EnumMapCoverage.AddPair(PAINT_OVER_ALL,"OverAll");
-  m_EnumMapCoverage.AddPair(PAINT_OVER_COLORS,"OverVisible");
-  m_EnumMapCoverage.AddPair(PAINT_OVER_ONE,"OverOne");
-
-  m_EnumMapSolver.AddPair(SnakeParameters::DENSE_SOLVER,"Dense");
-  m_EnumMapSolver.AddPair(SnakeParameters::LEGACY_SOLVER,"Legacy");
-  m_EnumMapSolver.AddPair(SnakeParameters::SPARSE_FIELD_SOLVER,"SparseField");
-  m_EnumMapSolver.AddPair(SnakeParameters::NARROW_BAND_SOLVER,"NarrowBand");
-  m_EnumMapSolver.AddPair(SnakeParameters::PARALLEL_SPARSE_FIELD_SOLVER,
-                              "ParallelSparseField");
-
-  m_EnumMapSnakeType.AddPair(SnakeParameters::EDGE_SNAKE,"EdgeStopping");
-  m_EnumMapSnakeType.AddPair(SnakeParameters::REGION_SNAKE,"RegionCompetition");
-
-  m_EnumMapROI.AddPair(SNAPSegmentationROISettings::NEAREST_NEIGHBOR,"Nearest");
-  m_EnumMapROI.AddPair(SNAPSegmentationROISettings::TRILINEAR,"TriLinear");
-  m_EnumMapROI.AddPair(SNAPSegmentationROISettings::TRICUBIC,"Cubic");
-  m_EnumMapROI.AddPair(SNAPSegmentationROISettings::SINC_WINDOW_05,"Sinc05");
-
-
-
-
-
+  BuildEnums();
 }
 
 /** Read snake parameters from a registry */
@@ -152,68 +144,11 @@ SNAPRegistryIO
 }
 
 /** Read mesh options from a registry */
-MeshOptions 
+void
 SNAPRegistryIO
-::ReadMeshOptions(
-  Registry &registry, const MeshOptions &defaultSet)
+::ReadMeshOptions(Registry &registry, MeshOptions *target)
 {
-  MeshOptions out;
-  
-  out.SetUseGaussianSmoothing(
-    registry["UseGaussianSmoothing"][defaultSet.GetUseGaussianSmoothing()]);
-    
-  out.SetUseDecimation(
-    registry["UseDecimation"][defaultSet.GetUseDecimation()]);
-
-  out.SetUseMeshSmoothing(
-    registry["UseMeshSmoothing"][defaultSet.GetUseMeshSmoothing()]);
-
-  out.SetGaussianStandardDeviation(
-    registry["GaussianStandardDeviation"][defaultSet.GetGaussianStandardDeviation()]);
-
-  out.SetGaussianError(
-    registry["GaussianError"][defaultSet.GetGaussianError()]);
-
-  out.SetDecimateTargetReduction(
-    registry["DecimateTargetReduction"][defaultSet.GetDecimateTargetReduction()]);
-
-  out.SetDecimateInitialError(
-    registry["DecimateInitialError"][defaultSet.GetDecimateInitialError()]);
-
-  out.SetDecimateAspectRatio(
-    registry["DecimateAspectRatio"][defaultSet.GetDecimateAspectRatio()]);
-
-  out.SetDecimateFeatureAngle(
-    registry["DecimateFeatureAngle"][defaultSet.GetDecimateFeatureAngle()]);
-
-  out.SetDecimateErrorIncrement(
-    registry["DecimateErrorIncrement"][defaultSet.GetDecimateErrorIncrement()]);
-
-  out.SetDecimateMaximumIterations(
-    registry["DecimateMaximumIterations"][defaultSet.GetDecimateMaximumIterations()]);
-
-  out.SetDecimatePreserveTopology(
-    registry["DecimatePreserveTopology"][defaultSet.GetDecimatePreserveTopology()]);
-
-  out.SetMeshSmoothingRelaxationFactor(
-    registry["MeshSmoothingRelaxationFactor"][defaultSet.GetMeshSmoothingRelaxationFactor()]);
-
-  out.SetMeshSmoothingIterations(
-    registry["MeshSmoothingIterations"][defaultSet.GetMeshSmoothingIterations()]);
-
-  out.SetMeshSmoothingConvergence(
-    registry["MeshSmoothingConvergence"][defaultSet.GetMeshSmoothingConvergence()]);
-
-  out.SetMeshSmoothingFeatureAngle(
-    registry["MeshSmoothingFeatureAngle"][defaultSet.GetMeshSmoothingFeatureAngle()]);
-
-  out.SetMeshSmoothingFeatureEdgeSmoothing(
-    registry["MeshSmoothingFeatureEdgeSmoothing"][defaultSet.GetMeshSmoothingFeatureEdgeSmoothing()]);
-
-  out.SetMeshSmoothingBoundarySmoothing(
-    registry["MeshSmoothingBoundarySmoothing"][defaultSet.GetMeshSmoothingBoundarySmoothing()]);
-
-  return out;
+  target->ReadFromRegistry(registry);
 }
 
 /** Write mesh options to a registry */
@@ -221,126 +156,69 @@ void
 SNAPRegistryIO
 ::WriteMeshOptions(const MeshOptions &in,Registry &registry)
 {
-  registry["UseGaussianSmoothing"] << in.GetUseGaussianSmoothing();
-  registry["UseDecimation"] << in.GetUseDecimation();
-  registry["UseMeshSmoothing"] << in.GetUseMeshSmoothing();
-  registry["GaussianStandardDeviation"] << in.GetGaussianStandardDeviation();
-  registry["GaussianError"] << in.GetGaussianError();
-  registry["DecimateTargetReduction"] << in.GetDecimateTargetReduction();
-  registry["DecimateInitialError"] << in.GetDecimateInitialError();
-  registry["DecimateAspectRatio"] << in.GetDecimateAspectRatio();
-  registry["DecimateFeatureAngle"] << in.GetDecimateFeatureAngle();
-  registry["DecimateErrorIncrement"] << in.GetDecimateErrorIncrement();
-  registry["DecimateMaximumIterations"] << in.GetDecimateMaximumIterations();
-  registry["DecimatePreserveTopology"] << in.GetDecimatePreserveTopology();
-  registry["MeshSmoothingRelaxationFactor"] << in.GetMeshSmoothingRelaxationFactor();
-  registry["MeshSmoothingIterations"] << in.GetMeshSmoothingIterations();
-  registry["MeshSmoothingConvergence"] << in.GetMeshSmoothingConvergence();
-  registry["MeshSmoothingFeatureAngle"] << in.GetMeshSmoothingFeatureAngle();
-  registry["MeshSmoothingFeatureEdgeSmoothing"] << in.GetMeshSmoothingFeatureEdgeSmoothing();
-  registry["MeshSmoothingBoundarySmoothing"] << in.GetMeshSmoothingBoundarySmoothing();
+  in.WriteToRegistry(registry);
 }
 
-/** Read edge preprocessing settings from a registry */
-EdgePreprocessingSettings 
+
+/** Write region of interest settings to a registry folder */
+void
 SNAPRegistryIO
-::ReadEdgePreprocessingSettings(
-  Registry &registry, const EdgePreprocessingSettings &defaultSet)
+::WriteSegmentationROISettings(
+  const SNAPSegmentationROISettings &in, Registry &folder)
 {
-  EdgePreprocessingSettings out;
-
-  out.SetGaussianBlurScale(
-    registry["GaussianBlurScale"][defaultSet.GetGaussianBlurScale()]);
-
-  out.SetRemappingSteepness(
-    registry["RemappingSteepness"][defaultSet.GetRemappingSteepness()]);
-
-  out.SetRemappingExponent(
-    registry["RemappingExponent"][defaultSet.GetRemappingExponent()]);
-  
-  return out;  
+  folder["ResampleDimensions"] << to_int(in.GetResampleDimensions());
+  for(unsigned int d = 0; d < 3; d++)
+    {
+    Registry &sub = folder.Folder(folder.Key("ROIBox[%d]",d));
+    sub["Index"] << in.GetROI().GetIndex(d);
+    sub["Size"] << in.GetROI().GetSize(d);
+    }
+  folder["InterpolationMethod"].PutEnum(m_EnumMapROI,in.GetInterpolationMethod());
 }
 
-/** Write edge preprocessing settings to a registry */
-void 
-SNAPRegistryIO
-::WriteEdgePreprocessingSettings(const EdgePreprocessingSettings &in,
-                                 Registry &registry)
+RegistryEnumMap<CoverageModeType> &SNAPRegistryIO::GetEnumMapCoverage()
 {
-  registry["GaussianBlurScale"] << in.GetGaussianBlurScale();
-  registry["RemappingSteepness"] << in.GetRemappingSteepness();
-  registry["RemappingExponent"] << in.GetRemappingExponent();
+  BuildEnums();
+  return m_EnumMapCoverage;
 }
 
-/** Read threshold settings from a registry */
-ThresholdSettings 
-SNAPRegistryIO
-::ReadThresholdSettings(
-  Registry &registry, const ThresholdSettings &defaultSet)
+RegistryEnumMap<SnakeParameters::SolverType> &SNAPRegistryIO::GetEnumMapSolver()
 {
-  ThresholdSettings out;
-  
-  out.SetLowerThreshold(
-    registry["LowerThreshold"][defaultSet.GetLowerThreshold()]);
-
-  out.SetUpperThreshold(
-    registry["UpperThreshold"][defaultSet.GetUpperThreshold()]);
-
-  out.SetSmoothness(
-    registry["Smoothness"][defaultSet.GetSmoothness()]);
-
-  out.SetLowerThresholdEnabled(
-    registry["LowerThresholdEnabled"][defaultSet.IsLowerThresholdEnabled()]);
-
-  out.SetUpperThresholdEnabled(
-    registry["UpperThresholdEnabled"][defaultSet.IsUpperThresholdEnabled()]);
+  BuildEnums();
+  return m_EnumMapSolver;
+}
 
-  // Check that what we've read is valid
-  if(!out.IsValid())
-    out = defaultSet;
+RegistryEnumMap<SnakeParameters::SnakeType> &SNAPRegistryIO::GetEnumMapSnakeType()
+{
+  BuildEnums();
+  return m_EnumMapSnakeType;
+}
 
-  return out;
+RegistryEnumMap<SNAPSegmentationROISettings::InterpolationMethod> &SNAPRegistryIO::GetEnumMapROI()
+{
+  BuildEnums();
+  return m_EnumMapROI;
 }
 
-/** Write threshold settings to a registry */
-void 
-SNAPRegistryIO
-::WriteThresholdSettings(const ThresholdSettings &in,Registry &registry)
+RegistryEnumMap<LayerRole> &SNAPRegistryIO::GetEnumMapLayerRole()
 {
-  registry["LowerThreshold"] << in.GetLowerThreshold();
-  registry["UpperThreshold"] << in.GetUpperThreshold();
-  registry["Smoothness"] << in.GetSmoothness();
-  registry["LowerThresholdEnabled"] << in.IsLowerThresholdEnabled();
-  registry["UpperThresholdEnabled"] << in.IsUpperThresholdEnabled();
+  BuildEnums();
+  return m_EnumMapLayerRole;
 }
 
-/** Write region of interest settings to a registry folder */
-void
-SNAPRegistryIO
-::WriteSegmentationROISettings(
-  const SNAPSegmentationROISettings &in, Registry &folder)
+RegistryEnumMap<LayerLayout> &SNAPRegistryIO::GetEnumMapLayerLayout()
 {
-  folder["ResampleFlag"] << in.GetResampleFlag();
-  folder["VoxelScale"] << in.GetVoxelScale();  
-  for(unsigned int d = 0; d < 3; d++)
-    {
-    Registry &sub = folder.Folder(folder.Key("ROIBox[%d]",d));
-    sub["Index"] << in.GetROI().GetIndex(d);
-    sub["Size"] << in.GetROI().GetSize(d);
-    }
-  folder["InterpolationMethod"].PutEnum(m_EnumMapROI,in.GetInterpolationMethod());
+  BuildEnums();
+  return m_EnumMapLayerLayout;
 }
 
-SNAPSegmentationROISettings 
+SNAPSegmentationROISettings
 SNAPRegistryIO
 ::ReadSegmentationROISettings(
   Registry &folder, const SNAPSegmentationROISettings &dfl)
 {
   SNAPSegmentationROISettings out;
 
-  // Read resampling properties
-  out.SetResampleFlag(folder["ResampleFlag"][dfl.GetResampleFlag()]);
-  out.SetVoxelScale(folder["VoxelScale"][dfl.GetVoxelScale()]);
   out.SetInterpolationMethod(
     folder["InterpolationMethod"].GetEnum(
       m_EnumMapROI, dfl.GetInterpolationMethod()));
@@ -356,6 +234,12 @@ SNAPRegistryIO
     }
   out.SetROI(outRegion);
 
+  // Read resampling properties. If the folder does not contain the resample
+  // dimensions value (added in ITK-SNAP 3.0), we default to the ROI dimensions
+  out.SetResampleDimensions(
+        to_unsigned_int(
+          folder["ResampleDimensions"][to_int(Vector3ui(outRegion.GetSize()))]));
+
   return out;
 }  
 
@@ -372,28 +256,25 @@ SNAPRegistryIO
     registry.Folder("SNAP.SnakeParameters"));
 
   // Write the preprocessing settings
-  WriteEdgePreprocessingSettings(
-    gs->GetEdgePreprocessingSettings(),
-    registry.Folder("SNAP.Preprocessing.Edge"));
-  WriteThresholdSettings(
-    gs->GetThresholdSettings(),
-    registry.Folder("SNAP.Preprocessing.Region"));
+  app->GetEdgePreprocessingSettings()->WriteToRegistry(registry);
+
+  // Read the threshold settings
+  // TODO: how are we going to handle per-component settings?
+  // app->GetThresholdSettings()->WriteToRegistry(registry);
 
   // Write the mesh display options
   WriteMeshOptions(
-    gs->GetMeshOptions(),
+    *gs->GetMeshOptions(),
     registry.Folder("IRIS.MeshOptions"));
 
   // Save the intensity mapping curve
-  if (app->GetIRISImageData()->IsGreyLoaded())
+  if (app->GetIRISImageData()->IsMainLoaded())
     {
-    app->GetCurrentImageData()->GetGrey()->GetIntensityMapFunction()->
-      SaveToRegistry(registry.Folder("IRIS.IntensityCurve"));
+    ImageWrapperBase *main = app->GetCurrentImageData()->GetMain();
+    main->GetDisplayMapping()->Save(registry.Folder("IRIS.DisplayMapping"));
     }
 
   // Write file related information
-  registry["Files.Segmentation.FileName"] << gs->GetLastAssociatedSegmentationFileName();
-  registry["Files.Preprocessing.FileName"] << gs->GetLastAssociatedPreprocessingFileName();
   registry["Files.Grey.Orientation"] << app->GetImageToAnatomyRAI();
   registry["Files.Grey.Dimensions"] << 
     to_int(app->GetIRISImageData()->GetVolumeExtents());
@@ -402,12 +283,11 @@ SNAPRegistryIO
   registry["IRIS.LabelState.DrawingLabel"] << 
     (int) gs->GetDrawingColorLabel();
   registry["IRIS.LabelState.OverwriteLabel"] << 
-    (int) gs->GetOverWriteColorLabel();
+    (int) gs->GetDrawOverFilter().DrawOverLabel;
   registry["IRIS.LabelState.CoverageMode"].PutEnum(
-    m_EnumMapCoverage,gs->GetCoverageMode());
+    m_EnumMapCoverage,gs->GetDrawOverFilter().CoverageMode);
   registry["IRIS.LabelState.PolygonInvert"] << gs->GetPolygonInvert();
-  registry["IRIS.LabelState.OverallAlpha"] << 
-    (int) gs->GetSegmentationAlpha();
+  registry["IRIS.LabelState.SegmentationAlpha"] << gs->GetSegmentationAlpha();
 
   // Write the information about the bounding box and ROI sub-sampling
   WriteSegmentationROISettings(
@@ -415,6 +295,14 @@ SNAPRegistryIO
 
   // Write the color label table
   app->GetColorLabelTable()->SaveToRegistry(registry.Folder("IRIS.LabelTable"));
+
+  // Write the local history
+  app->GetSystemInterface()->GetHistoryManager()->SaveLocalHistory(
+        registry.Folder("IOHistory"));
+
+  // Write the tiling state
+  registry["IRIS.SliceViewLayerLayout"].PutEnum(
+        GetEnumMapLayerLayout(), gs->GetSliceViewLayerLayout());
 }
 
 bool 
@@ -427,9 +315,14 @@ SNAPRegistryIO
   // Get a pointer to the global state
   GlobalState *gs = app->GetGlobalState();
 
+  // Get the main image if it's loaded
+  ImageWrapperBase *main =
+      app->IsMainImageLoaded()
+      ? app->GetCurrentImageData()->GetMain()
+      : NULL;
+
   // First of all, make sure that the image referred to in the association file
   // matches the image currently loaded
-  Vector3i xxx=iris_vector_fixed<int,3>(7);
   Vector3i dims = (registry["Files.Grey.Dimensions"])[Vector3i(0)];
   if(dims != to_int(app->GetIRISImageData()->GetVolumeExtents()))
     return false;
@@ -448,39 +341,35 @@ SNAPRegistryIO
   if(restorePreprocessing)
     {
     // Read the edge preprocessing settings
-    gs->SetEdgePreprocessingSettings(
-      SNAPRegistryIO::ReadEdgePreprocessingSettings(
-        registry.Folder("SNAP.Preprocessing.Edge"),
-        gs->GetEdgePreprocessingSettings()));
+    app->GetEdgePreprocessingSettings()->ReadFromRegistry(
+          registry.Folder("SNAP.Preprocessing.Edge"));
     
     // Read the thresholding settings (note that since they depend on an image
     // we have to use re-initialized defaults
-    if (app->GetIRISImageData()->IsGreyLoaded())
+    if (main)
       {
-    gs->SetThresholdSettings(
-      SNAPRegistryIO::ReadThresholdSettings(
-        registry.Folder("SNAP.Preprocessing.Region"),
-        ThresholdSettings::MakeDefaultSettings(
-          app->GetIRISImageData()->GetGrey())));
-	 }
+      // TODO: do something about reading and writing threshold settings
+      // app->GetThresholdSettings()->ReadFromRegistry(
+      //      registry, main->GetDefaultScalarRepresentation());
+      }
     }
 
   // Read the display options
   if(restoreDisplayOptions)
     {
     // Read the mesh options
-    gs->SetMeshOptions(
-      SNAPRegistryIO::ReadMeshOptions(
-        registry.Folder("IRIS.MeshOptions"),
-        gs->GetMeshOptions()));
+    SNAPRegistryIO::ReadMeshOptions(registry.Folder("IRIS.MeshOptions"), gs->GetMeshOptions());
 
     // Restore the intensity mapping curve
-    if (app->GetIRISImageData()->IsGreyLoaded())
+    if (main)
       {
-      app->GetCurrentImageData()->GetGrey()->GetIntensityMapFunction()->
-        LoadFromRegistry(registry.Folder("IRIS.IntensityCurve"));
-      app->GetCurrentImageData()->GetGrey()->UpdateIntensityMapFunction();
-	 }
+      main->GetDisplayMapping()->Restore(registry.Folder("IRIS.DisplayMapping"));
+      }
+
+    // Tiling state
+    gs->SetSliceViewLayerLayout(registry["IRIS.SliceViewLayerLayout"].GetEnum(
+          GetEnumMapLayerLayout(), gs->GetSliceViewLayerLayout()));
+
     }
 
   // Read the information about the bounding box and ROI sub-sampling
@@ -499,29 +388,69 @@ SNAPRegistryIO
       (LabelType)registry["IRIS.LabelState.DrawingLabel"][1]);
 
     // Read the override color label
-    gs->SetOverWriteColorLabel(
-      (LabelType)registry["IRIS.LabelState.OverwriteLabel"][0]);
+    gs->SetDrawOverFilter(
+          DrawOverFilter(
+            registry["IRIS.LabelState.CoverageMode"].GetEnum(
+              m_EnumMapCoverage,gs->GetCoverageMode()),
+            (LabelType)registry["IRIS.LabelState.OverwriteLabel"][0]));
     
-    // Read the coverage mode
-    gs->SetCoverageMode(
-      registry["IRIS.LabelState.CoverageMode"].GetEnum(
-        m_EnumMapCoverage,gs->GetCoverageMode()));      
-
     // Read the polygon inversion state
     gs->SetPolygonInvert(
       registry["IRIS.LabelState.PolygonInvert"][gs->GetPolygonInvert()]);
     
     // Read the segmentation alpha
     gs->SetSegmentationAlpha(
-      registry["IRIS.LabelState.OverallAlpha"][gs->GetSegmentationAlpha()]);
+      registry["IRIS.LabelState.SegmentationAlpha"][gs->GetSegmentationAlpha()]);
     } // If restore labels
 
   // Read other settings
+  // TODO: erase
+  /*
   gs->SetLastAssociatedSegmentationFileName(
     registry["Files.Segmentation.FileName"][""]);  
   gs->SetLastAssociatedPreprocessingFileName(
     registry["Files.Preprocessing.FileName"][""]);
+    */
+
+  // Read the local history
+  app->GetSystemInterface()->GetHistoryManager()->LoadLocalHistory(
+        registry.Folder("IOHistory"));
 
   // Done!
   return true;
 }
+
+void SNAPRegistryIO::BuildEnums()
+{
+  if(m_EnumMapCoverage.Size())
+    return;
+
+  // Set up the enum objects
+  m_EnumMapCoverage.AddPair(PAINT_OVER_ALL,"OverAll");
+  m_EnumMapCoverage.AddPair(PAINT_OVER_VISIBLE,"OverVisible");
+  m_EnumMapCoverage.AddPair(PAINT_OVER_ONE,"OverOne");
+
+  m_EnumMapSolver.AddPair(SnakeParameters::DENSE_SOLVER,"Dense");
+  m_EnumMapSolver.AddPair(SnakeParameters::LEGACY_SOLVER,"Legacy");
+  m_EnumMapSolver.AddPair(SnakeParameters::SPARSE_FIELD_SOLVER,"SparseField");
+  m_EnumMapSolver.AddPair(SnakeParameters::NARROW_BAND_SOLVER,"NarrowBand");
+  m_EnumMapSolver.AddPair(SnakeParameters::PARALLEL_SPARSE_FIELD_SOLVER,
+                              "ParallelSparseField");
+
+  m_EnumMapSnakeType.AddPair(SnakeParameters::EDGE_SNAKE,"EdgeStopping");
+  m_EnumMapSnakeType.AddPair(SnakeParameters::REGION_SNAKE,"RegionCompetition");
+
+  m_EnumMapROI.AddPair(SNAPSegmentationROISettings::NEAREST_NEIGHBOR,"Nearest");
+  m_EnumMapROI.AddPair(SNAPSegmentationROISettings::TRILINEAR,"TriLinear");
+  m_EnumMapROI.AddPair(SNAPSegmentationROISettings::TRICUBIC,"Cubic");
+  m_EnumMapROI.AddPair(SNAPSegmentationROISettings::SINC_WINDOW_05,"Sinc05");
+
+  m_EnumMapLayerRole.AddPair(MAIN_ROLE, "MainRole");
+  m_EnumMapLayerRole.AddPair(OVERLAY_ROLE, "OverlayRole");
+  m_EnumMapLayerRole.AddPair(LABEL_ROLE, "SegmentationRole");
+  m_EnumMapLayerRole.AddPair(SNAP_ROLE, "SnakeModeRole");
+  m_EnumMapLayerRole.AddPair(NO_ROLE, "InvalidRole");
+
+  m_EnumMapLayerLayout.AddPair(LAYOUT_STACKED, "Stacked");
+  m_EnumMapLayerLayout.AddPair(LAYOUT_TILED, "Tiled");
+}
diff --git a/Logic/Common/SNAPRegistryIO.h b/Logic/Common/SNAPRegistryIO.h
index b131ac4..2989fa4 100644
--- a/Logic/Common/SNAPRegistryIO.h
+++ b/Logic/Common/SNAPRegistryIO.h
@@ -39,8 +39,6 @@
 #include "Registry.h"
 #include "SnakeParameters.h"
 #include "MeshOptions.h"
-#include "EdgePreprocessingSettings.h"
-#include "ThresholdSettings.h"
 
 #if defined(_MSC_VER)
 #pragma warning ( disable : 4786 )
@@ -74,29 +72,13 @@ public:
     const SnakeParameters &in,Registry &registry);
   
   /** Read mesh options from a registry */
-  MeshOptions ReadMeshOptions(
-    Registry &registry,const MeshOptions &defaultSet);
+  void ReadMeshOptions(
+    Registry &registry, MeshOptions *target);
 
   /** Write mesh options to a registry */
   void WriteMeshOptions(
     const MeshOptions &in,Registry &registry);
   
-  /** Read edge preprocessing settings from a registry */
-  EdgePreprocessingSettings ReadEdgePreprocessingSettings(
-    Registry &registry,const EdgePreprocessingSettings &defaultSet);
-
-  /** Write edge preprocessing settings to a registry */
-  void WriteEdgePreprocessingSettings(
-    const EdgePreprocessingSettings &in,Registry &registry);
-
-  /** Read threshold settings from a registry */
-  ThresholdSettings ReadThresholdSettings(
-    Registry &registry,const ThresholdSettings &defaultSet);
-
-  /** Write threshold settings to a registry */
-  void WriteThresholdSettings(
-    const ThresholdSettings &in,Registry &registry);
-
   /** Read ROI settings from a registry */
   SNAPSegmentationROISettings ReadSegmentationROISettings(
     Registry &folder, const SNAPSegmentationROISettings &defaultSet);
@@ -105,13 +87,25 @@ public:
   void WriteSegmentationROISettings(
     const SNAPSegmentationROISettings &in, Registry &folder);
 
-
-
-  // Some enumeraticns used by this class
-  RegistryEnumMap<CoverageModeType> m_EnumMapCoverage;
-  RegistryEnumMap<SnakeParameters::SolverType> m_EnumMapSolver;
-  RegistryEnumMap<SnakeParameters::SnakeType> m_EnumMapSnakeType;
-  RegistryEnumMap<SNAPSegmentationROISettings::InterpolationMethod> m_EnumMapROI;
+  static RegistryEnumMap<CoverageModeType> &GetEnumMapCoverage();
+  static RegistryEnumMap<SnakeParameters::SolverType> &GetEnumMapSolver();
+  static RegistryEnumMap<SnakeParameters::SnakeType> &GetEnumMapSnakeType();
+  static RegistryEnumMap<SNAPSegmentationROISettings::InterpolationMethod> &GetEnumMapROI();
+  static RegistryEnumMap<LayerRole> &GetEnumMapLayerRole();
+  static RegistryEnumMap<LayerLayout> &GetEnumMapLayerLayout();
+
+protected:
+
+  // Method to build all the enums
+  static void BuildEnums();
+
+  // Some enumeraticns used by this class and others
+  static RegistryEnumMap<CoverageModeType> m_EnumMapCoverage;
+  static RegistryEnumMap<SnakeParameters::SolverType> m_EnumMapSolver;
+  static RegistryEnumMap<SnakeParameters::SnakeType> m_EnumMapSnakeType;
+  static RegistryEnumMap<SNAPSegmentationROISettings::InterpolationMethod> m_EnumMapROI;
+  static RegistryEnumMap<LayerRole> m_EnumMapLayerRole;
+  static RegistryEnumMap<LayerLayout> m_EnumMapLayerLayout;
 
 };
 
diff --git a/Logic/Common/SNAPSegmentationROISettings.cxx b/Logic/Common/SNAPSegmentationROISettings.cxx
index efc66dd..a24075c 100644
--- a/Logic/Common/SNAPSegmentationROISettings.cxx
+++ b/Logic/Common/SNAPSegmentationROISettings.cxx
@@ -34,30 +34,34 @@
 =========================================================================*/
 #include "SNAPSegmentationROISettings.h"
 
-bool 
-SNAPSegmentationROISettings
-::TransformImageVoxelToROIVoxel(const Vector3ui &vImage, Vector3ui &vROI)
+
+void SNAPSegmentationROISettings::SetROI(const itk::ImageRegion<3> &roi)
 {
-  itk::Index<3> idx = to_itkIndex(vImage);
-  if(m_ROI.IsInside(idx)) 
-  {
-    for(unsigned int i = 0; i < 3; i++)
+  if(m_ROI != roi)
     {
-      unsigned int p = vImage[i] - m_ROI.GetIndex()[i];
-      vROI[i] = (unsigned int) (p / m_VoxelScale[i]);
+    m_ROI = roi;
+    m_ResampleDimensions = Vector3ui(roi.GetSize());
     }
-    return true;
-  }
-  else return false;
 }
 
-void
-SNAPSegmentationROISettings
-::TransformROIVoxelToImageVoxel(const Vector3ui &vROI, Vector3ui &vImage)
+bool SNAPSegmentationROISettings::IsResampling() const
+{
+  return m_ROI.GetSize() != to_itkSize(m_ResampleDimensions);
+}
+
+bool SNAPSegmentationROISettings
+::operator ==(
+    const SNAPSegmentationROISettings &other) const
+{
+  return
+      m_ROI == other.m_ROI &&
+      m_ResampleDimensions == other.m_ResampleDimensions &&
+      m_InterpolationMethod == other.m_InterpolationMethod;
+}
+
+bool SNAPSegmentationROISettings
+::operator !=(
+    const SNAPSegmentationROISettings &other) const
 {
-  for(unsigned int i = 0; i < 3; i++)
-  {
-    unsigned int p = (unsigned int) (vROI[i] * m_VoxelScale[i]);
-    vImage[i] = p + m_ROI.GetIndex()[i];
-  }
+  return !(*this == other);
 }
diff --git a/Logic/Common/SNAPSegmentationROISettings.h b/Logic/Common/SNAPSegmentationROISettings.h
index 01b9d3b..9a62f3f 100644
--- a/Logic/Common/SNAPSegmentationROISettings.h
+++ b/Logic/Common/SNAPSegmentationROISettings.h
@@ -51,55 +51,44 @@ public:
     NEAREST_NEIGHBOR, TRILINEAR, TRICUBIC, SINC_WINDOW_05
   };
 
-  SNAPSegmentationROISettings() 
+  SNAPSegmentationROISettings()
     {
-    m_ResampleFlag = false;
-    m_VoxelScale.fill(1.0);
     m_InterpolationMethod = NEAREST_NEIGHBOR;
     }
 
   virtual ~SNAPSegmentationROISettings() {}
 
   // Get the region of interest, in the main IRIS image
-  irisSetMacro(ROI,itk::ImageRegion<3>);
+  void SetROI(const itk::ImageRegion<3> &roi);
   
   // Set the region of interest, in the main IRIS image
-  irisGetMacro(ROI,itk::ImageRegion<3>);
+  irisGetMacro(ROI,itk::ImageRegion<3>)
 
   // Get whether or not resampling is desired for the region
-  irisSetMacro(ResampleFlag,bool);
-  
-  // Set whether or not resampling is desired for the region
-  irisGetMacro(ResampleFlag,bool);
+  bool IsResampling() const;
 
-  // Get the scaling factor for each dimension
-  irisSetMacro(VoxelScale,Vector3d);
+  // Specify the resampling to be applied to the ROI (new size)
+  irisSetMacro(ResampleDimensions,Vector3ui)
   
-  // Set the scaling factor for each dimension
-  irisGetMacro(VoxelScale,Vector3d);
+  // Get the size of the ROI after resampling
+  irisGetMacro(ResampleDimensions,Vector3ui)
 
   // Get the interpolation method used
-  irisSetMacro(InterpolationMethod,InterpolationMethod);
+  irisSetMacro(InterpolationMethod,InterpolationMethod)
   
   // Set the interpolation method used
-  irisGetMacro(InterpolationMethod,InterpolationMethod);
+  irisGetMacro(InterpolationMethod,InterpolationMethod)
 
-  // Map image voxel to an ROI voxel, if the result is outside of the region
-  // this will return false, and not change the index
-  bool TransformImageVoxelToROIVoxel(const Vector3ui &vImage, Vector3ui &vROI);
+  bool operator == (const SNAPSegmentationROISettings &other) const;
+  bool operator != (const SNAPSegmentationROISettings &other) const;
 
-  // Map ROI voxel into an image voxel. The result will be inside the image
-  void TransformROIVoxelToImageVoxel(const Vector3ui &vROI, Vector3ui &vImage);
 
 private:
   // The region of interest, in the main IRIS image
   itk::ImageRegion<3> m_ROI;
   
-  // Whether or not resampling is desired for the region
-  bool m_ResampleFlag;
-  
   // The scaling factor for each dimension
-  Vector3d m_VoxelScale;
+  Vector3ui m_ResampleDimensions;
   
   // The interpolation method used
   InterpolationMethod m_InterpolationMethod;
diff --git a/Logic/Common/SegmentationStatistics.cxx b/Logic/Common/SegmentationStatistics.cxx
index d78dfcf..1efc28f 100644
--- a/Logic/Common/SegmentationStatistics.cxx
+++ b/Logic/Common/SegmentationStatistics.cxx
@@ -34,110 +34,137 @@
 =========================================================================*/
 #include "SegmentationStatistics.h"
 #include "GenericImageData.h"
+#include "ImageCollectionToImageFilter.h"
+
+#include <iostream>
+#include <iomanip>
 
 using namespace std;
 
-struct SegmentationStatisticsSource {
-  string name;
-  GreyImageWrapper *image;
-  GreyImageWrapper::ConstIterator it; 
-  GreyTypeToNativeFunctor funk;
-};
+
 
 void
 SegmentationStatistics
 ::Compute(GenericImageData *id)
 {
+  // TODO: improve efficiency by using filters to integrate label intensities
+
   // A list of image sources
-  vector<SegmentationStatisticsSource> isrc;
+  vector<ScalarImageWrapperBase *> layers;
 
-  // Populate image sources
-  if(id->IsGreyLoaded())
-    {
-    SegmentationStatisticsSource src;
-    src.name = "image";
-    src.image = id->GetGrey();
-    src.it = src.image->GetImageConstIterator();
-    src.funk = src.image->GetNativeMapping();
-    isrc.push_back(src);
-    }
+  // Clear the list of column names
+  m_ImageStatisticsColumnNames.clear();
 
-  // Add all grey overlays
-  size_t k = 1;
-  GenericImageData::WrapperIterator it = id->GetOverlays()->begin();
-  for(; it != id->GetOverlays()->end(); it++, k++)
+  // Find all the images available for statistics computation
+  for(LayerIterator it(id, MAIN_ROLE |
+                           OVERLAY_ROLE);
+      !it.IsAtEnd(); ++it)
     {
-    // Is it a grey wrapper?
-    GreyImageWrapper *wrapper = dynamic_cast<GreyImageWrapper *>(*it);
-    if (wrapper)
+    ScalarImageWrapperBase *lscalar = it.GetLayerAsScalar();
+    if(lscalar)
+      {
+      m_ImageStatisticsColumnNames.push_back(lscalar->GetNickname());
+      layers.push_back(lscalar);
+      }
+    else
       {
-      SegmentationStatisticsSource src;
-      ostringstream oss; oss << "ovl " << k;
-      src.name = oss.str();
-      src.image = wrapper;
-      src.it = src.image->GetImageConstIterator();
-      src.funk = src.image->GetNativeMapping();
-      isrc.push_back(src);
+      VectorImageWrapperBase *lvector = it.GetLayerAsVector();
+      for(int j = 0; j < lvector->GetNumberOfComponents(); j++)
+        {
+        std::ostringstream oss;
+        oss << lvector->GetNickname();
+        if(lvector->GetNumberOfComponents() > 1)
+          oss << " [" << j << "]";
+        m_ImageStatisticsColumnNames.push_back(oss.str());
+        layers.push_back(lvector->GetScalarRepresentation(
+              SCALAR_REP_COMPONENT, j));
+        }
       }
     }
 
   // Get the number of gray image layers
-  size_t ngray = isrc.size();
+  size_t ngray = layers.size();
 
   // Clear and initialize the statistics table
-  for(size_t i = 0; i < MAX_COLOR_LABELS; i++)
-    {
-    m_Stats[i] = Entry();
-    for(size_t j = 0; j < ngray; j++)
-      {
-      GrayStats gs;
-      gs.layer_id = isrc[j].name;
-      m_Stats[i].gray.push_back(gs);
-      }
-    }
+  m_Stats.clear();
+
+  // Start the label image iteration
+  LabelImageWrapper::ConstIterator itLabel = id->GetSegmentation()->GetImageConstIterator();
+  itk::ImageRegion<3> region = itLabel.GetRegion();
 
-  // Compute the statistics by iterating over each voxel
-  for(LabelImageWrapper::ConstIterator itLabel = 
-    id->GetSegmentation()->GetImageConstIterator();
-    !itLabel.IsAtEnd(); ++itLabel)
+  // Cache the entry to avoid many calls to std::map
+  LabelType runLabel = 0;
+  Entry *cachedEntry = &m_Stats[runLabel];
+  cachedEntry->resize(ngray);
+  itk::Index<3> runStart = itLabel.GetIndex();
+  long runLength = 0;
+
+  // Aggregate the statistical data
+  for( ; !itLabel.IsAtEnd(); ++itLabel, ++runLength)
     {
-    // Get the label and the corresponding entry
+    // Get the label and the corresponding entry (use cache to reduce time wasted in std::map)
     LabelType label = itLabel.Value();
-    Entry &entry = m_Stats[label];
+    if(label != runLabel)
+      {
+      // Record the statistics from the last run
+      this->RecordRunLength(ngray, layers, region, runStart, runLength, cachedEntry);
 
-    // Increment number of voxels for this label
-    entry.count++;
+      // Change the cached entry
+      runLabel = label;
+      cachedEntry = &m_Stats[runLabel];
+      if(cachedEntry->count == 0)
+        cachedEntry->resize(ngray);
 
-    // Update the gray statistics
-    for(size_t j = 0; j < ngray; j++)
-      {
-      double v = isrc[j].funk( isrc[j].it.Value() );
-      ++isrc[j].it;
-      entry.gray[j].sum += v;
-      entry.gray[j].sumsq += v * v;
+      runStart = itLabel.GetIndex();
+      runLength = 0;
       }
     }
-  
+
+  // Record the statistics from the last run
+  this->RecordRunLength(ngray, layers, region, runStart, runLength, cachedEntry);
+
   // Compute the size of a voxel, in mm^3
   const double *spacing = 
     id->GetMain()->GetImageBase()->GetSpacing().GetDataPointer();
   double volVoxel = spacing[0] * spacing[1] * spacing[2];
   
   // Compute the mean and standard deviation
-  for (size_t i=0; i < MAX_COLOR_LABELS; i++)
+  for(EntryMap::iterator it = m_Stats.begin(); it != m_Stats.end(); ++it)
     {
-    Entry &entry = m_Stats[i];
+    Entry &entry = it->second;
     for(size_t j = 0; j < ngray; j++)
       {
-      entry.gray[j].mean = entry.gray[j].sum / entry.count;
-      entry.gray[j].sd = sqrt(
-        (entry.gray[j].sumsq - entry.gray[j].sum * entry.gray[j].mean) 
-        / (entry.count - 1));
+      // Map to native format
+      double mean = entry.sum[j] / entry.count;
+      double stdev = sqrt((entry.sumsq[j] - entry.sum[j] * mean) / (entry.count - 1));
+
+      // Map with scale and shift
+      entry.mean[j] = layers[j]->GetNativeIntensityMapping()->MapInternalToNative(mean);
+
+      // Map with just shift
+      entry.stdev[j] = layers[j]->GetNativeIntensityMapping()->MapGradientMagnitudeToNative(stdev);
       }
     entry.volume_mm3 = entry.count * volVoxel;
     }
 }
 
+void SegmentationStatistics
+::RecordRunLength(size_t ngray, vector<ScalarImageWrapperBase *> &layers,
+                  itk::ImageRegion<3> &region, itk::Index<3> &runStart,
+                  long runLength, Entry *cachedEntry)
+{
+  // Record the statistics from the last run
+  for(size_t j = 0; j < ngray; j++)
+    {
+    layers[j]->GetRunLengthIntensityStatistics(
+          region, runStart, runLength,
+          cachedEntry->sum.data_block() + j,
+          cachedEntry->sumsq.data_block() + j);
+    }
+
+  cachedEntry->count += runLength;
+}
+
 void 
 SegmentationStatistics
 ::ExportLegacy(ostream &fout, const ColorLabelTable &clt)
@@ -156,21 +183,23 @@ SegmentationStatistics
   fout << "#    SD            Standard deviation of those voxels " << std::endl;
   fout << "##########################################################" << std::endl;
 
-  for (size_t i=1; i<MAX_COLOR_LABELS; i++) 
+  for (ColorLabelTable::ValidLabelConstIterator it = clt.begin();
+       it != clt.end(); it++)
     {
-    const ColorLabel &cl = clt.GetColorLabel(i);
-    if(cl.IsValid() && m_Stats[i].count > 0)
+    LabelType i = it->first;
+    ColorLabel cl = clt.GetColorLabel(i);
+    if(m_Stats[i].count > 0)
       {
       fout << std::left << std::setw(40) << cl.GetLabel() << ": ";
       fout << std::right << std::setw(4) << i << " / ";
       fout << std::right << std::setw(10) << m_Stats[i].count << " / ";
       fout << std::setw(10) << (m_Stats[i].volume_mm3);
      
-      for(size_t j = 0; j < m_Stats[i].gray.size(); j++)
+      for(size_t j = 0; j < m_Stats[i].mean.size(); j++)
         {
         fout << " / " << std::internal << std::setw(10) 
-          << m_Stats[i].gray[j].mean << " / " << std::setw(10) 
-          << m_Stats[i].gray[j].sd;
+          << m_Stats[i].mean[j] << " / " << std::setw(10)
+          << m_Stats[i].stdev[j];
         }
 
       fout << endl;
@@ -178,3 +207,51 @@ SegmentationStatistics
     }
 }
 
+#include "itksys/SystemTools.hxx"
+
+void SegmentationStatistics
+::Export(ostream &oss, const string &colsep, const ColorLabelTable &clt)
+{
+  // Write out the header
+  oss << "Label Id" << colsep;
+  oss << "Label Name" << colsep;
+  oss << "Number Of Voxels" << colsep;
+  oss << "Volume (mm^3)";
+
+  // Print the list of column names
+  for(int i = 0; i < m_ImageStatisticsColumnNames.size(); i++)
+    {
+    std::string colname = m_ImageStatisticsColumnNames[i];
+    itksys::SystemTools::ReplaceString(colname, colsep.c_str(), " ");
+
+    oss << colsep << "Image mean (" << colname << ")";
+    oss << colsep << "Image stdev (" << colname << ")";
+    }
+
+  // Endline
+  oss << std::endl;
+
+  // Write each row
+  for(EntryMap::iterator it = m_Stats.begin(); it != m_Stats.end(); ++it)
+    {
+    LabelType i = it->first;
+    Entry &entry = it->second;
+    oss << i << colsep;
+
+    std::string label(clt.GetColorLabel(i).GetLabel());
+    itksys::SystemTools::ReplaceString(label, colsep.c_str(), " ");
+    oss << label << colsep;
+
+    oss << entry.count << colsep;
+    oss << entry.volume_mm3;
+
+    for(int j = 0; j < entry.mean.size(); j++)
+      {
+      oss << colsep << entry.mean[j];
+      oss << colsep << entry.stdev[j];
+      }
+
+    oss << std::endl;
+    }
+}
+
diff --git a/Logic/Common/SegmentationStatistics.h b/Logic/Common/SegmentationStatistics.h
index 97d9197..bff80ca 100644
--- a/Logic/Common/SegmentationStatistics.h
+++ b/Logic/Common/SegmentationStatistics.h
@@ -39,9 +39,16 @@
 #include <vector>
 #include <string>
 #include <iostream>
+#include <map>
 
 class GenericImageData;
 class ColorLabelTable;
+class ScalarImageWrapperBase;
+
+namespace itk {
+  template <unsigned int VDim> class ImageRegion;
+  template <unsigned int VDim> class Index;
+}
 
 class SegmentationStatistics
 {
@@ -58,26 +65,48 @@ public:
   struct Entry {
     unsigned long int count;
     double volume_mm3;
-    std::vector<GrayStats> gray;
+    vnl_vector<double> sum, sumsq, mean, stdev;
     Entry() : count(0),volume_mm3(0) {}
+    void resize(int n) {
+      sum.set_size(n); sum.fill(0);
+      sumsq.set_size(n); sumsq.fill(0);
+      mean.set_size(n); mean.fill(0);
+      stdev.set_size(n); stdev.fill(0);
+    }
   };
 
+  typedef std::map<LabelType, Entry> EntryMap;
+
   /* Compute statistics from a segmentation image */
   void Compute(GenericImageData *id);
   
   /* Export to a text file using legacy format */
   void ExportLegacy(std::ostream &oss, const ColorLabelTable &clt);
 
-  /* Export to a text file as a formatted table */
-  void ExportText(std::ostream &oss, const ColorLabelTable &clt);
+  /* Export to a CSV or text file */
+  void Export(std::ostream &oss, const std::string &colsep, const ColorLabelTable &clt);
 
-  const Entry * GetStats() const
+  const EntryMap &GetStats() const
     { return m_Stats; }
 
+  const std::vector<std::string> &GetImageStatisticsColumns() const
+    { return m_ImageStatisticsColumnNames; }
+
 private:
+
   // Label statistics
-  Entry m_Stats[MAX_COLOR_LABELS];
+  EntryMap m_Stats;
+
+  // Column information
+  std::vector<std::string> m_ImageStatisticsColumnNames;
   
+  void RecordRunLength(
+      size_t ngray,
+      std::vector<ScalarImageWrapperBase *> &layers,
+      itk::ImageRegion<3> &region,
+      itk::Index<3> &runStart,
+      long runLength,
+      Entry *cachedEntry);
 };
 
 #endif
diff --git a/Logic/Framework/DefaultBehaviorSettings.cxx b/Logic/Framework/DefaultBehaviorSettings.cxx
new file mode 100644
index 0000000..2b76ff7
--- /dev/null
+++ b/Logic/Framework/DefaultBehaviorSettings.cxx
@@ -0,0 +1,32 @@
+#include "DefaultBehaviorSettings.h"
+#include "ColorMap.h"
+#include "SNAPRegistryIO.h"
+
+DefaultBehaviorSettings::DefaultBehaviorSettings()
+{
+  // Behaviors
+  m_LinkedZoomModel = NewSimpleProperty("LinkedZoom", true);
+  m_ContinuousMeshUpdateModel = NewSimpleProperty("ContinuousMeshUpdate", false);
+  m_SynchronizationModel = NewSimpleProperty("Synchronization", true);
+  m_SyncCursorModel = NewSimpleProperty("SyncCursor", true);
+  m_SyncZoomModel = NewSimpleProperty("SyncZoom", true);
+  m_SyncPanModel = NewSimpleProperty("SyncPan", true);
+
+  m_AutoContrastModel = NewSimpleProperty("AutoContrast", false);
+
+  // Permissions
+  RegistryEnumMap<UpdateCheckingPermission> remUpdate;
+  remUpdate.AddPair(UPDATE_NO, "No");
+  remUpdate.AddPair(UPDATE_YES, "Yes");
+  remUpdate.AddPair(UPDATE_UNKNOWN, "Unknown");
+  m_CheckForUpdatesModel = NewSimpleEnumProperty("CheckForUpdates", UPDATE_UNKNOWN, remUpdate);
+
+  // Overlay behavior
+  m_OverlayColorMapPresetModel =
+      NewSimpleProperty("OverlayColorMapPreset",
+                        std::string(ColorMap::GetPresetName(ColorMap::COLORMAP_GREY)));
+
+  // Layer layout (uses enum)
+  m_OverlayLayoutModel = NewSimpleEnumProperty("OverlayLayout", LAYOUT_STACKED,
+                                               SNAPRegistryIO::GetEnumMapLayerLayout());
+}
diff --git a/Logic/Framework/DefaultBehaviorSettings.h b/Logic/Framework/DefaultBehaviorSettings.h
new file mode 100644
index 0000000..798c677
--- /dev/null
+++ b/Logic/Framework/DefaultBehaviorSettings.h
@@ -0,0 +1,66 @@
+#ifndef DEFAULTBEHAVIORSETTINGS_H
+#define DEFAULTBEHAVIORSETTINGS_H
+
+#include "AbstractPropertyContainerModel.h"
+#include "DisplayLayoutModel.h"
+
+/**
+ * A set of default behaviors for SNAP. These are read at startup and used
+ * to initialize the SNAP state.
+ */
+class DefaultBehaviorSettings : public AbstractPropertyContainerModel
+{
+public:
+  irisITKObjectMacro(DefaultBehaviorSettings, AbstractPropertyContainerModel)
+
+  // Default behaviors
+  irisSimplePropertyAccessMacro(LinkedZoom, bool)
+  irisSimplePropertyAccessMacro(ContinuousMeshUpdate, bool)
+  irisSimplePropertyAccessMacro(Synchronization, bool)
+  irisSimplePropertyAccessMacro(SyncCursor, bool)
+  irisSimplePropertyAccessMacro(SyncZoom, bool)
+  irisSimplePropertyAccessMacro(SyncPan, bool)
+  irisSimplePropertyAccessMacro(AutoContrast, bool)
+
+  // Permissions
+  enum UpdateCheckingPermission {
+    UPDATE_YES, UPDATE_NO, UPDATE_UNKNOWN
+  };
+
+  /** Whether we are allowed to check for updates automatically */
+  irisSimplePropertyAccessMacro(CheckForUpdates, UpdateCheckingPermission)
+
+  // Default colormap for overlays. Since this can be a user preset, the
+  // value is specified as a string. This value may point to a preset that
+  // has been deleted, so we have to be careful to check and reset to default
+  // if that is the case
+  irisSimplePropertyAccessMacro(OverlayColorMapPreset, std::string)
+
+  // Default layout
+  irisSimplePropertyAccessMacro(OverlayLayout, LayerLayout)
+
+protected:
+
+  // Default behaviors
+  SmartPtr<ConcreteSimpleBooleanProperty> m_LinkedZoomModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_ContinuousMeshUpdateModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_SynchronizationModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_SyncCursorModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_SyncZoomModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_SyncPanModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_AutoContrastModel;
+
+  // Permissions
+  SmartPtr<ConcretePropertyModel<UpdateCheckingPermission> > m_CheckForUpdatesModel;
+
+  // Overlay behaviors
+  SmartPtr<ConcreteSimpleStringProperty> m_OverlayColorMapPresetModel;
+
+  typedef ConcretePropertyModel<LayerLayout, TrivialDomain> ConcreteLayerLayoutModel;
+  SmartPtr<ConcreteLayerLayoutModel> m_OverlayLayoutModel;
+
+  // Constructor
+  DefaultBehaviorSettings();
+};
+
+#endif // DEFAULTBEHAVIORSETTINGS_H
diff --git a/Logic/Framework/GenericImageData.cxx b/Logic/Framework/GenericImageData.cxx
index 866c734..6d4202a 100644
--- a/Logic/Framework/GenericImageData.cxx
+++ b/Logic/Framework/GenericImageData.cxx
@@ -33,52 +33,26 @@
 
 =========================================================================*/
 // ITK Includes
-#include "itkOrientedImage.h"
+#include "itkImage.h"
 #include "itkImageIterator.h"
 #include "itkImageRegionIterator.h"
 #include "itkImageRegionConstIterator.h"
 #include "itkImageRegionIteratorWithIndex.h"
 #include "itkMinimumMaximumImageCalculator.h"
 #include "itkUnaryFunctorImageFilter.h"
-#include "UnaryFunctorCache.h"
 #include "itkRGBAPixel.h"
 #include "IRISSlicer.h"
+#include "IRISException.h"
 #include "IRISApplication.h"
+#include <algorithm>
 #include <list>
-
-/** Borland compiler is very lazy so we need to instantiate the template
- *  by hand */
-#if defined(__BORLANDC__)
-typedef IRISSlicer<unsigned char> GenericImageDataDummyIRISSlicerTypeUchar;
-typedef itk::SmartPointer<GenericImageDataDummyIRISSlicerTypeUchar> GenericImageDataDummySmartPointerSlicerType;
-typedef IRISSlicer<short> GenericImageDataDummyIRISSlicerTypeShort;
-typedef itk::SmartPointer<GenericImageDataDummyIRISSlicerTypeShort> GenericImageDataDummySmartPointerSlicerShortType;
-typedef itk::ImageRegion<3> GenericImageDataBorlandDummyImageRegionType;
-typedef itk::ImageRegion<2> GenericImageDataBorlandDummyImageRegionType2;
-typedef itk::ImageBase<3> GenericImageDataBorlandDummyImageBaseType;
-typedef itk::ImageBase<2> GenericImageDataBorlandDummyImageBaseType2;
-typedef itk::Image<unsigned char,3> GenericImageDataBorlandDummyImageType;
-typedef itk::Image<unsigned char,2> GenericImageDataBorlandDummyImageType2;
-typedef itk::ImageRegionConstIterator<GenericImageDataBorlandDummyImageType> GenericImageDataBorlandDummyConstIteratorType;
-typedef itk::Image<short,3> GenericImageDataBorlandDummyShortImageType;
-typedef itk::Image<short,2> GenericImageDataBorlandDummyShortImageType2;
-typedef itk::Image<itk::RGBAPixel<unsigned char>,2> GenericImageDataBorlandDummyShortImageTypeRGBA;
-typedef itk::ImageRegionConstIterator<GenericImageDataBorlandDummyShortImageType> GenericImageDataBorlandDummyConstIteratorShortType;
-typedef itk::MinimumMaximumImageCalculator<GenericImageDataBorlandDummyShortImageType> GenericImageDataBorlandDummyMinMaxCalc;
-#endif
-
-#include "GreyImageWrapper.h"
-#if defined(__BORLANDC__)
-typedef CachingUnaryFunctor<short,unsigned char,GreyImageWrapper::IntensityFunctor> GenericImageDataBorlamdCachingUnaryFunctor;
-typedef itk::UnaryFunctorImageFilter<GenericImageDataBorlandDummyShortImageType,GenericImageDataBorlandDummyImageType2,GenericImageDataBorlamdCachingUnaryFunctor> GenericImageDataDummyFunctorType;
-typedef itk::SmartPointer<GenericImageDataDummyFunctorType> GenericImageDataDummyFunctorTypePointerType;
-#endif
-
+#include <map>
+#include <iostream>
+#include "SNAPEventListenerCallbacks.h"
 #include "GenericImageData.h"
-
-#include "LabelImageWrapper.h"
-
-#include "RGBImageWrapper.h"
+#include "Rebroadcaster.h"
+#include "LayerIterator.h"
+#include "GuidedNativeImageIO.h"
 
 // System includes
 #include <fstream>
@@ -91,30 +65,33 @@ GenericImageData
 ::SetSegmentationVoxel(const Vector3ui &index, LabelType value)
 {
   // Make sure that the main image data and the segmentation data exist
-  assert(m_MainImageWrapper->IsInitialized() && m_LabelWrapper.IsInitialized());
+  assert(IsSegmentationLoaded());
 
   // Store the voxel
-  m_LabelWrapper.GetVoxelForUpdate(index) = value;
+  m_LabelWrapper->SetVoxel(index, value);
 
   // Mark the image as modified
-  m_LabelWrapper.GetImage()->Modified();
+  m_LabelWrapper->GetImage()->Modified();
 }
 
 GenericImageData
-::GenericImageData(IRISApplication *parent) 
+::GenericImageData()
 {
-  // Copy the parent object
-  m_Parent = parent;
-
   // Make main image wrapper point to grey wrapper initially
-  m_MainImageWrapper = &m_GreyWrapper;
+  m_MainImageWrapper = NULL;
 
   // Pass the label table from the parent to the label wrapper
-  m_LabelWrapper.SetLabelColorTable(m_Parent->GetColorLabelTable());
+  m_LabelWrapper = NULL;
   
-  // Add to the primary wrapper list
-  m_MainWrappers.push_back(m_MainImageWrapper);
-  m_MainWrappers.push_back(&m_LabelWrapper);
+  // Add to the relevant lists
+  m_Wrappers[MAIN_ROLE].push_back(m_MainImageWrapper);
+  m_Wrappers[LABEL_ROLE].push_back(m_LabelWrapper.GetPointer());
+}
+
+GenericImageData
+::~GenericImageData()
+{
+  UnloadMainImage();
 }
 
 Vector3d 
@@ -133,46 +110,104 @@ GenericImageData
   return m_MainImageWrapper->GetImageBase()->GetOrigin().GetVnlVector();
 }
 
-void 
+
+void
 GenericImageData
-::SetGreyImage(GreyImageType *newGreyImage,
-               const ImageCoordinateGeometry &newGeometry,
-               const GreyTypeToNativeFunctor &native) 
+::SetMainImageInternal(ImageWrapperBase *wrapper)
 {
-  m_GreyWrapper.SetImage(newGreyImage);
-  m_GreyWrapper.SetNativeMapping(native);
-  m_GreyWrapper.SetAlpha(255);
-  m_GreyWrapper.UpdateIntensityMapFunction();
+  // Set properties
+  wrapper->SetDefaultNickname("Main Image");
+
+  // Make the wrapper the main image
+  SetSingleImageWrapper(MAIN_ROLE, wrapper);
+  m_MainImageWrapper = wrapper;
+
+  // Reset the segmentation image
+  ResetSegmentationImage();
 
-  SetMainImageCommon(&m_GreyWrapper, newGeometry);
+  // Set opaque
+  m_MainImageWrapper->SetAlpha(255);
 }
 
-void
-GenericImageData
-::SetRGBImage(RGBImageType *newRGBImage,
-              const ImageCoordinateGeometry &newGeometry) 
+
+SmartPtr<ImageWrapperBase>
+GenericImageData::CreateAnatomicWrapper(GuidedNativeImageIO *io)
 {
-  m_RGBWrapper.SetImage(newRGBImage);
-  m_RGBWrapper.SetAlpha(255);
+  // The output wrapper
+  SmartPtr<ImageWrapperBase> out_wrapper;
+
+  // Split depending on whether the image is scalar or vector
+  if(io->GetNumberOfComponentsInNativeImage() > 1)
+    {
+    // The image will be cast to a vector anatomic image
+    typedef AnatomicImageWrapper::ImageType AnatomicImageType;
+
+    // Rescale the image to desired number of bits
+    RescaleNativeImageToIntegralType<AnatomicImageType> rescaler;
+    AnatomicImageType::Pointer image = rescaler(io);
+
+    // Create a mapper to native intensity
+    LinearInternalToNativeIntensityMapping mapper(
+          rescaler.GetNativeScale(), rescaler.GetNativeShift());
+
+    // Create a main wrapper of fixed type.
+    SmartPtr<AnatomicImageWrapper> wrapper = AnatomicImageWrapper::New();
+
+    // Set properties
+    wrapper->SetDisplayGeometry(m_DisplayGeometry);
+    wrapper->SetImage(image);
+    wrapper->SetNativeMapping(mapper);
+    out_wrapper = wrapper.GetPointer();
+    }
+
+  else
+    {
+    // Rescale the image to desired number of bits
+    typedef AnatomicScalarImageWrapper::ImageType AnatomicImageType;
+
+    // Rescale the image to desired number of bits
+    RescaleNativeImageToIntegralType<AnatomicImageType> rescaler;
+    AnatomicImageType::Pointer image = rescaler(io);
+
+    // Create a mapper to native intensity
+    LinearInternalToNativeIntensityMapping mapper(
+          rescaler.GetNativeScale(), rescaler.GetNativeShift());
+
+    // Create a main wrapper of fixed type.
+    SmartPtr<AnatomicScalarImageWrapper> wrapper = AnatomicScalarImageWrapper::New();
+
+    // Set properties
+    wrapper->SetDisplayGeometry(m_DisplayGeometry);
+    wrapper->SetImage(image);
+    wrapper->SetNativeMapping(mapper);
+    out_wrapper = wrapper.GetPointer();
+    }
 
-  SetMainImageCommon(&m_RGBWrapper, newGeometry);
+  // Create an image coordinate geometry object
+  return out_wrapper;
+}
+
+void GenericImageData::SetMainImage(GuidedNativeImageIO *io)
+{
+  // Create the wrapper from the Native IO (the wrapper will either be a scalar
+  // or a vector-valued image, depending on the number of components)
+  SmartPtr<ImageWrapperBase> wrapper = this->CreateAnatomicWrapper(io);
+
+  // Assign this wrapper to the main image
+  this->SetMainImageInternal(wrapper);
 }
 
 void
 GenericImageData
-::SetMainImageCommon(ImageWrapperBase *wrapper,
-                      const ImageCoordinateGeometry &newGeometry)
+::ResetSegmentationImage()
 {
-  // Make the wrapper the main image
-  m_MainImageWrapper = wrapper;
-  m_MainWrappers.pop_front();
-  m_MainWrappers.push_front(m_MainImageWrapper);
-
   // Initialize the segmentation data to zeros
-  m_LabelWrapper.InitializeToWrapper(m_MainImageWrapper, (LabelType) 0);
+  m_LabelWrapper = LabelImageWrapper::New();
+  m_LabelWrapper->InitializeToWrapper(m_MainImageWrapper, (LabelType) 0);
+  m_LabelWrapper->SetDefaultNickname("Segmentation Image");
 
-  // Pass the coordinate transform to the wrappers
-  SetImageGeometry(newGeometry);
+  m_LabelWrapper->GetDisplayMapping()->SetLabelColorTable(m_Parent->GetColorLabelTable());
+  SetSingleImageWrapper(LABEL_ROLE, m_LabelWrapper.GetPointer());
 }
 
 void
@@ -183,69 +218,52 @@ GenericImageData
   UnloadOverlays();
 
   // Clear the main image wrappers
-  m_LabelWrapper.Reset();
-  m_MainImageWrapper->Reset();
+  RemoveSingleImageWrapper(MAIN_ROLE);
+  m_MainImageWrapper = NULL;
+
+  // Reset the label wrapper
+  RemoveSingleImageWrapper(LABEL_ROLE);
+  m_LabelWrapper = NULL;
 }
 
 void
 GenericImageData
-::SetGreyOverlay(GreyImageType *newGreyImage,
-                 const GreyTypeToNativeFunctor &native)
+::AddOverlay(GuidedNativeImageIO *io)
 {
-  // Check that the image matches the size of the main image
-  assert(m_MainImageWrapper->GetBufferedRegion() ==
-         newGreyImage->GetBufferedRegion());
+  // Create the wrapper from the Native IO (the wrapper will either be a scalar
+  // or a vector-valued image, depending on the number of components)
+  SmartPtr<ImageWrapperBase> wrapper = this->CreateAnatomicWrapper(io);
 
-  // Pass the image to a Grey image wrapper
-  GreyImageWrapper *newGreyOverlayWrapper = new GreyImageWrapper;
-  newGreyOverlayWrapper->SetImage(newGreyImage);
-  newGreyOverlayWrapper->SetNativeMapping(native);
-  newGreyOverlayWrapper->SetAlpha(128);
-  newGreyOverlayWrapper->UpdateIntensityMapFunction();
-
-  SetOverlayCommon(newGreyOverlayWrapper);
+  // Assign this wrapper to the main image
+  this->AddOverlayInternal(wrapper);
 }
 
 void
 GenericImageData
-::SetRGBOverlay(RGBImageType *newRGBImage)
+::AddOverlayInternal(ImageWrapperBase *overlay)
 {
   // Check that the image matches the size of the main image
-  assert(m_MainImageWrapper->GetBufferedRegion() ==
-         newRGBImage->GetBufferedRegion());
-
-  // Pass the image to a RGB image wrapper
-  RGBImageWrapper *newRGBOverlayWrapper = new RGBImageWrapper;
-  newRGBOverlayWrapper->SetImage(newRGBImage);
-  newRGBOverlayWrapper->SetAlpha(128);
+  if(m_MainImageWrapper->GetBufferedRegion() != overlay->GetBufferedRegion())
+    {
+    throw IRISException("Main and overlay data sizes are different");
+    }
 
-  SetOverlayCommon(newRGBOverlayWrapper);
-}
+  // Pass the image to a Grey image wrapper
+  overlay->SetAlpha(0.5);
+  overlay->SetDefaultNickname("Overlay Image");
 
-void
-GenericImageData
-::SetOverlayCommon(ImageWrapperBase *overlay)
-{
   // Sync up spacing between the main and overlay image
-  overlay->GetImageBase()->SetSpacing(m_MainImageWrapper->GetImageBase()->GetSpacing());
-  overlay->GetImageBase()->SetOrigin(m_MainImageWrapper->GetImageBase()->GetOrigin());
-
-  // Propagate the geometry information to this wrapper
-  for(unsigned int iSlice = 0;iSlice < 3;iSlice ++)
-    {
-    overlay->SetImageToDisplayTransform(
-      iSlice,m_ImageGeometry.GetImageToDisplayTransform(iSlice));
-    }
+  overlay->CopyImageCoordinateTransform(m_MainImageWrapper);
 
   // Add to the overlay wrapper list
-  m_OverlayWrappers.push_back(overlay);
+  PushBackImageWrapper(OVERLAY_ROLE, overlay);
 }
 
 void
 GenericImageData
 ::UnloadOverlays()
 {
-  while (m_OverlayWrappers.size() > 0)
+  while (m_Wrappers[OVERLAY_ROLE].size() > 0)
     UnloadOverlayLast();
 }
 
@@ -258,12 +276,18 @@ GenericImageData
     return;
 
   // Release the data associated with the last overlay
-  ImageWrapperBase *wrapper = m_OverlayWrappers.back();
-  delete wrapper;
-  wrapper = NULL;
+  PopBackImageWrapper(OVERLAY_ROLE);
+}
 
-  // Clear it off the wrapper lists
-  m_OverlayWrappers.pop_back();
+void GenericImageData
+::UnloadOverlay(ImageWrapperBase *overlay)
+{
+  // Erase the overlay
+  WrapperList &overlays = m_Wrappers[OVERLAY_ROLE];
+  WrapperIterator it =
+      std::find(overlays.begin(), overlays.end(), overlay);
+  if(it != overlays.end())
+    overlays.erase(it);
 }
 
 void
@@ -275,61 +299,64 @@ GenericImageData
     m_MainImageWrapper->GetBufferedRegion() == 
          newLabelImage->GetBufferedRegion());
 
-  // Pass the image to the segmentation wrapper
-  m_LabelWrapper.SetImage(newLabelImage);
+  // Pass the image to the segmentation wrapper (why this and not create a
+  // new label wrapper? Why should a wrapper have longer lifetime than an
+  // image that it wraps around
+  m_LabelWrapper->SetImage(newLabelImage);
 
   // Sync up spacing between the main and label image
-  newLabelImage->SetSpacing(m_MainImageWrapper->GetImageBase()->GetSpacing());
-  newLabelImage->SetOrigin(m_MainImageWrapper->GetImageBase()->GetOrigin());
+  m_LabelWrapper->CopyImageCoordinateTransform(m_MainImageWrapper);
 }
 
 bool
 GenericImageData
-::IsGreyLoaded()
+::IsOverlayLoaded()
 {
-  return m_GreyWrapper.IsInitialized();
+  return (m_Wrappers[OVERLAY_ROLE].size() > 0);
 }
 
 bool
 GenericImageData
-::IsOverlayLoaded()
+::IsSegmentationLoaded()
 {
-  return (m_OverlayWrappers.size() > 0);
+  return m_LabelWrapper && m_LabelWrapper->IsInitialized();
 }
 
-bool
+void
 GenericImageData
-::IsRGBLoaded()
+::SetCrosshairs(const Vector3ui &crosshairs)
 {
-  return m_RGBWrapper.IsInitialized();
+  // Set crosshairs in all wrappers
+  for(LayerIterator lit(this); !lit.IsAtEnd(); ++lit)
+    if(lit.GetLayer() && lit.GetLayer()->IsInitialized())
+      lit.GetLayer()->SetSliceIndex(crosshairs);
 }
 
-bool
-GenericImageData
-::IsSegmentationLoaded()
+void GenericImageData::SetDisplayGeometry(const IRISDisplayGeometry &dispGeom)
 {
-  return m_LabelWrapper.IsInitialized();
+  m_DisplayGeometry = dispGeom;
+  for(LayerIterator lit(this); !lit.IsAtEnd(); ++lit)
+    if(lit.GetLayer())
+      {
+      // Set the direction matrix in the image
+      lit.GetLayer()->SetDisplayGeometry(m_DisplayGeometry);
+      }
 }
 
-void
-GenericImageData
-::SetCrosshairs(const Vector3ui &crosshairs)
+void GenericImageData::SetDirectionMatrix(const vnl_matrix<double> &direction)
 {
-  SetCrosshairs(m_MainWrappers, crosshairs);
-  SetCrosshairs(m_OverlayWrappers, crosshairs);
+  for(LayerIterator lit(this); !lit.IsAtEnd(); ++lit)
+    if(lit.GetLayer())
+      {
+      // Set the direction matrix in the image
+      lit.GetLayer()->SetDirectionMatrix(direction);
+      }
 }
 
-void
-GenericImageData
-::SetCrosshairs(WrapperList &list, const Vector3ui &crosshairs)
+const ImageCoordinateGeometry &GenericImageData::GetImageGeometry() const
 {
-  WrapperIterator it = list.begin();
-  while (it != list.end())
-    {
-    ImageWrapperBase *wrapper = *it++;
-    if (wrapper->IsInitialized())
-      wrapper->SetSliceIndex(crosshairs);
-    }
+  assert(m_MainImageWrapper->IsInitialized());
+  return m_MainImageWrapper->GetImageGeometry();
 }
 
 GenericImageData::RegionType
@@ -340,39 +367,123 @@ GenericImageData
   return m_MainImageWrapper->GetBufferedRegion();
 }
 
-void
-GenericImageData
-::SetImageGeometry(const ImageCoordinateGeometry &geometry)
+
+unsigned int GenericImageData::GetNumberOfLayers(int role_filter)
 {
-  SetImageGeometry(m_MainWrappers, geometry);
-  SetImageGeometry(m_OverlayWrappers, geometry);
+  unsigned int n = 0;
+
+  LayerIterator it = this->GetLayers(role_filter);
+  while(!it.IsAtEnd())
+    {
+    n++; ++it;
+    }
+
+  return n;
 }
 
-void
+ImageWrapperBase *
 GenericImageData
-::SetImageGeometry(WrapperList &list, const ImageCoordinateGeometry &geometry)
+::FindLayer(unsigned long unique_id, bool search_derived, int role_filter)
 {
-  // Save the geometry
-  m_ImageGeometry = geometry;
-
-  // Propagate the geometry to the image wrappers
-  for(WrapperIterator it = list.begin();
-    it != list.end(); ++it)
+  for(LayerIterator it = this->GetLayers(role_filter); !it.IsAtEnd(); ++it)
     {
-    ImageWrapperBase *wrapper = *it;
-    if(wrapper->IsInitialized())
+    if(it.GetLayer()->GetUniqueId() == unique_id)
       {
-      // Set the direction matrix in the image
-      wrapper->GetImageBase()->SetDirection(
-        itk::Matrix<double,3,3>(geometry.GetImageDirectionCosineMatrix()));
-
-      // Update the geometry for each slice
-      for(unsigned int iSlice = 0;iSlice < 3;iSlice ++)
+      return it.GetLayer();
+      }
+    else if(search_derived)
+      {
+      VectorImageWrapperBase *vec = it.GetLayerAsVector();
+      if(vec)
         {
-        wrapper->SetImageToDisplayTransform(
-          iSlice,m_ImageGeometry.GetImageToDisplayTransform(iSlice));
+        for(int j = SCALAR_REP_COMPONENT; j < NUMBER_OF_SCALAR_REPS; j++)
+          {
+          int n = (j == SCALAR_REP_COMPONENT) ? vec->GetNumberOfComponents() : 1;
+          for(int k = 0; k < n; k++)
+            {
+            ImageWrapperBase *w = vec->GetScalarRepresentation((ScalarRepresentation) j, k);
+            if(w && w->GetUniqueId() == unique_id)
+              return w;
+            }
+          }
         }
       }
     }
+
+  return NULL;
+}
+
+int GenericImageData::GetNumberOfOverlays()
+{
+  return m_Wrappers[OVERLAY_ROLE].size();
+}
+
+ImageWrapperBase *GenericImageData::GetLastOverlay()
+{
+  return m_Wrappers[OVERLAY_ROLE].back();
+}
+
+
+
+void GenericImageData::PushBackImageWrapper(LayerRole role,
+                                            ImageWrapperBase *wrapper)
+{
+  // Append the wrapper
+  m_Wrappers[role].push_back(wrapper);
+
+  // Rebroadcast the wrapper-related events as our own events
+  Rebroadcaster::RebroadcastAsSourceEvent(wrapper, WrapperChangeEvent(), this);
+}
+
+
+void GenericImageData::PopBackImageWrapper(LayerRole role)
+{
+  m_Wrappers[role].pop_back();
+}
+
+void GenericImageData::MoveLayer(ImageWrapperBase *layer, int direction)
+{
+  // Find the layer
+  LayerIterator it(this);
+  it.Find(layer);
+  if(!it.IsAtEnd())
+    {
+    WrapperList &wl = m_Wrappers[it.GetRole()];
+    int k = it.GetPositionInRole();
+
+    // Make sure the operation is legal!
+    assert(k + direction >= 0 && k + direction < wl.size());
+
+    // Do the swap
+    std::swap(wl[k], wl[k+direction]);
+    }
+}
+
+void GenericImageData::RemoveImageWrapper(LayerRole role,
+                                          ImageWrapperBase *wrapper)
+{
+  m_Wrappers[role].erase(
+        std::find(m_Wrappers[role].begin(), m_Wrappers[role].end(), wrapper));
+}
+
+void GenericImageData::SetSingleImageWrapper(LayerRole role,
+                                             ImageWrapperBase *wrapper)
+{
+  assert(m_Wrappers[role].size() == 1);
+  m_Wrappers[role].front() = wrapper;
+
+  // Rebroadcast the wrapper-related events as our own events
+  Rebroadcaster::RebroadcastAsSourceEvent(wrapper, WrapperChangeEvent(), this);
 }
 
+void GenericImageData::RemoveSingleImageWrapper(LayerRole role)
+{
+  assert(m_Wrappers[role].size() == 1);
+  m_Wrappers[role].front() = NULL;
+}
+
+
+
+
+
+
diff --git a/Logic/Framework/GenericImageData.h b/Logic/Framework/GenericImageData.h
index a2f3ff8..736e203 100644
--- a/Logic/Framework/GenericImageData.h
+++ b/Logic/Framework/GenericImageData.h
@@ -45,13 +45,18 @@
 
 #include "SNAPCommon.h"
 #include "IRISException.h"
-#include "LabelImageWrapper.h"
-#include "GreyImageWrapper.h"
-#include "RGBImageWrapper.h"
+#include "ImageWrapperTraits.h"
+#include <itkObject.h>
 #include "GlobalState.h"
 #include "ImageCoordinateGeometry.h"
+#include <string>
+#include "LayerIterator.h"
 
 class IRISApplication;
+class GenericImageData;
+class LayerIterator;
+class Registry;
+class GuidedNativeImageIO;
 
 /**
  * \class GenericImageData
@@ -63,73 +68,116 @@ class IRISApplication;
  *  + exists(si) ==> exists(gi)
  *  + if exists(si) then size(si) == size(gi)
  */
-class GenericImageData 
+class GenericImageData : public itk::Object
 {
 public:
+  irisITKObjectMacro(GenericImageData, itk::Object)
+
   // Image type definitions
-  typedef GreyImageWrapper::ImageType GreyImageType;
-  typedef RGBImageWrapper::ImageType RGBImageType;
-  typedef LabelImageWrapper::ImageType LabelImageType;
   typedef itk::ImageRegion<3> RegionType;
+  typedef itk::ImageBase<3> ImageBaseType;
+
+  /**
+   * The type of anatomical images. For the time being, all anatomic images
+   * are made to be of type short. Eventually, it may make sense to allow
+   * both short and char images, to save memory in some cases. However, it
+   * is not that common to only have 8-bit precision, so for the time being
+   * we are going to stick to short
+   */
+  typedef AnatomicImageWrapper::ImageType                   AnatomicImageType;
+  typedef LabelImageWrapper::ImageType                         LabelImageType;
+
 
-  typedef std::list<ImageWrapperBase *> WrapperList;
+  // Support for lists of wrappers
+  typedef SmartPtr<ImageWrapperBase> WrapperPointer;
+  typedef std::vector<WrapperPointer> WrapperList;
   typedef WrapperList::iterator WrapperIterator;
   typedef WrapperList::const_iterator WrapperConstIterator;
 
-  GenericImageData(IRISApplication *parent);
-  virtual ~GenericImageData() {};
+  /**
+   * Set the parent driver
+   */
+  irisGetSetMacro(Parent, IRISApplication *)
 
   /** 
-   * Access the 'main' image, either grey or RGB. The main image is the
-   * one that all other images must mimic
+   Access the 'main' image, either grey or RGB. The main image is the
+   one that all other images must mimic. This object will be destroyed
+   when a new image is loaded. This means that downstream objects should
+   not make copies of this pointer.
    */
   ImageWrapperBase* GetMain()
-    {
+  {
     assert(m_MainImageWrapper->IsInitialized());
     return m_MainImageWrapper;
-    }
+  }
 
-  bool IsMainLoaded()
-    {
-    return m_MainImageWrapper->IsInitialized();
-    }
+  bool IsMainLoaded() const
+  {
+    return m_MainImageWrapper && m_MainImageWrapper->IsInitialized();
+  }
 
   /**
-   * Access the greyscale image (read only access is allowed)
-   */
-  GreyImageWrapper* GetGrey() {
-    assert(m_GreyWrapper.IsInitialized());
-    return &m_GreyWrapper;
-  }
+    Get the number of layers in certain role(s). This is not as fast
+    as calling GetLayers(role).size(), but you can query for combinations
+    of roles, i.e., MAIN_ROLE | OVERLAY_ROLE
+    */
+  virtual unsigned int GetNumberOfLayers(int role_filter = ALL_ROLES);
+
 
   /**
-   * Access the RGB image (read only access is allowed)
-   */
-  RGBImageWrapper* GetRGB() {
-    assert(m_RGBWrapper.IsInitialized());
-    return &m_RGBWrapper;
+    Get an iterator that iterates throught the layers in certain roles
+    */
+  LayerIterator GetLayers(int role_filter = ALL_ROLES)
+  {
+    return LayerIterator(this, role_filter);
   }
 
   /**
-   * Access the overlay images (read only access is allowed)
-   */
-  WrapperList* GetOverlays() {
-    return &m_OverlayWrappers;
+    Get one of the layers (counting main and overlays). This is the same as
+    calling GetLayers(role_filter) and then iterating n-times. Throws an
+    exception if n exceeds the number of layers.
+    */
+  ImageWrapperBase *GetNthLayer(int n, int role_filter = ALL_ROLES)
+  {
+    LayerIterator it(this, role_filter);
+    for(int i = 0; i < n && !it.IsAtEnd(); i++)
+      ++it;
+    if(it.IsAtEnd())
+      throw IRISException("Illegal layer (%d of %d) requested",
+                          n, GetNumberOfLayers());
+    return it.GetLayer();
   }
 
   /**
+    Find a layer given the layer's unique id. The role_filter restricts the
+    search to specific layers, and the search_derived flag enables searching
+    among the derived (component, mean) wrappers in vector wrappers.
+    */
+  ImageWrapperBase *FindLayer(unsigned long unique_id, bool search_derived,
+                              int role_filter = ALL_ROLES);
+
+
+  int GetNumberOfOverlays();
+
+  ImageWrapperBase *GetLastOverlay();
+
+  // virtual ImageWrapperBase* GetLayer(unsigned int layer) const;
+
+  /**
    * Access the segmentation image (read only access allowed 
    * to preserve state)
    */
-  LabelImageWrapper* GetSegmentation() {
-    assert(m_MainImageWrapper->IsInitialized() && m_LabelWrapper.IsInitialized());
-    return &m_LabelWrapper;
+  LabelImageWrapper* GetSegmentation()
+  {
+    assert(m_MainImageWrapper->IsInitialized() && m_LabelWrapper->IsInitialized());
+    return m_LabelWrapper;
   }
 
   /** 
    * Get the extents of the image volume
    */
-  Vector3ui GetVolumeExtents() const {
+  Vector3ui GetVolumeExtents() const
+  {
     assert(m_MainImageWrapper->IsInitialized());
     return m_MainImageWrapper->GetSize();
   }
@@ -150,34 +198,38 @@ public:
   Vector3d GetImageOrigin();
 
   /**
-   * Set the grey image (read important note).
-   * 
-   * Note: this method replaces the internal pointer to the grey image
-   * by the pointer that is passed in.  That means that the caller should relinquish
-   * control of this pointer and that the GenericImageData class will dispose of the
-   * pointer properly. 
+   * Set the main image. The main image is the anatomical image that defines
+   * the coordinate space of all other images in a SNAP session. It is the
+   * image in which structures are traced. The main image can have multiple
+   * components or channels (e.g., red, green, blue).
    *
-   * The second parameter to this method is the new geometry object, which depends
-   * on the size of the grey image and will be updated.
+   * The input is a pointer to the GuidedNativeImageIO class,
+   * which stores the image data in raw native format.
    */
-  virtual void SetGreyImage(
-    GreyImageType *newGreyImage,
-    const ImageCoordinateGeometry &newGeometry,
-    const GreyTypeToNativeFunctor &native);
-
-  virtual void SetRGBImage(RGBImageType *newRGBImage,
-                    const ImageCoordinateGeometry &newGeometry);
+  virtual void SetMainImage(GuidedNativeImageIO *io);
 
+  /** Unload the main image (and everything else) */
   virtual void UnloadMainImage();
 
-  virtual void SetGreyOverlay(
-    GreyImageType *newGreyImage,
-    const GreyTypeToNativeFunctor &native);
-
-  virtual void SetRGBOverlay(RGBImageType *newRGBImage);
+  /**
+   * Reset the segmentation wrapper. This happens when the main image is loaded
+   * or when the user asks for a new segmentation image
+   */
+  virtual void ResetSegmentationImage();
 
+  /** Handle overlays */
+  virtual void AddOverlay(GuidedNativeImageIO *io);
   virtual void UnloadOverlays();
   virtual void UnloadOverlayLast();
+  virtual void UnloadOverlay(ImageWrapperBase *overlay);
+
+  /**
+   * Change the ordering of the layers within a particular role (for now just
+   * overlays are supported in the GUI) by moving the specified layer up or
+   * down one spot. The sign of the direction determines whether the layer is
+   * moved up or down.
+   */
+  virtual void MoveLayer(ImageWrapperBase *layer, int direction);
 
   /**
    * This method sets the segmentation image (see note for SetGrey).
@@ -190,16 +242,6 @@ public:
   void SetSegmentationVoxel(const Vector3ui &index, LabelType value);
 
   /**
-   * Check validity of greyscale image
-   */
-  bool IsGreyLoaded();
-
-  /**
-   * Check validity of RGB image
-   */
-  bool IsRGBLoaded();
-
-  /**
    * Check validity of overlay images
    */
   bool IsOverlayLoaded();
@@ -215,46 +257,71 @@ public:
   virtual void SetCrosshairs(const Vector3ui &crosshairs);
 
   /**
-   * Set the image coordinate geometry for this image set.  Propagates
-   * the transform to the internal image wrappers
+   * Set the display to anatomy coordinate mapping, and propagate it to
+   * all of the loaded layers
    */
-  virtual void SetImageGeometry(const ImageCoordinateGeometry &geometry);
+  virtual void SetDisplayGeometry(const IRISDisplayGeometry &dispGeom);
+
+  /**
+   * Set the direction matrix of all the images
+   */
+  virtual void SetDirectionMatrix(const vnl_matrix<double> &direction);
 
   /** Get the image coordinate geometry */
-  irisGetMacro(ImageGeometry,ImageCoordinateGeometry);
+  const ImageCoordinateGeometry &GetImageGeometry() const;
 
 protected:
-  virtual void SetMainImageCommon(ImageWrapperBase *wrapper,
-                          const ImageCoordinateGeometry &geometry);
-  virtual void SetOverlayCommon(ImageWrapperBase *wrapper);
-  virtual void SetCrosshairs(WrapperList &list, const Vector3ui &crosshairs);
-  virtual void SetImageGeometry(WrapperList &list, const ImageCoordinateGeometry &geometry);
 
-  // Wrapper around the grey-scale image
-  GreyImageWrapper m_GreyWrapper;
+  GenericImageData();
+  virtual ~GenericImageData();
+
+  // The base storage for the layers in the image data. For each role, there
+  // is a list of wrappers serving in that role. For many roles, there will
+  // be only one wrapper serving in that role.
+  typedef std::map<LayerRole, WrapperList> WrapperStorage;
 
-  // Wrapper around the RGB image
-  RGBImageWrapper m_RGBWrapper;
+  // This is where the all the wrappers are maintained. Child classes should
+  // aslo add their own wrappers to this list of wrappers.
+  WrapperStorage m_Wrappers;
 
   // A pointer to the 'main' image, i.e., the image that is treated as the
-  // reference for all other images. It is typically the grey image, but
-  // since we now allow for RGB images, it can point to the RGB image too
+  // reference for all other images.
+  // Equal to m_Wrappers[MAIN].first()
   ImageWrapperBase *m_MainImageWrapper;
 
-  // Wrapper around the segmentatoin image
-  LabelImageWrapper m_LabelWrapper;
+  // Wrapper around the segmentatoin image.
+  // Equal to m_Wrappers[SEGMENTATION].first()
+  SmartPtr<LabelImageWrapper> m_LabelWrapper;
 
   // A list of linked wrappers, whose cursor position and image geometry
   // are updated concurrently
-  WrapperList m_MainWrappers;
-  WrapperList m_OverlayWrappers;
+  // WrapperList m_MainWrappers;
+  // WrapperList m_OverlayWrappers;
 
   // Parent object
   IRISApplication *m_Parent;
 
-  // Image coordinate geometry (it's placed here because the transform depends
-  // on image size)
-  ImageCoordinateGeometry m_ImageGeometry;
+  // The display to anatomy transformation, which is stored by this object
+  IRISDisplayGeometry m_DisplayGeometry;
+
+  friend class SNAPImageData;
+  friend class LayerIterator;
+
+  // Create a wrapper (vector or scalar) from native format stored in the IO
+  SmartPtr<ImageWrapperBase> CreateAnatomicWrapper(GuidedNativeImageIO *io);
+
+  // Update the main image
+  virtual void SetMainImageInternal(ImageWrapperBase *wrapper);
+  virtual void AddOverlayInternal(ImageWrapperBase *wrapper);
+
+  // Append an image wrapper to a role
+  void PushBackImageWrapper(LayerRole role, ImageWrapperBase *wrapper);
+  void PopBackImageWrapper(LayerRole role);
+  void RemoveImageWrapper(LayerRole role, ImageWrapperBase *wrapper);
+
+  // For roles that only have one wrapper
+  void SetSingleImageWrapper(LayerRole, ImageWrapperBase *wrapper);
+  void RemoveSingleImageWrapper(LayerRole);
 
 };
 
diff --git a/Logic/Framework/GlobalState.cxx b/Logic/Framework/GlobalState.cxx
index 000c33c..638c7e4 100644
--- a/Logic/Framework/GlobalState.cxx
+++ b/Logic/Framework/GlobalState.cxx
@@ -33,54 +33,54 @@
 
 =========================================================================*/
 #include "GlobalState.h"
-
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "MeshOptions.h"
+#include "DefaultBehaviorSettings.h"
 
 GlobalState
-::GlobalState() 
+::GlobalState()
 {
   m_GreyFileExtension = NULL;
-  m_DrawingColorLabel = 1;
-  m_OverWriteColorLabel = 0;
   m_CrosshairsPosition[0] = 0;
   m_CrosshairsPosition[1] = 0;
   m_CrosshairsPosition[2] = 0;
-  m_ToolbarMode = CROSSHAIRS_MODE;
-  m_CoverageMode = PAINT_OVER_ALL;
   m_UpdateSliceFlag = 1;
   m_InterpolateGrey = false;
   m_InterpolateSegmentation = false;
-  m_PolygonInvert = false;
   m_LockHeld = 0;
   m_LockOwner = 0;
-  m_SegmentationAlpha = 0;
+
+  // Segmentation alpha model - range [0 1]
+  m_SegmentationAlphaModel = NewRangedConcreteProperty<double>(0.5, 0.0, 1.0, 0.01);
 
   // SNAP is off initially
   m_SNAPActive = false;
 
-  // Presets
-  m_SpeedColorMapInRegionMode = COLORMAP_BLUE_BLACK_WHITE;
-  m_SpeedColorMapInEdgeMode = COLORMAP_BLACK_BLACK_WHITE;
-
   // Snake stuff:
   m_SpeedValid = false;
-  m_ShowSpeed = false;
-  m_IsValidROI = false;
   m_ShowROI = false;
   m_DraggingROI = false;
-  m_SnakeMode = EDGE_SNAKE;
-  m_SnakeActive = false;
 
-  m_SpeedViewZero = false;
-  m_SnakeParameters = SnakeParameters::GetDefaultEdgeParameters();
-  m_ThresholdSettings = ThresholdSettings::MakeDefaultSettingsWithoutImage();
-  m_EdgePreprocessingSettings = EdgePreprocessingSettings::MakeDefaultSettings();
+  // Snake type model initialization
+  m_SnakeTypeModel = ConcretePropertyModel<SnakeType, SnakeTypeDomain>::New();
+  m_SnakeTypeModel->SetValue(IN_OUT_SNAKE);
+  SnakeTypeDomain snakedomain;
+  snakedomain[IN_OUT_SNAKE] = "Region Competition";
+  snakedomain[EDGE_SNAKE] = "Edge Attraction";
+  m_SnakeTypeModel->SetDomain(snakedomain);
 
-  // Default preview modes: enabled for in-out, disabled for edges (too slow)
-  m_ShowPreprocessedEdgePreview = false;
-  m_ShowPreprocessedInOutPreview = true;
+  // Last used preprocessing mode
+  m_LastUsedPreprocessingModeModel = NewSimpleConcreteProperty(PREPROCESS_THRESHOLD);
 
-  // The preview is not currently valid
-  m_SpeedPreviewValid = false;
+  // Initialize the property model for the ROI settings
+  m_SegmentationROISettingsModel
+      = NewSimpleConcreteProperty(SNAPSegmentationROISettings());
+
+  m_SpeedViewZero = false;
+
+  m_SnakeParametersModel = ConcreteSnakeParametersModel::New();
+  m_SnakeParametersModel->SetValue(SnakeParameters::GetDefaultInOutParameters());
 
   // Bubbles
   m_ActiveBubble = -1;
@@ -88,7 +88,7 @@ GlobalState
   // Set paintbrush defaults
   m_PaintbrushSettings.radius = 4;
   m_PaintbrushSettings.mode = PAINTBRUSH_RECTANGULAR;
-  m_PaintbrushSettings.flat = true;
+  m_PaintbrushSettings.volumetric = false;
   m_PaintbrushSettings.isotropic = false;
   m_PaintbrushSettings.chase = false;
   m_PaintbrushSettings.watershed.level = 0.2;
@@ -97,8 +97,49 @@ GlobalState
   // Set annotation defaults
   m_AnnotationSettings.shownOnAllSlices = false;
 
+  m_PolygonDrawingContextMenuModel = NewSimpleConcreteProperty(false);
+
+  // Create the drawing label model
+  m_DrawingColorLabelModel = ConcreteColorLabelPropertyModel::New();
+
+  // Create the draw-over label model
+  m_DrawOverFilterModel = ConcreteDrawOverFilterPropertyModel::New();
+
+  // Polygon inversion - create and initialize
+  m_PolygonInvertModel = NewSimpleConcreteProperty(false);
+
+  m_SnakeInitializedWithManualSegmentationModel = NewSimpleConcreteProperty(false);
+
+  // Mesh options
+  m_MeshOptions = MeshOptions::New();
+
+  // Default behaviors
+  m_DefaultBehaviorSettings = DefaultBehaviorSettings::New();
+
+  // Project stuff
+  m_ProjectFilenameModel = NewSimpleConcreteProperty(std::string());
+
+  // Initialize the properties
+  m_ToolbarModeModel = NewSimpleConcreteProperty(CROSSHAIRS_MODE);
+  m_ToolbarMode3DModel = NewSimpleConcreteProperty(TRACKBALL_MODE);
+
+  m_SliceViewLayerLayoutModel = NewSimpleConcreteProperty(LAYOUT_STACKED);
+}
+
+void GlobalState::SetDriver(IRISApplication *parent)
+{
+  m_Driver = parent;
+
+  m_DrawingColorLabelModel->Initialize(parent->GetColorLabelTable());
+  m_DrawingColorLabelModel->SetValue(
+        parent->GetColorLabelTable()->FindNextValidLabel(0,false));
+
+  // Create the draw-over label model
+  m_DrawOverFilterModel->Initialize(parent->GetColorLabelTable());
+  m_DrawOverFilterModel->SetValue(DrawOverFilter(PAINT_OVER_ALL, 0));
 }
 
+
 GlobalState
 ::~GlobalState() 
 {
@@ -139,101 +180,34 @@ GlobalState
 
 #endif /* DRAWING_LOCK */
 
-/**
- * Pulls the extension off of a filename and
- * saves it for future use in saving preproc
- * data
- *
- * PRE: none
- * POST: if fname is valid, m_GreyFileExtension will
- * have the file extension (including leading
- * period) of the file
- */
-void 
-GlobalState
-::SetGreyExtension(const char *fname)
+
+void GlobalState::SetCoverageMode(CoverageModeType coverage)
 {
-  const char * basename;
-  // Make sure fname is valid
-  if(fname != NULL)
-    {
+  DrawOverFilter f = this->GetDrawOverFilter();
+  f.CoverageMode = coverage;
+  this->SetDrawOverFilter(f);
+}
 
-    // Get rid of any currently saved
-    // extension
-    if(m_GreyFileExtension != NULL)
-      {                                                 
-      delete [] m_GreyFileExtension;
-      m_GreyFileExtension = NULL;
-      }
-
-    // Get rid of all path information
-    // TODO: This is platform specific!!!
-    basename = strrchr(fname, '/');
-    if(basename)
-      {
-      basename++;
-      }
-    else
-      {
-      basename = fname;
-      }
-
-    // Find the first period and count everything
-    // to the right of it as path.  Allows for
-    // multiple periods (ie .hdr.gz)
-    basename = strchr(basename, '.');
-    if(basename)
-      {
-      m_GreyFileExtension = new char[strlen(basename) + 1];
-      strcpy(m_GreyFileExtension, basename);
-      }
-    }
+CoverageModeType GlobalState::GetCoverageMode() const
+{
+  return this->GetDrawOverFilter().CoverageMode;
 }
 
-/**
- * Returns the extension for the grey file,
- * user is responsible for deallocating the
- * memory for ext
- * PRE: ext is NULL or dynamically allocated array
- * POST: ext points to a null terminated string
- * which contains the extension in m_GreyFileExtension
- * or ext is NULL if m_GreyFileExtension is empty
- */
-void 
-GlobalState
-::GetGreyExtension(char *& ext)
+bool GlobalState::isSegmentationROIValid()
 {
-  // Get rid of any data in ext
-  if(ext != NULL)
-    delete [] ext;
-
-  // Copy m_GreyFileExtension into ext
-  if(m_GreyFileExtension == NULL)
-    ext = NULL;
-  else
-    {
-    ext = new char[strlen(m_GreyFileExtension) + 1];
-    strcpy(ext, m_GreyFileExtension);
-    }
+  return this->GetSegmentationROI().GetNumberOfPixels() > 0;
 }
 
-/** Set the colormap in current preprocessing mode*/
-void 
-GlobalState
-::SetSpeedColorMap(ColorMapPreset xPreset)
+void GlobalState::SetSegmentationROI(const GlobalState::RegionType &roi)
 {
-  if(m_SnakeMode == EDGE_SNAKE)
-    SetSpeedColorMapInEdgeMode(xPreset);
-  else
-    SetSpeedColorMapInRegionMode(xPreset);
+  SNAPSegmentationROISettings s = this->GetSegmentationROISettings();
+  s.SetROI(roi);
+  this->SetSegmentationROISettings(s);
 }
 
-/** Get the colormap in current preprocessing mode*/
-ColorMapPreset 
-GlobalState
-::GetSpeedColorMap()
+GlobalState::RegionType GlobalState::GetSegmentationROI()
 {
-  return (m_SnakeMode == EDGE_SNAKE) ?
-    GetSpeedColorMapInEdgeMode() : GetSpeedColorMapInRegionMode();
+  return this->GetSegmentationROISettings().GetROI();
 }
 
+
diff --git a/Logic/Framework/GlobalState.h b/Logic/Framework/GlobalState.h
index 64fbc7a..e4381b7 100644
--- a/Logic/Framework/GlobalState.h
+++ b/Logic/Framework/GlobalState.h
@@ -43,39 +43,18 @@
 #ifndef __GlobalState_h_
 #define __GlobalState_h_
 
+class IRISApplication;
+class MeshOptions;
+class DefaultBehaviorSettings;
+
 #include <vector>
 #include "SNAPCommon.h"
-#include "EdgePreprocessingSettings.h"
-#include "MeshOptions.h"
 #include "SnakeParameters.h"
 #include "ThresholdSettings.h"
 #include "SNAPSegmentationROISettings.h"
 #include "itkImageRegion.h"
-
-enum ToolbarModeType 
-{
-  POLYGON_DRAWING_MODE,
-  NAVIGATION_MODE,
-  CROSSHAIRS_MODE,
-  PAINTBRUSH_MODE,
-  ANNOTATION_MODE,
-  ROI_MODE
-};
-
-enum ToolbarMode3DType
-{
-  TRACKBALL_MODE,
-  CROSSHAIRS_3D_MODE,
-  SPRAYPAINT_MODE,
-  SCALPEL_MODE
-};
-
-enum CoverageModeType 
-{
-  PAINT_OVER_ALL,
-  PAINT_OVER_ONE,
-  PAINT_OVER_COLORS
-};
+#include "PropertyModel.h"
+#include "ColorLabelPropertyModel.h"
 
 enum MeshFilterType
 {
@@ -90,6 +69,18 @@ enum SnakeType
   EDGE_SNAKE
 };
 
+/**
+  Available modes for speed image generation
+  */
+enum PreprocessingMode
+{
+  PREPROCESS_NONE = 0,
+  PREPROCESS_THRESHOLD,
+  PREPROCESS_EDGE,
+  PREPROCESS_GMM,
+  PREPROCESS_RF
+};
+
 enum ConstraintsType 
 {
   SAPIRO,
@@ -98,16 +89,6 @@ enum ConstraintsType
   USER
 };
   
-/** Color map presets */
-enum ColorMapPreset 
-{
-  COLORMAP_BLACK_BLACK_WHITE = 0,
-  COLORMAP_BLUE_BLACK_WHITE,
-  COLORMAP_BLACK_GRAY_WHITE,
-  COLORMAP_BLUE_WHITE_RED,
-  COLORMAP_BLACK_YELLOW_WHITE
-};
-
 enum PaintbrushMode
 {
   PAINTBRUSH_RECTANGULAR = 0,
@@ -115,11 +96,35 @@ enum PaintbrushMode
   PAINTBRUSH_WATERSHED = 2
 };
   
-enum AnatomicalDirection
+enum DisplayPanel
+{
+  PANEL_AXIAL = 0,
+  PANEL_SAGITTAL,
+  PANEL_CORONAL,
+  PANEL_3D
+};
+
+enum ToolbarModeType
 {
-  ANATOMY_AXIAL = 0,
-  ANATOMY_SAGITTAL,
-  ANATOMY_CORONAL
+  CROSSHAIRS_MODE = 0,
+  NAVIGATION_MODE,
+  POLYGON_DRAWING_MODE,
+  PAINTBRUSH_MODE,
+  ROI_MODE,
+  ANNOTATION_MODE
+};
+
+enum ToolbarMode3DType
+{
+  TRACKBALL_MODE = 0,
+  CROSSHAIRS_3D_MODE,
+  SPRAYPAINT_MODE,
+  SCALPEL_MODE
+};
+
+/** Layout of overlays in a slice view */
+enum LayerLayout {
+  LAYOUT_STACKED = 0, LAYOUT_TILED
 };
 
 /** Watershed settings for paintbrush */
@@ -138,7 +143,7 @@ struct PaintbrushSettings
 {
   double radius;
   PaintbrushMode mode;
-  bool flat;
+  bool volumetric;
   bool isotropic;
   bool chase;
 
@@ -166,31 +171,24 @@ struct Bubble {
 /**
  * \class GlobalState
  * \brief Contains global variables describing the state of the application.
+ *
+ * TODO: this class should be refactored to use PropertyModel objects for all
+ * the various settings, rather than mixing PropertyModels with simple attributes.
+ *
  */
-class GlobalState 
+class GlobalState : public AbstractModel
 {
 public:
+  irisITKObjectMacro(GlobalState, AbstractModel)
+
   // Region of interest definition
   typedef itk::ImageRegion<3> RegionType;
 
   // Define the bubble array
   typedef std::vector<Bubble> BubbleArray;
 
-  GlobalState();
-  virtual ~GlobalState();
-  
-  /** Get color label used to draw polygons */
-  irisSetMacro(DrawingColorLabel,LabelType);
-
-  /** Set color label used to draw polygons */
-  irisGetMacro(DrawingColorLabel,LabelType);
-  
-  /** Get color label over which we can draw */
-  irisSetMacro(OverWriteColorLabel,LabelType);
+  void SetDriver(IRISApplication *app);
 
-  /** Set color label over which we can draw */
-  irisGetMacro(OverWriteColorLabel,LabelType);
-  
   /** Get whether the grey image display uses linear interpolation */
   irisSetMacro(InterpolateGrey,bool );
 
@@ -203,29 +201,8 @@ public:
   /** Set whether the segmentation image uses linear interpolation */
   irisGetMacro(InterpolateSegmentation,bool );
 
-  /** Get whether polygons drawn are inverted or not */
-  irisSetMacro(PolygonInvert,bool );
-
-  /** Set whether polygons drawn are inverted or not */
-  irisGetMacro(PolygonInvert,bool );
-
-  /** Get the transparency of the segmentation overlay */
-  irisSetMacro(SegmentationAlpha,unsigned char );
-
-  /** Set the transparency of the segmentation overlay */
-  irisGetMacro(SegmentationAlpha,unsigned char );
-
-  /** Get the current toolbar mode */
-  irisSetMacro(ToolbarMode,ToolbarModeType );
-
-  /** Set the current toolbar mode */
-  irisGetMacro(ToolbarMode,ToolbarModeType );
-
-  /** Get the current 3D toolbar mode */
-  irisSetMacro(ToolbarMode3D,ToolbarMode3DType);
-
-  /** Set the current 3D toolbar mode */
-  irisGetMacro(ToolbarMode3D,ToolbarMode3DType);
+  /** Get/Set the on/off state of the segmentation overlay */
+  irisRangedPropertyAccessMacro(SegmentationAlpha, double)
 
   /** Get whether the slice requires an update or not (TODO: obsolete?) */
   irisSetMacro(UpdateSliceFlag,int );
@@ -234,16 +211,13 @@ public:
   irisGetMacro(UpdateSliceFlag,int );
 
   /** Get current mode of polygon/snake painting (over all, over label) */
-  irisSetMacro(CoverageMode,CoverageModeType );
+  void SetCoverageMode(CoverageModeType coverage);
 
   /** Set current mode of polygon/snake painting (over all, over label) */
-  irisGetMacro(CoverageMode,CoverageModeType );
-
-  /** Get whether the region of interest is valid */
-  irisSetMacro(IsValidROI,bool );
+  CoverageModeType GetCoverageMode() const;
 
   /** Set whether the region of interest is valid */
-  irisGetMacro(IsValidROI,bool );
+  bool isSegmentationROIValid();
 
   /** Get whether the region of interest is visible */
   irisSetMacro(ShowROI,bool );
@@ -263,12 +237,6 @@ public:
   /** Set whether SNAP is currently active */
   irisGetMacro(SNAPActive,bool );
 
-  /** Get whether the speed (preprocessing) image is visible */
-  irisSetMacro(ShowSpeed,bool );
-
-  /** Set whether the speed (preprocessing) image is visible */
-  irisGetMacro(ShowSpeed,bool );
-
   /** Get whether the speed (preprocessing) image is valid */
   irisSetMacro(SpeedValid,bool );
 
@@ -281,93 +249,36 @@ public:
   /** Set whether the zero level of the speed image is being displayed */
   irisGetMacro(SpeedViewZero,bool );
 
-  /** Get the colormap used to display speed in edge mode */
-  irisGetMacro(SpeedColorMapInEdgeMode, ColorMapPreset);
-
-  /** Set the colormap used to display speed in edge mode */
-  irisSetMacro(SpeedColorMapInEdgeMode, ColorMapPreset);
-
-  /** Get the colormap used to display speed in region mode */
-  irisGetMacro(SpeedColorMapInRegionMode, ColorMapPreset);
-
-  /** Set the colormap used to display speed in region mode */
-  irisSetMacro(SpeedColorMapInRegionMode, ColorMapPreset);
-
-  /** Set the colormap in current preprocessing mode*/
-  void SetSpeedColorMap(ColorMapPreset xPreset);
+  /**
+   * The last 'real' preprocessing mode used in the application. This
+   * is stored so that the preprocessing mode can be remembered next
+   * time that we enter active contour mode.
+   */
+  irisSimplePropertyAccessMacro(LastUsedPreprocessingMode, PreprocessingMode)
 
-  /** Get the colormap in current preprocessing mode*/
-  ColorMapPreset GetSpeedColorMap();
+  /** The domain of values for snake type (edge/region) */
+  typedef SimpleItemSetDomain<SnakeType, std::string> SnakeTypeDomain;
 
   /** Get the type of the snake being used */
-  irisSetMacro(SnakeMode,SnakeType );
-
-  /** Set the type of the snake being used */
-  irisGetMacro(SnakeMode,SnakeType );
-
-  /** Get whether the snake is currently active */
-  irisSetMacro(SnakeActive,bool );
-
-  /** Set whether the snake is currently active */
-  irisGetMacro(SnakeActive,bool );
-
-  /** Set whether the speed preview is valid or not */
-  irisSetMacro(SpeedPreviewValid, bool);
-  
-  /** Get whether the speed preview is valid or not */
-  irisGetMacro(SpeedPreviewValid, bool);
-  
-  /** Set the auto-preview feature of edge-mode preprocessor uses  */
-  irisSetMacro(ShowPreprocessedEdgePreview,bool);
-
-  /** Get the auto-preview feature of edge-mode preprocessor uses  */
-  irisGetMacro(ShowPreprocessedEdgePreview,bool);
-
-  /** Set the auto-preview feature of edge-mode preprocessor uses  */
-  irisSetMacro(ShowPreprocessedInOutPreview,bool);
-
-  /** Get the auto-preview feature of edge-mode preprocessor uses  */
-  irisGetMacro(ShowPreprocessedInOutPreview,bool);
-
-  /** Get the current settings for in/out snake processing */
-  irisGetMacro(ThresholdSettings,ThresholdSettings);
-
-  /** Set the current settings for in/out snake processing */
-  irisSetMacro(ThresholdSettings,ThresholdSettings);  
-
-  /** Set the current settings for edge snake processing */
-  irisSetMacro(EdgePreprocessingSettings,EdgePreprocessingSettings);  
-
-  /** Get the current settings for edge snake processing */
-  irisGetMacro(EdgePreprocessingSettings,EdgePreprocessingSettings);
+  irisGenericPropertyAccessMacro(SnakeType, SnakeType, SnakeTypeDomain)
 
   /** Get the current parameters of the snake algorithm */
-  irisGetMacro(SnakeParameters,SnakeParameters);
-
-  /** Set the current parameters of the snake algorithm */
-  irisSetMacro(SnakeParameters,SnakeParameters);
+  irisSimplePropertyAccessMacro(SnakeParameters, SnakeParameters)
 
   /** Get the current mesh rendering options */
-  irisGetMacro(MeshOptions,MeshOptions);
-
-  /** Set the current mesh rendering options */
-  irisSetMacro(MeshOptions,MeshOptions);
+  irisGetMacro(MeshOptions, MeshOptions *)
 
-  /** Set the settings associated with the region of interest extracted for
-   segmentation */
-  irisSetMacro(SegmentationROISettings,const SNAPSegmentationROISettings &);
+  /** Get the default behavior settings */
+  irisGetMacro(DefaultBehaviorSettings, DefaultBehaviorSettings *)
 
-  /** Set the settings associated with the region of interest extracted for
-   segmentation */
-  irisGetMacro(SegmentationROISettings,const SNAPSegmentationROISettings &);
+  /** Settings associated with the segmentation ROI */
+  irisSimplePropertyAccessMacro(SegmentationROISettings, SNAPSegmentationROISettings)
 
   /** Shortcut ot set the actual bounding box in the ROI from the settings */
-  void SetSegmentationROI(const RegionType &roi)
-    { m_SegmentationROISettings.SetROI(roi); }
+  void SetSegmentationROI(const RegionType &roi);
 
   /** Shortcut ot get the actual bounding box in the ROI from the settings */
-  RegionType GetSegmentationROI()
-    { return m_SegmentationROISettings.GetROI(); }
+  RegionType GetSegmentationROI();
 
   /** Get the current paintbrush settings */
   irisGetMacro(PaintbrushSettings, const PaintbrushSettings &);
@@ -386,48 +297,6 @@ public:
   int ReleaseDrawingLock( short );
 #endif /* DRAWING_LOCK */
 
-  /** Set the extension of the grey image */
-  void SetGreyExtension(const char * fname);
-  
-  /** Get the extension of the grey image */
-  void GetGreyExtension(char *& ext);
-
-  /** Set the grey image file name */
-  irisSetStringMacro(GreyFileName);
-
-  /** Get the grey image file name */
-  irisGetStringMacro(GreyFileName);
-
-  /** Set the grey overlay image file name */
-  irisSetStringMacro(GreyOverlayFileName);
-
-  /** Get the grey overlay image file name */
-  irisGetStringMacro(GreyOverlayFileName);
-
-  /** Set the RGB image file name */
-  irisSetStringMacro(RGBFileName);
-
-  /** Get the RGB image file name */
-  irisGetStringMacro(RGBFileName);
-
-  /** Set the RGB overlay image file name */
-  irisSetStringMacro(RGBOverlayFileName);
-
-  /** Get the RGB overlay image file name */
-  irisGetStringMacro(RGBOverlayFileName);
-
-  /** Set the segmentation image file name */
-  irisSetStringMacro(SegmentationFileName);
-
-  /** Get the segmentation image file name */
-  irisGetStringMacro(SegmentationFileName);
-
-  /** Set the preprocessing image file name */
-  irisSetStringMacro(PreprocessingFileName);
-
-  /** Get the preprocessing image file name */
-  irisGetStringMacro(PreprocessingFileName);
-
   /** Set the segmentation image file name */
   irisSetStringMacro(LastAssociatedSegmentationFileName);
 
@@ -440,20 +309,6 @@ public:
   /** Get the preprocessing image file name */
   irisGetStringMacro(LastAssociatedPreprocessingFileName);
 
-  /** Set the preprocessing image file name */
-  irisSetStringMacro(LevelSetFileName);
-
-  /** Get the preprocessing image file name */
-  irisGetStringMacro(LevelSetFileName);
-
-  /** Set the advection file name */
-  void SetAdvectionFileName(unsigned int i, const char *name)
-    { m_AdvectionFileName[i] = name; }
-
-  /** Get the advection file name */
-  const char *GetAdvectionFileName(unsigned int i)
-    { return m_AdvectionFileName[i].c_str(); }
-
   /** Get the array of bubbles */
   irisGetMacro(BubbleArray, BubbleArray);
 
@@ -480,6 +335,49 @@ public:
   void UnsetActiveBubble()
     { m_ActiveBubble = -1; }
 
+  /** Get the polygon access menu flag */
+  irisSimplePropertyAccessMacro(PolygonDrawingContextMenu, bool)
+
+  /** Get the drawing label */
+  irisGenericPropertyAccessMacro(DrawingColorLabel, LabelType,
+                                 ColorLabelItemSetDomain)
+
+  /** Get the draw over label */
+  irisGenericPropertyAccessMacro(DrawOverFilter, DrawOverFilter,
+                                 DrawOverLabelItemSetDomain)
+
+  /** Whether drawing operations are inverted */
+  irisSimplePropertyAccessMacro(PolygonInvert, bool)
+
+  /** Whether the snake has been initialized with a manual segmentation, i.e.
+    before running segmentation with label X, the user has labeled some voxels
+    with label X. Only applicable in snake mode. */
+  irisSimplePropertyAccessMacro(SnakeInitializedWithManualSegmentation, bool)
+
+  /** Get/Set the current toolbar mode */
+  irisSimplePropertyAccessMacro(ToolbarMode,ToolbarModeType)
+
+  /** Set/Get the current 3D toolbar mode */
+  irisSimplePropertyAccessMacro(ToolbarMode3D,ToolbarMode3DType)
+
+  /** Set/Get the layout of multiple layers in slice views */
+  irisSimplePropertyAccessMacro(SliceViewLayerLayout, LayerLayout)
+
+  // ----------------------- Project support ------------------------------
+
+  /**
+   * Model for the filename of the current project. This is an empty string if
+   * there is no project.
+   */
+  irisSimplePropertyAccessMacro(ProjectFilename, std::string)
+
+  // --------------------- End Project support ----------------------------
+
+protected:
+
+  GlobalState();
+  virtual ~GlobalState();
+
 private:
 
   /** Get the current crosshairs position */
@@ -491,10 +389,10 @@ private:
   friend class IRISApplication;
 
   /** Color label used to draw polygons */
-  LabelType m_DrawingColorLabel;
+  SmartPtr<ConcreteColorLabelPropertyModel> m_DrawingColorLabelModel;
 
   /** Color label over which we can draw */
-  LabelType m_OverWriteColorLabel;
+  SmartPtr<ConcreteDrawOverFilterPropertyModel> m_DrawOverFilterModel;
 
   /** Whether the grey image display uses linear interpolation */
   bool m_InterpolateGrey;
@@ -502,30 +400,15 @@ private:
   /** Whether the segmentation image uses linear interpolation */
   bool m_InterpolateSegmentation;
 
-  /** Whether polygons drawn are inverted or not */
-  bool m_PolygonInvert;
-
   /** The transparency of the segmentation overlay */
-  unsigned char m_SegmentationAlpha;
+  SmartPtr<ConcreteRangedDoubleProperty> m_SegmentationAlphaModel;
 
   /** The current crosshairs position */
   Vector3ui m_CrosshairsPosition;
 
-  /** The current toolbar mode */
-  ToolbarModeType m_ToolbarMode;
-
-  /** The current 3D toolbar mode */
-  ToolbarMode3DType m_ToolbarMode3D;
-
   /** Whether the slice requires an update or not (TODO: obsolete?) */
   int m_UpdateSliceFlag;
 
-  /** Current mode of polygon/snake painting (over all, over label) */
-  CoverageModeType m_CoverageMode;
-
-  /** Whether the region of interest is valid */
-  bool m_IsValidROI;
-
   /** Whether the region of interest is visible */
   bool m_ShowROI;
 
@@ -535,81 +418,64 @@ private:
   /** Whether SNAP is currently active */
   bool m_SNAPActive;
 
-  /** Whether the speed (preprocessing) image is visible */
-  bool m_ShowSpeed;
-
   /** Whether the speed (preprocessing) image is valid */
   bool m_SpeedValid;
 
   /** Whether the zero level of the speed image is being displayed */
   bool m_SpeedViewZero;
 
-  /** Color map preset in edge mode */
-  ColorMapPreset m_SpeedColorMapInEdgeMode;
-
-  /** Color map preset in region mode */
-  ColorMapPreset m_SpeedColorMapInRegionMode;
-
   /** The type of the snake being used */
-  SnakeType m_SnakeMode;
+  typedef ConcretePropertyModel<SnakeType, SnakeTypeDomain> SnakeTypeModel;
+  SmartPtr<SnakeTypeModel> m_SnakeTypeModel;
 
-  /** Whether the snake is currently active */
-  bool m_SnakeActive;
+  /** The last real preprocessing mode used in the program */
+  SmartPtr<ConcretePropertyModel<PreprocessingMode> > m_LastUsedPreprocessingModeModel;
 
   /** Grey image file extension */
   char * m_GreyFileExtension; 
 
   /** The region of interest for the segmentation (drawn by the user) */
-  SNAPSegmentationROISettings m_SegmentationROISettings;
-  
-  int m_LockHeld; 
-  int m_LockOwner;
+  SmartPtr<ConcretePropertyModel<SNAPSegmentationROISettings> > m_SegmentationROISettingsModel;
 
-  // Current settings for threshold preprocessing
-  ThresholdSettings m_ThresholdSettings;
+  /** Whether the context menu is enabled for polygon drawing. I don't think
+    this is the right place to put this, because it's quite GUI specific, but
+    for the time being, I stick it here */
+  SmartPtr<ConcreteSimpleBooleanProperty> m_PolygonDrawingContextMenuModel;
 
-  // Current settings for threshold preprocessing
-  EdgePreprocessingSettings m_EdgePreprocessingSettings;
+  /** Whether drawing operations are inverted */
+  SmartPtr<ConcreteSimpleBooleanProperty> m_PolygonInvertModel;
 
-  // Current mesh options
-  MeshOptions m_MeshOptions;
+  /** Whether snake has been initialized with manual seg voxels */
+  SmartPtr<ConcreteSimpleBooleanProperty> m_SnakeInitializedWithManualSegmentationModel;
 
-  // Whether preview is valid or not
-  bool m_SpeedPreviewValid;
-  
-  // Auto-preview state
-  bool m_ShowPreprocessedEdgePreview;
-  bool m_ShowPreprocessedInOutPreview;
+  // The current 2D toolbar mode
+  SmartPtr<ConcretePropertyModel<ToolbarModeType> > m_ToolbarModeModel;
 
-  // Current settings for the snake algorithm
-  SnakeParameters m_SnakeParameters;
+  // The current 3D toolbar mode
+  SmartPtr<ConcretePropertyModel<ToolbarMode3DType> > m_ToolbarMode3DModel;
 
-  // File name of the current grey file
-  std::string m_GreyFileName;
+  // Slice view layout model
+  SmartPtr<ConcretePropertyModel<LayerLayout> > m_SliceViewLayerLayoutModel;
+  
+  int m_LockHeld; 
+  int m_LockOwner;
 
-  // File name of the current grey overlay file
-  std::string m_GreyOverlayFileName;
+  // Current mesh options
+  SmartPtr<MeshOptions> m_MeshOptions;
 
-  // File name of the current RGB file
-  std::string m_RGBFileName;
+  // Default behavior settings
+  SmartPtr<DefaultBehaviorSettings> m_DefaultBehaviorSettings;
 
-  // File name of the current RGB overlay file
-  std::string m_RGBOverlayFileName;
+  // Current settings for the snake algorithm
+  typedef ConcretePropertyModel<SnakeParameters, TrivialDomain> ConcreteSnakeParametersModel;
+  SmartPtr<ConcreteSnakeParametersModel> m_SnakeParametersModel;
 
   // File name of the current grey file
-  std::string m_SegmentationFileName;
   std::string m_LastAssociatedSegmentationFileName;
 
   // File name of the current preprocessing file
-  std::string m_PreprocessingFileName;
   std::string m_LastAssociatedPreprocessingFileName;
 
-  // File name of level set image file
-  std::string m_LevelSetFileName;
-
-  // File names for advection images
-  std::string m_AdvectionFileName[3];
-
   // Array of bubbles
   BubbleArray m_BubbleArray;
 
@@ -622,6 +488,11 @@ private:
   // Annotation settings
   AnnotationSettings m_AnnotationSettings;
 
+  IRISApplication *m_Driver;
+
+  // ------------------- Project Related -----------------------------------
+  SmartPtr<ConcreteSimpleStringProperty> m_ProjectFilenameModel;
+
 };
 
 #endif // __GlobalState_h_
diff --git a/Logic/Framework/IRISApplication.cxx b/Logic/Framework/IRISApplication.cxx
index 861a374..16e0eda 100644
--- a/Logic/Framework/IRISApplication.cxx
+++ b/Logic/Framework/IRISApplication.cxx
@@ -38,14 +38,14 @@
 #include "SNAPBorlandDummyTypes.h"
 #endif
 
+#include "IRISException.h"
 #include "IRISApplication.h"
-
 #include "GlobalState.h"
 #include "GuidedNativeImageIO.h"
 #include "IRISImageData.h"
 #include "IRISVectorTypesToITKConversion.h"
 #include "SNAPImageData.h"
-#include "MeshObject.h"
+#include "MeshManager.h"
 #include "MeshExportSettings.h"
 #include "SegmentationStatistics.h"
 #include "itkImageRegionIterator.h"
@@ -61,102 +61,135 @@
 #include "itkWindowedSincInterpolateImageFunction.h"
 #include "itkImageFileWriter.h"
 #include "itkFlipImageFilter.h"
+#include "itkConstantBoundaryCondition.h"
 #include <itksys/SystemTools.hxx>
 #include "vtkAppendPolyData.h"
 #include "vtkUnsignedShortArray.h"
 #include "vtkPointData.h"
-
+#include "SNAPRegistryIO.h"
+#include "Rebroadcaster.h"
+#include "HistoryManager.h"
 #include "IRISSlicer.h"
+#include "EdgePreprocessingSettings.h"
+#include "ThresholdSettings.h"
+#include "SlicePreviewFilterWrapper.h"
+#include "PreprocessingFilterConfigTraits.h"
+#include "SmoothBinaryThresholdImageFilter.h"
+#include "EdgePreprocessingImageFilter.h"
+#include "UnsupervisedClustering.h"
+#include "GMMClassifyImageFilter.h"
+#include "DefaultBehaviorSettings.h"
+#include "ColorMapPresetManager.h"
+#include "ImageIODelegates.h"
+#include "IRISDisplayGeometry.h"
+#include "RFClassificationEngine.h"
+#include "RandomForestClassifyImageFilter.h"
+#include "LabelUseHistory.h"
 
 
 #include <stdio.h>
 #include <sstream>
 #include <iomanip>
 
-
 IRISApplication
 ::IRISApplication() 
 : m_UndoManager(4,200000)
 {
-  // Construct new global state object
-  m_GlobalState = new GlobalState;
-
   // Create a new system interface
   m_SystemInterface = new SystemInterface();
+  m_HistoryManager = m_SystemInterface->GetHistoryManager();
+
+  // Create a color map preset manager
+  m_ColorMapPresetManager = ColorMapPresetManager::New();
+  m_ColorMapPresetManager->Initialize(m_SystemInterface);
 
   // Initialize the color table
-  m_ColorLabelTable = new ColorLabelTable();
+  m_ColorLabelTable = ColorLabelTable::New();
+
+  // Initialize the label use history
+  m_LabelUseHistory = LabelUseHistory::New();
+  m_LabelUseHistory->SetColorLabelTable(m_ColorLabelTable);
 
   // Contruct the IRIS and SNAP data objects
-  m_IRISImageData = new IRISImageData(this);
-  m_SNAPImageData = NULL;
+  m_IRISImageData = IRISImageData::New();
+  m_IRISImageData->SetParent(this);
+
+  m_SNAPImageData = SNAPImageData::New();
+  m_SNAPImageData->SetParent(this);
 
   // Set the current IRIS pointer
-  m_CurrentImageData = m_IRISImageData;
+  m_CurrentImageData = m_IRISImageData.GetPointer();
+
+  // Listen to events from wrappers and image data objects and refire them
+  // as our own events.
+  Rebroadcaster::RebroadcastAsSourceEvent(m_IRISImageData, WrapperChangeEvent(), this);
+  Rebroadcaster::RebroadcastAsSourceEvent(m_SNAPImageData, WrapperChangeEvent(), this);
+
+  // TODO: should this also be a generic Wrapper Image Data change event?
+  Rebroadcaster::RebroadcastAsSourceEvent(m_SNAPImageData, LevelSetImageChangeEvent(), this);
+
+  // Construct new global state object
+  m_GlobalState = GlobalState::New();
+  m_GlobalState->SetDriver(this);
+
+  // Initialize the preprocessing settings
+  // TODO: m_ThresholdSettings = ThresholdSettings::New();
+  m_EdgePreprocessingSettings = EdgePreprocessingSettings::New();
+
+  // Initialize the preprocessing filter preview wrappers
+  m_ThresholdPreviewWrapper = ThresholdPreviewWrapperType::New();
+  // TODO: m_ThresholdPreviewWrapper->SetParameters(m_ThresholdSettings);
+
+  m_EdgePreviewWrapper = EdgePreprocessingPreviewWrapperType::New();
+  m_EdgePreviewWrapper->SetParameters(m_EdgePreprocessingSettings);
+
+  m_GMMPreviewWrapper = GMMPreprocessingPreviewWrapperType::New();
 
-  // Initialize the display-anatomy transformation with RPI code
-  m_DisplayToAnatomyRAI[0] = "RPS";
-  m_DisplayToAnatomyRAI[1] = "AIR";
-  m_DisplayToAnatomyRAI[2] = "RIP";
+  m_RandomForestPreviewWrapper = RFPreprocessingPreviewWrapperType::New();
+  m_LastUsedRFClassifierComponents = 0;
+
+  m_PreprocessingMode = PREPROCESS_NONE;
+
+  // Initialize the mesh management object
+  m_MeshManager = MeshManager::New();
+  m_MeshManager->Initialize(this);
 }
 
-std::string
-IRISApplication::
-GetImageToAnatomyRAI()
+
+bool
+IRISApplication
+::IsImageOrientationOblique()
 {
   assert(m_CurrentImageData->IsMainLoaded());
-  return ImageCoordinateGeometry::ConvertDirectionMatrixToClosestRAICode(
+  return ImageCoordinateGeometry::IsDirectionMatrixOblique(
     m_CurrentImageData->GetImageGeometry().GetImageDirectionCosineMatrix());
 }
 
 
 std::string
 IRISApplication::
-GetDisplayToAnatomyRAI(unsigned int slice)
+GetImageToAnatomyRAI()
 {
-  return m_DisplayToAnatomyRAI[slice];
+  assert(m_CurrentImageData->IsMainLoaded());
+  return ImageCoordinateGeometry::ConvertDirectionMatrixToClosestRAICode(
+    m_CurrentImageData->GetImageGeometry().GetImageDirectionCosineMatrix());
 }
 
-
 IRISApplication
 ::~IRISApplication() 
 {
-  delete m_IRISImageData;
-  if(m_SNAPImageData)
-    delete m_SNAPImageData;
-  delete m_GlobalState;
-  delete m_ColorLabelTable;
   delete m_SystemInterface;
 }
 
 void 
 IRISApplication
 ::InitializeSNAPImageData(const SNAPSegmentationROISettings &roi,
-                          CommandType *progressCommand) 
+                          CommandType *progressCommand)
 {
-  assert(m_SNAPImageData == NULL);
   assert(m_IRISImageData->IsMainLoaded());
 
   // Create the SNAP image data object
-  m_SNAPImageData = new SNAPImageData(this);
-
-  // Get the roi chunk from the grey image
-  GreyImageType::Pointer imgNewGrey = 
-    m_IRISImageData->GetGrey()->DeepCopyRegion(roi,progressCommand);
-
-  // Get the size of the region
-  Vector3ui size = to_unsigned_int(
-    Vector3ul(imgNewGrey->GetLargestPossibleRegion().GetSize().GetSize()));
-
-  // Compute an image coordinate geometry for the region of interest  
-  ImageCoordinateGeometry icg(
-    m_IRISImageData->GetImageGeometry().GetImageDirectionCosineMatrix(),
-    m_DisplayToAnatomyRAI, size);
-
-  // Assign the new wrapper to the target
-  m_SNAPImageData->SetGreyImage(
-    imgNewGrey, icg,
-    m_IRISImageData->GetGrey()->GetNativeMapping());
+  m_SNAPImageData->InitializeToROI(m_IRISImageData, roi, progressCommand);
   
   // Override the interpolator in ROI for label interpolation, or we will get
   // nonsense
@@ -172,14 +205,20 @@ IRISApplication
   LabelType passThroughLabel = m_GlobalState->GetDrawingColorLabel();
 
   typedef itk::ImageRegionIterator<LabelImageType> IteratorType;
-  IteratorType itLabel(imgNewLabel,imgNewLabel->GetBufferedRegion());  
+  IteratorType itLabel(imgNewLabel,imgNewLabel->GetBufferedRegion());
+  unsigned int nCopied = 0;
   while(!itLabel.IsAtEnd())
     {
     if(itLabel.Value() != passThroughLabel)
       itLabel.Value() = (LabelType) 0;
+    else
+      nCopied++;
     ++itLabel;
     }
 
+  // Record whether the segmentation has any values that are not zero
+  m_GlobalState->SetSnakeInitializedWithManualSegmentation(nCopied > 0);
+
   // Pass the cleaned up segmentation image to SNAP
   m_SNAPImageData->SetSegmentationImage(imgNewLabel);
 
@@ -187,52 +226,40 @@ IRISApplication
   m_SNAPImageData->SetColorLabel(
     m_ColorLabelTable->GetColorLabel(passThroughLabel));
 
-  // Assign the intensity mapping function to the Snap data
-  m_SNAPImageData->GetGrey()->SetReferenceIntensityRange(
-    m_IRISImageData->GetGrey()->GetImageMin(),
-    m_IRISImageData->GetGrey()->GetImageMax());
-  m_SNAPImageData->GetGrey()->CopyIntensityMap(*m_IRISImageData->GetGrey());
-  m_SNAPImageData->GetGrey()->UpdateIntensityMapFunction();
-
-  // Copy the colormap too
-  m_SNAPImageData->GetGrey()->SetColorMap(m_IRISImageData->GetGrey()->GetColorMap());
-
   // Initialize the speed image of the SNAP image data
   m_SNAPImageData->InitializeSpeed();
 
   // Remember the ROI object
   m_GlobalState->SetSegmentationROISettings(roi);
+
+  // Indicate that the speed image is invalid
+  m_GlobalState->SetSpeedValid(false);
+
+  // The set of layers has changed
+  InvokeEvent(LayerChangeEvent());
 }
 
 void 
 IRISApplication
-::SetDisplayToAnatomyRAI(const char *rai0,const char *rai1,const char *rai2)
+::SetDisplayGeometry(const IRISDisplayGeometry &dispGeom)
 {
-  // Store the new RAI code
-  m_DisplayToAnatomyRAI[0] = rai0;
-  m_DisplayToAnatomyRAI[1] = rai1;
-  m_DisplayToAnatomyRAI[2] = rai2;
+  // Store the new geometry
+  m_DisplayGeometry = dispGeom;
 
-  if(!m_IRISImageData->IsMainLoaded()) 
-    return;
-  
-  // Create the appropriate transform and pass it to the IRIS data
-  m_IRISImageData->SetImageGeometry(
-    ImageCoordinateGeometry(
-      m_IRISImageData->GetImageGeometry().GetImageDirectionCosineMatrix(),
-      m_DisplayToAnatomyRAI,
-      m_IRISImageData->GetVolumeExtents()));
-
-  // Do the same for the SNAP data if needed
-  if(!m_SNAPImageData)
-    return;
+  // If image data are loaded, propagate the geometry to them
+  if(m_IRISImageData->IsMainLoaded())
+    {
+    m_IRISImageData->SetDisplayGeometry(dispGeom);
+    }
 
   // Create the appropriate transform and pass it to the SNAP data
-  m_SNAPImageData->SetImageGeometry(
-    ImageCoordinateGeometry(
-      m_SNAPImageData->GetImageGeometry().GetImageDirectionCosineMatrix(),
-      m_DisplayToAnatomyRAI,
-      m_SNAPImageData->GetVolumeExtents()));
+  if(m_SNAPImageData->IsMainLoaded())
+    {
+    m_SNAPImageData->SetDisplayGeometry(dispGeom);
+    }
+
+  // Invoke the corresponding event
+  InvokeEvent(DisplayToAnatomyCoordinateMappingChangeEvent());
 }
 
 
@@ -242,10 +269,10 @@ IRISApplication
                        SnakeType snakeMode)
 {
   // This has to happen in SNAP mode
-  assert(m_SNAPImageData);
+  assert(IsSnakeModeActive());
 
   // Make sure the dimensions of the speed image are appropriate
-  assert(m_SNAPImageData->GetGrey()->GetImage()->GetBufferedRegion().GetSize()
+  assert(to_itkSize(m_SNAPImageData->GetMain()->GetSize())
     == newSpeedImage->GetBufferedRegion().GetSize());
 
   // Initialize the speed wrapper
@@ -256,63 +283,94 @@ IRISApplication
   m_SNAPImageData->GetSpeed()->SetImage(newSpeedImage);
 
   // Save the snake mode 
-  m_GlobalState->SetSnakeMode(snakeMode);
+  m_GlobalState->SetSnakeType(snakeMode);
 
   // Set the speed as valid
   m_GlobalState->SetSpeedValid(true);
 
   // Set the snake state
+  // TODO: fix this!
   if(snakeMode == EDGE_SNAKE)
     {
-    m_SNAPImageData->GetSpeed()->SetModeToEdgeSnake();
+    // m_SNAPImageData->GetSpeed()->SetModeToEdgeSnake();
     }
   else
     {
-    m_SNAPImageData->GetSpeed()->SetModeToInsideOutsideSnake();
+     // m_SNAPImageData->GetSpeed()->SetModeToInsideOutsideSnake();
     }
 }
 
-void
-IRISApplication
-::UnloadOverlays()
+void IRISApplication::UnloadOverlay(ImageWrapperBase *ovl)
 {
-  // unload all the overlays
-  m_IRISImageData->UnloadOverlays();
+  // Save the overlay associated settings
+  SaveMetaDataAssociatedWithLayer(ovl, OVERLAY_ROLE);
+
+  // Unload this overlay
+  m_IRISImageData->UnloadOverlay(ovl);
 
   // for overlay, we don't want to change the cursor location
   // just force the IRISSlicer to update
   m_IRISImageData->SetCrosshairs(m_GlobalState->GetCrosshairsPosition());
+
+  // Fire event
+  InvokeEvent(LayerChangeEvent());
 }
 
-void
-IRISApplication
-::UnloadOverlayLast()
+void IRISApplication::UnloadAllOverlays()
 {
-  // unload the last overlay
-  m_IRISImageData->UnloadOverlayLast();
+  LayerIterator it = m_IRISImageData->GetLayers(OVERLAY_ROLE);
+  for(; !it.IsAtEnd(); ++it)
+    SaveMetaDataAssociatedWithLayer(it.GetLayer(), OVERLAY_ROLE);
+
+  m_IRISImageData->UnloadOverlays();
 
   // for overlay, we don't want to change the cursor location
   // just force the IRISSlicer to update
   m_IRISImageData->SetCrosshairs(m_GlobalState->GetCrosshairsPosition());
+
+  // Fire event
+  InvokeEvent(LayerChangeEvent());
+
+}
+
+void IRISApplication
+::ChangeOverlayPosition(ImageWrapperBase *overlay, int dir)
+{
+  m_IRISImageData->MoveLayer(overlay, dir);
+  InvokeEvent(LayerChangeEvent());
 }
 
 void
 IRISApplication
-::ClearIRISSegmentationImage()
+::ResetIRISSegmentationImage()
 {
   // This has to happen in 'pure' IRIS mode
-  assert(m_SNAPImageData == NULL);
-
-  // Fill the image with blanks
-  this->m_IRISImageData->GetSegmentation()->GetImage()->FillBuffer(0);
-  this->m_IRISImageData->GetSegmentation()->GetImage()->Modified();
+  assert(!IsSnakeModeActive());
 
-  // Fill the undo image with blanks too
-  this->m_IRISImageData->GetUndoImage()->GetImage()->FillBuffer(0);
-  this->m_IRISImageData->GetUndoImage()->GetImage()->Modified();
+  // Reset the segmentation image
+  this->m_IRISImageData->ResetSegmentationImage();
 
   // Clear the undo buffer
   m_UndoManager.Clear();
+  m_UndoManager.SetCumulativeDelta(NULL);
+
+  // Fire the appropriate event
+  InvokeEvent(LayerChangeEvent());
+  InvokeEvent(SegmentationChangeEvent());
+}
+
+void
+IRISApplication
+::ResetSNAPSegmentationImage()
+{
+  assert(m_SNAPImageData);
+
+  // Reset the segmentation image
+  m_SNAPImageData->ResetSegmentationImage();
+
+  // Fire the appropriate event
+  InvokeEvent(LayerChangeEvent());
+  InvokeEvent(SegmentationChangeEvent());
 }
 
 void
@@ -320,10 +378,10 @@ IRISApplication
 ::UpdateIRISSegmentationImage(GuidedNativeImageIO *io)
 {
   // This has to happen in 'pure' IRIS mode
-  assert(m_SNAPImageData == NULL);
+  assert(!IsSnakeModeActive());
 
   // Cast the image to label type
-  CastNativeImageToScalar<LabelType> caster;
+  CastNativeImage<LabelImageType> caster;
   LabelImageType::Pointer imgLabel = caster(io);
   
   // The header of the label image is made to match that of the grey image
@@ -334,53 +392,169 @@ IRISApplication
   // Update the iris data
   m_IRISImageData->SetSegmentationImage(imgLabel); 
 
-  // Check that the range is valid
-#if MAX_COLOR_LABELS < 0xffff
-  if(m_IRISImageData->GetSegmentation()->GetImageMax() > MAX_COLOR_LABELS)
-    {
-    m_IRISImageData->GetSegmentation()->GetImage()->FillBuffer(0);
-    throw IRISException(
-      "Segmentation image has more labels than maximum allowed (%d)", 
-      MAX_COLOR_LABELS);
-    }
-#endif
+  // Update filenames
+  m_IRISImageData->GetSegmentation()->SetFileName(io->GetFileNameOfNativeImage());
+
+  // Update the history
+  m_SystemInterface->GetHistoryManager()->UpdateHistory(
+        "LabelImage", io->GetFileNameOfNativeImage(), true);
 
-  // Update the color labels, so that for every label in the image
-  // there is a valid color label
-  LabelImageWrapper::ConstIterator it = 
-    m_IRISImageData->GetSegmentation()->GetImageConstIterator();
-  for( ; !it.IsAtEnd(); ++it)
-    if(!m_ColorLabelTable->IsColorLabelValid(it.Get()))
-      m_ColorLabelTable->SetColorLabelValid(it.Get(), true);
 
   // Reset the UNDO manager
   m_UndoManager.Clear();
+
+  // Store the current segmentation image as the cumulative delta in the undo
+  // manager.
+  UndoManagerType::Delta *new_cumulative = new UndoManagerType::Delta();
+  LabelImageType *seg = m_IRISImageData->GetSegmentation()->GetImage();
+  LabelType *buffer = seg->GetBufferPointer();
+  LabelType *buffer_end = buffer + seg->GetPixelContainer()->Size();
+  while (buffer < buffer_end)
+    new_cumulative->Encode(*buffer++);
+
+  new_cumulative->FinishEncoding();
+  m_UndoManager.SetCumulativeDelta(new_cumulative);
+
+  // Now we can use the RLE encoding of the segmentation to quickly determine
+  // which labels are valid
+  for(size_t j = 0; j < new_cumulative->GetNumberOfRLEs(); j++)
+    {
+    LabelType label = new_cumulative->GetRLEValue(j);
+    m_ColorLabelTable->SetColorLabelValid(label, true);
+    }
+
+  // Let the GUI know that segmentation changed
+  InvokeEvent(SegmentationChangeEvent());
 }
 
+inline
 LabelType
 IRISApplication
 ::DrawOverLabel(LabelType iTarget)
 {
   // Get the current merge settings
-  CoverageModeType iMode = m_GlobalState->GetCoverageMode();
+  const DrawOverFilter &filter = m_GlobalState->GetDrawOverFilter();
+  const LabelType &iDrawing = m_GlobalState->GetDrawingColorLabel();
+
+  // If mode is paint over all, the victim is overridden
+  if(filter.CoverageMode == PAINT_OVER_ALL)
+    return iDrawing;
+
+  if(filter.CoverageMode == PAINT_OVER_ONE && filter.DrawOverLabel == iTarget)
+    return iDrawing;
+
+  if(filter.CoverageMode == PAINT_OVER_VISIBLE
+     && m_ColorLabelTable->GetColorLabel(iTarget).IsVisible())
+    return iDrawing;
+
+  return iTarget;
+}
+
+void IRISApplication::BeginSegmentationUpdate(std::string undo_name)
+{
+  m_SegmentationUpdateName = undo_name;
+  m_SegmentationChangeCount = 0;
+}
+
+void IRISApplication::UpdateSegmentationVoxel(const Vector3ui &pos)
+{
+  // Get the segmentation image
+  LabelImageType *seg = m_CurrentImageData->GetSegmentation()->GetImage();
+  LabelType &label = seg->GetPixel(to_itkIndex(pos));
+  LabelType newlabel = DrawOverLabel(label);
+  if(label != newlabel)
+    {
+    label = newlabel;
+    m_SegmentationChangeCount++;
+    }
+}
+
+int IRISApplication::EndSegmentationUpdate()
+{
+  if(m_SegmentationChangeCount > 0)
+    {
+    m_CurrentImageData->GetSegmentation()->GetImage()->Modified();
+    this->StoreUndoPoint(m_SegmentationUpdateName.c_str());
+    this->InvokeEvent(SegmentationChangeEvent());
+    }
+
+  m_SegmentationUpdateName = std::string();
+  return m_SegmentationChangeCount;
+}
+
+unsigned int
+IRISApplication
+::UpdateSegmentationWithSliceDrawing(
+    IRISApplication::SliceBinaryImageType *drawing,
+    const ImageCoordinateTransform &xfmSliceToImage,
+    double zSlice,
+    const std::string &undoTitle)
+{
+  // Only in IRIS mode
+  assert(!IsSnakeModeActive());
+
+  // Get the segmentation image
+  LabelImageType *seg = m_CurrentImageData->GetSegmentation()->GetImage();
+
+  // Drawing parameters
+  CoverageModeType iMode = m_GlobalState->GetDrawOverFilter().CoverageMode;
   LabelType iDrawing = m_GlobalState->GetDrawingColorLabel();
-  LabelType iDrawOver = m_GlobalState->GetOverWriteColorLabel();  
+  LabelType iDrawOver = m_GlobalState->GetDrawOverFilter().DrawOverLabel;
+  bool invert = m_GlobalState->GetPolygonInvert();
 
-  // Assign the output intensity based on the current drawing mode    
-  bool visible = m_ColorLabelTable->GetColorLabel(iTarget).IsVisible();
+  // Keep track of the number of pixels changed
+  unsigned int nUpdates = 0;
 
-  // If mode is paint over all, the victim is overridden
-  return
-     ((iMode == PAINT_OVER_ALL) ||
-      (iMode == PAINT_OVER_COLORS && visible) ||
-      (iMode == PAINT_OVER_ONE && iDrawOver == iTarget)) ? iDrawing : iTarget;
+  // Iterate through the drawing
+  for (itk::ImageRegionIteratorWithIndex<SliceBinaryImageType>
+       it(drawing, drawing->GetBufferedRegion()); !it.IsAtEnd(); ++it)
+    {
+    // Get the current polygon pixel
+    SliceBinaryImageType::PixelType px = it.Get();
+
+    // Check for non-zero alpha of the pixel
+    if((px != 0) ^ invert)
+      {
+      // Figure out the coordinate of the target image
+      itk::Index<2> idx = it.GetIndex();
+      Vector3f idxImageFloat = xfmSliceToImage.TransformPoint(
+            Vector3f(idx[0] + 0.5, idx[1] + 0.5, zSlice));
+      itk::Index<3> iseg = to_itkIndex(to_unsigned_int(idxImageFloat));
+
+      // Access the voxel in the segmentation
+      LabelType &voxel = seg->GetPixel(iseg);
+
+      // Apply the label to the voxel
+      if(iMode == PAINT_OVER_ALL ||
+         (iMode == PAINT_OVER_ONE && voxel == iDrawOver) ||
+         (iMode == PAINT_OVER_VISIBLE &&
+          m_ColorLabelTable->GetColorLabel(voxel).IsVisible()))
+        {
+        if(voxel != iDrawing)
+          {
+          voxel = iDrawing;
+          nUpdates++;
+          }
+        }
+      }
+    }
+
+  // Has anything been changed?
+  if(nUpdates > 0)
+    {
+    seg->Modified();
+    StoreUndoPoint(undoTitle.c_str());
+    InvokeEvent(SegmentationChangeEvent());
+    }
+
+  return nUpdates;
 }
 
 void 
 IRISApplication
 ::UpdateIRISWithSnapImageData(CommandType *progressCommand)
 {
-  assert(m_SNAPImageData != NULL);
+  assert(IsSnakeModeActive());
 
   // Get pointers to the source and destination images
   typedef LevelSetImageWrapper::ImageType SourceImageType;
@@ -395,7 +569,7 @@ IRISApplication
   SNAPSegmentationROISettings roi = m_GlobalState->GetSegmentationROISettings();
 
   // If the ROI has been resampled, resample the segmentation in reverse direction
-  if(roi.GetResampleFlag())
+  if(roi.IsResampling())
     {
     // Create a resampling filter
     typedef itk::ResampleImageFilter<SourceImageType,SourceImageType> ResampleFilterType;
@@ -513,10 +687,16 @@ IRISApplication
 
 void
 IRISApplication
-::SetCursorPosition(const Vector3ui cursor)
+::SetCursorPosition(const Vector3ui cursor, bool force)
 {
-  m_GlobalState->SetCrosshairsPosition(cursor); 
-  this->GetCurrentImageData()->SetCrosshairs(cursor);
+  if(cursor != this->GetCursorPosition() || force)
+    {
+    m_GlobalState->SetCrosshairsPosition(cursor);
+    this->GetCurrentImageData()->SetCrosshairs(cursor);
+
+    // Fire the appropriate event
+    InvokeEvent(CursorUpdateEvent());
+    }
 }
 
 Vector3ui
@@ -526,41 +706,76 @@ IRISApplication
   return m_GlobalState->GetCrosshairsPosition();
 }
 
-void 
+
+void
 IRISApplication
 ::StoreUndoPoint(const char *text)
 {
   // Set the current state as the undo point. We store the difference between
   // the last 'undo' image and the current segmentation image, and then copy
   // the current segmentation image into the undo image
-  LabelImageWrapper *undo = m_IRISImageData->GetUndoImage();
   LabelImageWrapper *seg = m_IRISImageData->GetSegmentation();
-  
+  UndoManagerType::Delta *new_cumulative = new UndoManagerType::Delta();
+
   LabelType *dseg = seg->GetVoxelPointer();
-  LabelType *dundo = undo->GetVoxelPointer();
   size_t n = seg->GetNumberOfVoxels();
 
   // Create the Undo delta object
   UndoManagerType::Delta *delta = new UndoManagerType::Delta();
 
-  // Copy and encode
-  for(size_t i = 0; i < n; i++)
+  // Get the old cumulative delta
+  UndoManagerType::Delta *old_cumulative = m_UndoManager.GetCumulativeDelta();
+
+  // Run over the old cumulative data
+  if(old_cumulative)
     {
-    LabelType vSrc = dseg[i], vDst = dundo[i];
-    delta->Encode(vSrc - vDst);
-    dundo[i] = vSrc;
-    }
+    for(size_t i = 0; i < old_cumulative->GetNumberOfRLEs(); i++)
+      {
+      size_t rle_len = old_cumulative->GetRLELength(i);
+      LabelType rle_val = old_cumulative->GetRLEValue(i);
+
+      for(size_t j = 0; j < rle_len; j++)
+        {
+        delta->Encode(*dseg - rle_val);
+        new_cumulative->Encode(*dseg);
+        dseg++;
+        }
+      }
 
-  // Important last step!
-  delta->FinishEncoding();
+    // Important last step!
+    delta->FinishEncoding();
+    new_cumulative->FinishEncoding();
+    }
+  else
+    {
+    LabelType *dseg_end = dseg + n;
+    for(; dseg < dseg_end; ++dseg)
+      {
+      // TODO: add code to duplicate
+      delta->Encode(*dseg);
+      }
 
-  // Set modified flag on the undo image
-  undo->GetImage()->Modified();
+    delta->FinishEncoding();
+    *new_cumulative = *delta;
+    }
 
   // Add the delta object
   m_UndoManager.AppendDelta(delta);
+  m_UndoManager.SetCumulativeDelta(new_cumulative);
+
+  // TODO: I am not sure this is the best place for this code. I think it's a
+  // good idea to migrate all of the code that deals with updating the
+  // segmentation image into one place, such as the LabelImageWrapper class.
+
+  // Along with the undo point, we would like to store the combination of
+  // the foreground and background label used for this update. This will
+  // help us keep track of the most recently used combinations.
+  m_LabelUseHistory->RecordLabelUse(
+        m_GlobalState->GetDrawingColorLabel(),
+        m_GlobalState->GetDrawOverFilter());
 }
 
+
 void
 IRISApplication
 ::ClearUndoPoints()
@@ -575,6 +790,7 @@ IRISApplication
   return m_UndoManager.IsUndoPossible();
 }
 
+/*
 void
 IRISApplication
 ::Undo()
@@ -612,8 +828,53 @@ IRISApplication
   // Set modified flags
   imSeg->GetImage()->Modified();
   imUndo->GetImage()->Modified();
+  InvokeEvent(SegmentationChangeEvent());
 }
+*/
+
+void
+IRISApplication
+::Undo()
+{
+  // In order to undo, we must take the 'current' delta and apply
+  // it to the image
+  UndoManagerType::Delta *delta = m_UndoManager.GetDeltaForUndo();
+  UndoManagerType::Delta *cumulative = new UndoManagerType::Delta();
+
+  LabelImageWrapper *imSeg = m_IRISImageData->GetSegmentation();
+  LabelType *dseg = imSeg->GetVoxelPointer();
+
+  // Applying the delta means adding
+  for(size_t i = 0; i < delta->GetNumberOfRLEs(); i++)
+    {
+    size_t n = delta->GetRLELength(i);
+    LabelType d = delta->GetRLEValue(i);
+    if(d == 0)
+      {
+      for(size_t j = 0; j < n; j++)
+        {
+        cumulative->Encode(*dseg);
+        ++dseg;
+        }
+      }
+    else
+      {
+      for(size_t j = 0; j < n; j++)
+        {
+        *dseg -= d;
+        cumulative->Encode(*dseg);
+        ++dseg;
+        }
+      }
+    }
+
+  cumulative->FinishEncoding();
+  m_UndoManager.SetCumulativeDelta(cumulative);
 
+  // Set modified flags
+  imSeg->GetImage()->Modified();
+  InvokeEvent(SegmentationChangeEvent());
+}
 
 bool
 IRISApplication
@@ -622,6 +883,7 @@ IRISApplication
   return m_UndoManager.IsRedoPossible();
 }
 
+/*
 void
 IRISApplication
 ::Redo()
@@ -658,7 +920,52 @@ IRISApplication
 
   // Set modified flags
   imSeg->GetImage()->Modified();
-  imUndo->GetImage()->Modified();
+  InvokeEvent(SegmentationChangeEvent());
+}
+*/
+
+void
+IRISApplication
+::Redo()
+{
+  // In order to undo, we must take the 'current' delta and apply
+  // it to the image
+  UndoManagerType::Delta *delta = m_UndoManager.GetDeltaForRedo();
+  LabelImageWrapper *imSeg = m_IRISImageData->GetSegmentation();
+  LabelType *dseg = imSeg->GetVoxelPointer();
+
+  UndoManagerType::Delta *cumulative = new UndoManagerType::Delta();
+
+  // Applying the delta means adding
+  for(size_t i = 0; i < delta->GetNumberOfRLEs(); i++)
+    {
+    size_t n = delta->GetRLELength(i);
+    LabelType d = delta->GetRLEValue(i);
+    if(d == 0)
+      {
+      for(size_t j = 0; j < n; j++)
+        {
+        cumulative->Encode(*dseg);
+        ++dseg;
+        }
+      }
+    else
+      {
+      for(size_t j = 0; j < n; j++)
+        {
+        *dseg += d;
+        cumulative->Encode(*dseg);
+        ++dseg;
+        }
+      }
+    }
+
+  cumulative->FinishEncoding();
+  m_UndoManager.SetCumulativeDelta(cumulative);
+
+  // Set modified flags
+  imSeg->GetImage()->Modified();
+  InvokeEvent(SegmentationChangeEvent());
 }
 
 
@@ -668,10 +975,35 @@ void
 IRISApplication
 ::ReleaseSNAPImageData() 
 {
-  assert(m_SNAPImageData && m_CurrentImageData != m_SNAPImageData);
+  assert(m_SNAPImageData->IsMainLoaded() &&
+         m_CurrentImageData != m_SNAPImageData);
+
+  m_SNAPImageData->UnloadAll();
+}
+
+void
+IRISApplication
+::TransferCursor(GenericImageData *source, GenericImageData *target)
+{
+  Vector3d cursorSource = to_double(this->GetCursorPosition());
+
+  Vector3d xyzSource =
+      source->GetMain()->TransformVoxelIndexToNIFTICoordinates(cursorSource);
+
+  itk::Index<3> indexTarget =
+      to_itkIndex(target->GetMain()->TransformNIFTICoordinatesToVoxelIndex(xyzSource));
+
+  Vector3ui newCursor =
+      target->GetMain()->GetBufferedRegion().IsInside(indexTarget)
+      ? Vector3ui(indexTarget)
+      : target->GetMain()->GetSize() / 2u;
+
+  // Store the cursor position in the global state and the target image data
+  m_GlobalState->SetCrosshairsPosition(newCursor);
+  target->SetCrosshairs(newCursor);
 
-  delete m_SNAPImageData;
-  m_SNAPImageData = NULL;
+  // Fire the appropriate event
+  InvokeEvent(CursorUpdateEvent());
 }
 
 void 
@@ -679,26 +1011,44 @@ IRISApplication
 ::SetCurrentImageDataToIRIS() 
 {
   assert(m_IRISImageData);
-  m_CurrentImageData = m_IRISImageData;
+  if(m_CurrentImageData != m_IRISImageData)
+    {
+    m_CurrentImageData = m_IRISImageData;
+    TransferCursor(m_SNAPImageData, m_IRISImageData);
+    InvokeEvent(MainImageDimensionsChangeEvent());
+    }
 }
 
 void IRISApplication
 ::SetCurrentImageDataToSNAP() 
 {
-  assert(m_SNAPImageData);
-  m_CurrentImageData = m_SNAPImageData;
+  assert(m_SNAPImageData->IsMainLoaded());
+  if(m_CurrentImageData != m_SNAPImageData)
+    {
+    // The cursor needs to be modified to point to the same location
+    // as before, or to the center of the image
+    TransferCursor(m_IRISImageData, m_SNAPImageData);
+
+    // Set the image data
+    m_CurrentImageData = m_SNAPImageData;
+
+    // Fire the event
+    InvokeEvent(MainImageDimensionsChangeEvent());
+
+    // Upon entering this mode, we need reset the active tools
+    m_GlobalState->SetToolbarMode(CROSSHAIRS_MODE);
+    m_GlobalState->SetToolbarMode3D(TRACKBALL_MODE);
+    }
 }
 
-size_t 
-IRISApplication
-::GetImageDirectionForAnatomicalDirection(AnatomicalDirection iAnat)
+int IRISApplication::GetImageDirectionForAnatomicalDirection(AnatomicalDirection iAnat)
 {
   std::string myrai = this->GetImageToAnatomyRAI();
   
   string rai1 = "SRA", rai2 = "ILP";
   
   char c1 = rai1[iAnat], c2 = rai2[iAnat];
-  for(size_t j = 0; j < 3; j++)
+  for(int j = 0; j < 3; j++)
     if(myrai[j] == c1 || myrai[j] == c2)
       return j;
   
@@ -706,22 +1056,18 @@ IRISApplication
   return 0;
 }
 
-size_t 
+int
 IRISApplication
 ::GetDisplayWindowForAnatomicalDirection(
-  AnatomicalDirection iAnat)
+  AnatomicalDirection iAnat) const
 {
-  string rai1 = "SRA", rai2 = "ILP";
-  char c1 = rai1[iAnat], c2 = rai2[iAnat];
-  for(size_t j = 0; j < 3; j++)
-    {
-    char sd = m_DisplayToAnatomyRAI[j][2];
-    if(sd == c1 || sd == c2)
-      return j;
-    }
+  return m_DisplayGeometry.GetDisplayWindowForAnatomicalDirection(iAnat);
+}
 
-  assert(0);
-  return 0;
+AnatomicalDirection
+IRISApplication::GetAnatomicalDirectionForDisplayWindow(int iWin) const
+{
+  return m_DisplayGeometry.GetAnatomicalDirectionForDisplayWindow(iWin);
 }
 
 void
@@ -732,20 +1078,24 @@ IRISApplication
   size_t iSliceImg = 
     GetImageDirectionForAnatomicalDirection(iSliceAnat);
 
+  // TODO: should this not export using the default scalar representation,
+  // rather than RGB? Not sure...
+
   // Find the slicer that slices along that direction
-  GreyImageWrapper::DisplaySlicePointer imgGrey = NULL;
+  typedef ImageWrapperBase::DisplaySliceType SliceType;
+  SmartPtr<SliceType> imgGrey = NULL;
   for(size_t i = 0; i < 3; i++)
     {
-    if(iSliceImg == m_CurrentImageData->GetGrey()->GetSlicer(i)->GetSliceDirectionImageAxis())
+    if(iSliceImg == m_CurrentImageData->GetMain()->GetDisplaySliceImageAxis(i))
       {
-      imgGrey = m_CurrentImageData->GetGrey()->GetDisplaySlice(i);
+      imgGrey = m_CurrentImageData->GetMain()->GetDisplaySlice(i);
       break;
       }
     }
   assert(imgGrey);
 
   // Flip the image in the Y direction
-  typedef itk::FlipImageFilter<GreyImageWrapper::DisplaySliceType> FlipFilter;
+  typedef itk::FlipImageFilter<SliceType> FlipFilter;
   FlipFilter::Pointer fltFlip = FlipFilter::New();
   fltFlip->SetInput(imgGrey);
   
@@ -754,7 +1104,7 @@ IRISApplication
   fltFlip->SetFlipAxes(arrFlips);
 
   // Create a writer for saving the image
-  typedef itk::ImageFileWriter<GreyImageWrapper::DisplaySliceType> WriterType;
+  typedef itk::ImageFileWriter<SliceType> WriterType;
   WriterType::Pointer writer = WriterType::New();
   writer->SetInput(fltFlip->GetOutput());
   writer->SetFileName(file);
@@ -763,7 +1113,7 @@ IRISApplication
 
 void 
 IRISApplication
-::ExportSegmentationStatistics(const char *file)  throw(itk::ExceptionObject)
+::ExportSegmentationStatistics(const char *file)
 {
   // Make sure that the segmentation image exists
   assert(m_CurrentImageData->IsSegmentationLoaded());
@@ -796,18 +1146,23 @@ IRISApplication
 void
 IRISApplication
 ::ExportSegmentationMesh(const MeshExportSettings &sets, itk::Command *progress) 
-  throw(itk::ExceptionObject)
 {
-  // Based on the export settings, we will export one of the labels or all labels
-  MeshObject mob;
-  mob.Initialize(this);
-  mob.GenerateVTKMeshes(progress);
+  // Update the list of VTK meshes
+  m_MeshManager->UpdateVTKMeshes(progress);
+
+  // Get the list of available labels
+  MeshManager::MeshCollection meshes = m_MeshManager->GetMeshes();
+  MeshManager::MeshCollection::iterator it;
 
   // If in SNAP mode, just save the first mesh
-  if(m_SNAPImageData)
+  if(m_SNAPImageData->IsMainLoaded())
     {
+    if(meshes.size() != 1)
+      throw IRISException("Unexpected number of meshes in SNAP mode");
+
     // Get the VTK mesh for the label
-    vtkPolyData *mesh = mob.GetVTKMesh(0);
+    it = meshes.begin();
+    vtkPolyData *mesh = it->second;
 
     // Export the mesh
     GuidedMeshIO io;
@@ -818,38 +1173,38 @@ IRISApplication
   // If only one mesh is to be exported, life is easy
   else if(sets.GetFlagSingleLabel())
     {
-    for(size_t i = 0; i < mob.GetNumberOfVTKMeshes(); i++)
-      {
-      if(mob.GetVTKMeshLabel(i) == sets.GetExportLabel())
-        {
-        // Get the VTK mesh for the label
-        vtkPolyData *mesh = mob.GetVTKMesh(i);
+    // Get the VTK mesh for the label
+    it = meshes.find(sets.GetExportLabel());
+    if(it == meshes.end())
+      throw IRISException("Missing mesh for the selected label");
 
-        // Export the mesh
-        GuidedMeshIO io;
-        Registry rFormat = sets.GetMeshFormat();
-        io.SaveMesh(sets.GetMeshFileName().c_str(), rFormat, mesh);
-        }
-      }
+    vtkPolyData *mesh = it->second;
+
+    // Export the mesh
+    GuidedMeshIO io;
+    Registry rFormat = sets.GetMeshFormat();
+    io.SaveMesh(sets.GetMeshFileName().c_str(), rFormat, mesh);
     }
   else if(sets.GetFlagSingleScene())
     {
     // Create an append filter
-    vtkAppendPolyData *append = vtkAppendPolyData::New();
-    std::vector<vtkUnsignedShortArray *> scalarArray;
+    vtkSmartPointer<vtkAppendPolyData> append = vtkSmartPointer<vtkAppendPolyData>::New();
 
-    for(size_t i = 0; i < mob.GetNumberOfVTKMeshes(); i++)
+    for(it = meshes.begin(); it != meshes.end(); it++)
       {
       // Get the VTK mesh for the label
-      vtkPolyData *mesh = mob.GetVTKMesh(i);
-      vtkUnsignedShortArray *scalar = vtkUnsignedShortArray::New();
+      vtkPolyData *mesh = it->second;
+      vtkSmartPointer<vtkUnsignedShortArray> scalar =
+          vtkSmartPointer<vtkUnsignedShortArray>::New();
+
       scalar->SetNumberOfComponents(1);
+
       scalar->Allocate(mesh->GetNumberOfPoints());
       for(int j = 0; j < mesh->GetNumberOfPoints(); j++)
-        scalar->InsertNextTuple1(mob.GetVTKMeshLabel(i));
+        scalar->InsertNextTuple1(it->first);
+
       mesh->GetPointData()->SetScalars(scalar);
-      scalarArray.push_back(scalar);
-      append->AddInput(mesh);
+      append->AddInputData(mesh);
       }
 
     append->Update();
@@ -859,9 +1214,9 @@ IRISApplication
     Registry rFormat = sets.GetMeshFormat();
     io.SaveMesh(sets.GetMeshFileName().c_str(), rFormat, append->GetOutput());
 
-    append->Delete();
-    for(size_t i = 0; i < scalarArray.size(); i++)
-      scalarArray[i]->Delete();
+    // Remove the scalars from the meshes
+    for(it = meshes.begin(); it != meshes.end(); it++)
+      it->second->GetPointData()->SetScalars(NULL);
     }
   else
     {
@@ -881,14 +1236,14 @@ IRISApplication
       }
 
     // Loop, saving each mesh into a filename
-    for(size_t i = 0; i < mob.GetNumberOfVTKMeshes(); i++)
+    for(it = meshes.begin(); it != meshes.end(); it++)
       {
       // Get the VTK mesh for the label
-      vtkPolyData *mesh = mob.GetVTKMesh(i);
+      vtkPolyData *mesh = it->second;
 
       // Generate filename
       char outfn[4096];
-      sprintf(outfn, "%s/%s%05d%s", path.c_str(), prefix.c_str(), mob.GetVTKMeshLabel(i), extn.c_str());
+      sprintf(outfn, "%s/%s%05d%s", path.c_str(), prefix.c_str(), it->first, extn.c_str());
 
       // Export the mesh
       GuidedMeshIO io;
@@ -896,8 +1251,6 @@ IRISApplication
       io.SaveMesh(outfn, rFormat, mesh);
       }
     }
-
-  mob.DiscardVTKMeshes();
 }
 
 size_t
@@ -931,6 +1284,28 @@ IRISApplication
   return nvoxels;
 }
 
+// TODO: This information should be cached at the segmentation layer level
+// by keeping track of label counts after every update operation.
+size_t
+IRISApplication
+::GetNumberOfVoxelsWithLabel(LabelType label)
+{
+  // Get the label image
+  assert(m_CurrentImageData->IsSegmentationLoaded());
+  LabelImageType *seg = m_CurrentImageData->GetSegmentation()->GetImage();
+
+  // Get the number of voxels
+  size_t nvoxels = 0;
+  for(LabelImageWrapper::ConstIterator it(seg, seg->GetBufferedRegion());
+      !it.IsAtEnd(); ++it)
+    {
+    if(it.Get() == label)
+      ++nvoxels;
+    }
+
+  return nvoxels;
+}
+
 
 void 
 IRISApplication
@@ -971,8 +1346,13 @@ IRISApplication
     // Check the side of the plane
     if(distance > 0)
       {
-      LabelType &voxel = it.Value();
-      voxel = table[voxel];
+      LabelType voxel = it.Value();
+      LabelType newvox = table[voxel];
+      if(voxel != newvox)
+        {
+        it.Set(newvox);
+        m_SegmentationChangeCount++;
+        }
       }
 
     // Next voxel
@@ -1049,14 +1429,17 @@ IRISApplication
     lIndex[2] = (int)pz;
 
     LabelType hitlabel = m_CurrentImageData->GetSegmentation()->GetVoxel(lIndex);
-    const ColorLabel &cl = m_ColorLabelTable->GetColorLabel(hitlabel);
 
-    if (cl.IsValid() && cl.IsVisible())
+    if (m_ColorLabelTable->IsColorLabelValid(hitlabel))
       {
-      hit[0] = lIndex[0];
-      hit[1] = lIndex[1];
-      hit[2] = lIndex[2];
-      return 1;
+      ColorLabel cl = m_ColorLabelTable->GetColorLabel(hitlabel);
+      if(cl.IsVisible())
+        {
+        hit[0] = lIndex[0];
+        hit[1] = lIndex[1];
+        hit[2] = lIndex[2];
+        return 1;
+        }
       }
 
     // BEGIN : walk along ray to border of next voxel touched by ray
@@ -1125,170 +1508,642 @@ IRISApplication
   return 0;
 }
 
-IRISApplication::MainImageType
+
+void
 IRISApplication
-::AddIRISOverlayImage(GuidedNativeImageIO *io, MainImageType force_type)
+::AddIRISOverlayImage(GuidedNativeImageIO *io, Registry *metadata)
 {
-  assert(m_SNAPImageData == NULL);
+  assert(!IsSnakeModeActive());
   assert(m_IRISImageData->IsMainLoaded());
   assert(io->IsNativeImageLoaded());
 
-  // If the input type is 'ANY', determine based on number of components
-  MainImageType type = (force_type == MAIN_ANY)
-    ? (io->GetNumberOfComponentsInNativeImage() == 3 ? MAIN_RGB : MAIN_SCALAR)
-    : force_type;
+  // Add the image as the current grayscale overlay
+  m_IRISImageData->AddOverlay(io);
+
+  // Set the filename of the overlay
+  // TODO: this is cumbersome, could we just initialize the wrapper from the
+  // GuidedNativeImageIO without passing all this junk around?
+  m_IRISImageData->GetLastOverlay()->SetFileName(io->GetFileNameOfNativeImage());
+
+  // Add the overlay to the history
+  m_HistoryManager->UpdateHistory("AnatomicImage", io->GetFileNameOfNativeImage(), true);
 
-  // Cast the native image to desired format and pass on to IRISImageData
-  if(type == MAIN_SCALAR)
+  // for overlay, we don't want to change the cursor location
+  // just force the IRISSlicer to update
+  m_IRISImageData->SetCrosshairs(m_GlobalState->GetCrosshairsPosition());
+
+  // Apply the default color map for overlays
+  std::string deflt_preset =
+      m_GlobalState->GetDefaultBehaviorSettings()->GetOverlayColorMapPreset();
+  m_ColorMapPresetManager->SetToPreset(
+        m_IRISImageData->GetLastOverlay()->GetDisplayMapping()->GetColorMap(),
+        deflt_preset);
+
+  // Initialize the layer-specific segmentation parameters
+  CreateSegmentationSettings(m_IRISImageData->GetLastOverlay(), OVERLAY_ROLE);
+
+  // Read and apply the project-level settings associated with the main image
+  LoadMetaDataAssociatedWithLayer(
+        m_IRISImageData->GetLastOverlay(), OVERLAY_ROLE, metadata);
+
+  // If the default is to auto-contrast, perform the contrast adjustment
+  // operation on the image
+  if(m_GlobalState->GetDefaultBehaviorSettings()->GetAutoContrast())
     {
-    // Rescale the image to grey
-    RescaleNativeImageToScalar<GreyType> rescaler;
-    GreyImageType::Pointer imgGrey = rescaler(io);
-    GreyTypeToNativeFunctor mapper(rescaler.GetNativeScale(), rescaler.GetNativeShift());
+    AutoContrastLayerOnLoad(m_IRISImageData->GetLastOverlay());
+    }
+
+  // Fire event
+  InvokeEvent(LayerChangeEvent());
+}
 
-    // At this point, deallocate the native image, so that we don't use more memory
-    io->DeallocateNativeImage();
+void
+IRISApplication
+::AutoContrastLayerOnLoad(ImageWrapperBase *layer)
+{
+  // Get a pointer to the policy for this layer
+  AbstractContinuousImageDisplayMappingPolicy *policy =
+      dynamic_cast<AbstractContinuousImageDisplayMappingPolicy *>(
+        m_IRISImageData->GetMain()->GetDisplayMapping());
 
-    // Add the image as the current grayscale overlay
-    m_IRISImageData->SetGreyOverlay(imgGrey, mapper);
+  // The policy must be of the right type to proceed
+  if(policy)
+    {
+    // Check if the image contrast is already set by the user
+    if(policy->IsContrastInDefaultState())
+      policy->AutoFitContrast();
+    }
+}
+
+void
+IRISApplication
+::CreateSegmentationSettings(ImageWrapperBase *wrapper, LayerRole role)
+{
+  // Create threshold settings for every scalar component of this wrapper
+  if(wrapper->IsScalar())
+    {
+    // Create threshold settings for this wrapper
+    SmartPtr<ThresholdSettings> ts = ThresholdSettings::New();
+    wrapper->SetUserData("ThresholdSettings", ts);
     }
-  else if(type == MAIN_RGB)
+  else
     {
-    // Cast image to RGB
-    CastNativeImageToRGB<RGBType> caster;
-    RGBImageType::Pointer imgRGB = caster(io);
+    // Call the method recursively for the components
+    VectorImageWrapperBase *vec = dynamic_cast<VectorImageWrapperBase *>(wrapper);
+    for(ScalarRepresentationIterator it(vec); !it.IsAtEnd(); ++it)
+      CreateSegmentationSettings(vec->GetScalarRepresentation(it), role);
+    }
+}
+
+/*
+ *   // Get the size of the image as a vector of uint
+  Vector3ui size = io->GetNativeImage()->GetBufferedRegion().GetSize();
 
-    // At this point, deallocate the native image, so that we don't use more memory
-    io->DeallocateNativeImage();
+  // Compute the new image geometry for the IRIS data
+  ImageCoordinateGeometry icg(
+        io->GetNativeImage()->GetDirection().GetVnlMatrix(),
+        m_DisplayToAnatomyRAI, size);
 
-    // Add the image as the current RGB overlay
-    m_IRISImageData->SetRGBOverlay(imgRGB);
-    }
-  else throw itk::ExceptionObject("Unsupported overlay image type");
+  // Rescale the image to desired number of bits
+  RescaleNativeImageToIntegralType<AnatomyImageType> rescaler;
+  AnatomyImageType::Pointer imgMain = rescaler(io);
+  LinearInternalToNativeIntensityMapping mapper(rescaler.GetNativeScale(), rescaler.GetNativeShift());
 
-  // for overlay, we don't want to change the cursor location
-  // just force the IRISSlicer to update
-  m_IRISImageData->SetCrosshairs(m_GlobalState->GetCrosshairsPosition());
+  // Set the image as the current main anatomy image/
+  m_IRISImageData->SetMainImage(imgMain, icg, mapper);
 
-  // Return the type loaded as
-  return type;
-}
+*/
 
-IRISApplication::MainImageType
+void
 IRISApplication
-::UpdateIRISMainImage(GuidedNativeImageIO *io, MainImageType force_type)
-  {
+::UpdateIRISMainImage(GuidedNativeImageIO *io, Registry *metadata)
+{
   // This has to happen in 'pure' IRIS mode
-  assert(m_SNAPImageData == NULL);
+  assert(!IsSnakeModeActive());
 
-  // If the input type is 'ANY', determine based on number of components
-  MainImageType type = (force_type == MAIN_ANY)
-    ? (io->GetNumberOfComponentsInNativeImage() == 3 ? MAIN_RGB : MAIN_SCALAR)
-    : force_type;
+  // Load the image into the current image data object
+  m_IRISImageData->SetMainImage(io);
 
-  // Get the size of the image as a vector of uint
-  Vector3ui size = to_unsigned_int(Vector3ul(
-    io->GetNativeImage()->GetBufferedRegion().GetSize().GetSize()));
+  // Set the filename and nickname of the image wrapper
+  m_IRISImageData->GetMain()->SetFileName(io->GetFileNameOfNativeImage());
 
-  // Compute the new image geometry for the IRIS data
-  ImageCoordinateGeometry icg(
-    io->GetNativeImage()->GetDirection().GetVnlMatrix(), m_DisplayToAnatomyRAI, size);
+  // Update the preprocessing settings to defaults.
+  m_EdgePreprocessingSettings->InitializeToDefaults();
+
+  // Initialize the layer-specific segmentation parameters
+  CreateSegmentationSettings(m_IRISImageData->GetMain(), MAIN_ROLE);
+
+  // Update the system's history list
+  m_HistoryManager->UpdateHistory("MainImage", io->GetFileNameOfNativeImage(), false);
+  m_HistoryManager->UpdateHistory("AnatomicImage", io->GetFileNameOfNativeImage(), false);
+
+  // Reset the segmentation ROI
+  m_GlobalState->SetSegmentationROI(io->GetNativeImage()->GetBufferedRegion());
 
-  // Cast the native image to desired format and pass on to IRISImageData
-  if(type == MAIN_SCALAR)
+  // Read and apply the project-level settings associated with the main image
+  LoadMetaDataAssociatedWithLayer(
+        m_IRISImageData->GetMain(), MAIN_ROLE, metadata);
+
+  // Fire the dimensions change event
+  InvokeEvent(MainImageDimensionsChangeEvent());
+
+  // Update the crosshairs position to the center of the image
+  Vector3ui cursor = m_IRISImageData->GetMain()->GetSize();
+  cursor /= 2;
+  this->SetCursorPosition(cursor);
+
+  // This line forces the cursor to be propagated to the image even if the
+  // crosshairs positions did not change from their previous values
+  this->GetIRISImageData()->SetCrosshairs(cursor);
+
+  // If the default is to auto-contrast, perform the contrast adjustment
+  // operation on the image
+  if(m_GlobalState->GetDefaultBehaviorSettings()->GetAutoContrast())
     {
-    // Rescale the image to grey
-    RescaleNativeImageToScalar<GreyType> rescaler;
-    GreyImageType::Pointer imgGrey = rescaler(io);
-    GreyTypeToNativeFunctor mapper(rescaler.GetNativeScale(), rescaler.GetNativeShift());
+    AutoContrastLayerOnLoad(m_IRISImageData->GetMain());
+    }
 
-    // At this point, deallocate the native image, so that we don't use more memory
-    io->DeallocateNativeImage();
+  // Save the thumbnail for the current image. This ensures that a thumbnail
+  // is created even if the application crashes or is killed.
+  m_CurrentImageData->GetMain()->WriteThumbnail(
+        m_SystemInterface->GetThumbnailAssociatedWithFile(
+          io->GetFileNameOfNativeImage().c_str()).c_str(), 128);
 
-    // Set the image as the current grayscale image
-    m_IRISImageData->SetGreyImage(imgGrey, icg, mapper); 
+  // Reset the UNDO manager
+  m_UndoManager.Clear();
+  m_UndoManager.SetCumulativeDelta(NULL);
 
-    // Update the preprocessing settings in the global state
-    m_GlobalState->SetEdgePreprocessingSettings(
-      EdgePreprocessingSettings::MakeDefaultSettings());
-    m_GlobalState->SetThresholdSettings(
-      ThresholdSettings::MakeDefaultSettings(
-        m_IRISImageData->GetGrey()));
+  // We also want to reset the label history at this point, as these are
+  // very different labels
+  m_LabelUseHistory->Reset();
+}
+
+void IRISApplication::LoadMetaDataAssociatedWithLayer(
+    ImageWrapperBase *layer, int role, Registry *override)
+{
+  Registry assoc, *folder;
+
+
+  if(override)
+    folder = override;
+  else if(m_SystemInterface->FindRegistryAssociatedWithFile(layer->GetFileName(), assoc))
+    {
+    LayerRole role_cast = (LayerRole) role;
+
+    // Determine the group under which the association is stored. This is to
+    // deal with the situation when the same image is loaded as a main and as
+    // a segmentation, for example
+    std::string roletype;
+    if(role_cast == MAIN_ROLE || role_cast == OVERLAY_ROLE)
+      roletype = "AnatomicImage";
+    else
+      roletype = SNAPRegistryIO::GetEnumMapLayerRole()[role_cast].c_str();
+
+    folder = &assoc.Folder(Registry::Key("Role[%s]", roletype.c_str()));
     }
-  else if(type == MAIN_RGB)
+  else
+    return;
+
+  // Read the image-level metadata (display map, etc) for the image
+  layer->ReadMetaData(folder->Folder("LayerMetaData"));
+
+  // Read and apply the project-level settings associated with the main image
+  if(role == MAIN_ROLE)
     {
-    // Cast to RGB
-    CastNativeImageToRGB<RGBType> caster;
-    RGBImageType::Pointer imgRGB = caster(io);
-    m_IRISImageData->SetRGBImage(imgRGB,icg);
+    SNAPRegistryIO rio;
+    rio.ReadImageAssociatedSettings(folder->Folder("ProjectMetaData"), this, true, true, true, true);
+    }
+}
 
-    // At this point, deallocate the native image, so that we don't use more memory
-    io->DeallocateNativeImage();
+
+void IRISApplication
+::SaveMetaDataAssociatedWithLayer(ImageWrapperBase *layer, int role, Registry *override)
+{
+  Registry assoc, *folder;
+
+  // Load the current associations for the main image
+  if(override)
+    {
+    folder = override;
     }
-  else throw itk::ExceptionObject("Unsupported main image type");
+  else
+    {
+    m_SystemInterface->FindRegistryAssociatedWithFile(layer->GetFileName(), assoc);
 
-  // Update the crosshairs position
-  Vector3ui cursor = size;
-  cursor /= 2;
-  m_IRISImageData->SetCrosshairs(cursor);
+    LayerRole role_cast = (LayerRole) role;
 
-  // TODO: Unify this!
-  m_GlobalState->SetCrosshairsPosition(cursor);
+    // Determine the group under which the association is stored. This is to
+    // deal with the situation when the same image is loaded as a main and as
+    // a segmentation, for example
+    std::string roletype;
+    if(role_cast == MAIN_ROLE || role_cast == OVERLAY_ROLE)
+      roletype = "AnatomicImage";
+    else
+      roletype = SNAPRegistryIO::GetEnumMapLayerRole()[role_cast].c_str();
 
-  // Reset the UNDO manager
-  m_UndoManager.Clear();
+    folder = &assoc.Folder(Registry::Key("Role[%s]", roletype.c_str()));
+    }
 
-  return type;
+  // Write the metadata for the specific layer
+  layer->WriteMetaData(folder->Folder("LayerMetaData"));
+
+  // For the main image layer, write the project-level settings
+  if(role == MAIN_ROLE)
+    {
+    // Write the project-level associations
+    SNAPRegistryIO io;
+    io.WriteImageAssociatedSettings(this, folder->Folder("ProjectMetaData"));
+    }
+
+  // Save the settings
+  if(!override)
+    m_SystemInterface->AssociateRegistryWithFile(layer->GetFileName(), assoc);
 }
 
-IRISApplication::MainImageType 
+void
 IRISApplication
-::LoadMainImage(const char *filename, MainImageType force_type)
+::UnloadMainImage()
+{
+  // Save the settings for this image
+  if(m_CurrentImageData->IsMainLoaded())
+    {
+    ImageWrapperBase *image = m_CurrentImageData->GetMain();
+    const char *fnMain = image->GetFileName();
+
+    // Reset the toolbar mode to default
+    m_GlobalState->SetToolbarMode(CROSSHAIRS_MODE);
+
+    // Write the image-level and project-level associations
+    SaveMetaDataAssociatedWithLayer(image, MAIN_ROLE);
+
+    // Create a thumbnail from the one of the image slices
+    std::string fnThumb = m_SystemInterface->GetThumbnailAssociatedWithFile(fnMain);
+    m_CurrentImageData->GetMain()->WriteThumbnail(fnThumb.c_str(), 128);
+
+    // Do likewise for the project if one exists
+    if(m_GlobalState->GetProjectFilename().length())
+      {
+      // TODO: it would look nicer if we actually saved the state of the SNAP
+      // windows rather than just the image in its current colormap. But this
+      // would require doing this elsewhere
+      std::string fnThumb = m_SystemInterface->GetThumbnailAssociatedWithFile(
+            m_GlobalState->GetProjectFilename().c_str());
+
+      m_CurrentImageData->GetMain()->WriteThumbnail(fnThumb.c_str(), 128);
+      }
+    }
+
+  // Reset the automatic segmentation ROI
+  m_GlobalState->SetSegmentationROI(GlobalState::RegionType());
+
+  // Unload the main image
+  m_CurrentImageData->UnloadMainImage();
+
+  // After unloading the main image, we reset the workspace filename
+  m_GlobalState->SetProjectFilename("");
+
+  // Reset the project registry
+  m_LastSavedProjectState = Registry();
+
+  // Reset the local history
+  m_HistoryManager->ClearLocalHistory();
+
+  // Let everyone know that the main image is gone!
+  InvokeEvent(MainImageDimensionsChangeEvent());
+}
+
+void IRISApplication
+::LoadImageViaDelegate(const char *fname,
+                       AbstractLoadImageDelegate *del,
+                       IRISWarningList &wl)
 {
   // Load the settings associated with this file
-  Registry regFull;
-  m_SystemInterface->FindRegistryAssociatedWithFile(filename, regFull);
-    
+  Registry reg;
+  m_SystemInterface->FindRegistryAssociatedWithFile(fname, reg);
+
   // Get the folder dealing with grey image properties
-  Registry &folder = regFull.Folder("Files.Grey");
+  Registry &folder = reg.Folder("Files.Grey");
 
   // Create a native image IO object
-  GuidedNativeImageIO io;
-  io.ReadNativeImage(filename, folder);
+  SmartPtr<GuidedNativeImageIO> io = GuidedNativeImageIO::New();
+
+  // Load the header of the image
+  io->ReadNativeImageHeader(fname, folder);
+
+  // Validate the header
+  del->ValidateHeader(io, wl);
+
+  // Unload the current image data
+  del->UnloadCurrentImage();
+
+  // Read the image body
+  io->ReadNativeImageData();
+
+  // Validate the image data
+  del->ValidateImage(io, wl);
+
+  // Put the image in the right place
+  del->UpdateApplicationWithImage(io);
+}
+
+void IRISApplication
+::LoadImage(const char *fname, LayerRole role,
+            IRISWarningList &wl, Registry *meta_data_reg)
+{
+  // Pointer to the delegate
+  SmartPtr<AbstractLoadImageDelegate> delegate;
+
+  switch(role)
+    {
+    case MAIN_ROLE:
+      delegate = LoadMainImageDelegate::New().GetPointer();
+      break;
+    case OVERLAY_ROLE:
+      delegate = LoadOverlayImageDelegate::New().GetPointer();
+      break;
+    case LABEL_ROLE:
+      delegate = LoadSegmentationImageDelegate::New().GetPointer();
+      break;
+    default:
+      throw IRISException("LoadImage does not support role %d", role);
+    }
+
+  delegate->Initialize(this);
+  if(meta_data_reg)
+    delegate->SetMetaDataRegistry(meta_data_reg);
+  this->LoadImageViaDelegate(fname, delegate, wl);
+}
+
+SmartPtr<AbstractSaveImageDelegate>
+IRISApplication::CreateSaveDelegateForLayer(ImageWrapperBase *layer, LayerRole role)
+{
+  // TODO: need some unified way of handling histories and categories
+
+  // Which history does the image belong under? This goes beyond the role
+  // of the image, as in snake mode, there are sub-roles that the wrappers
+  // have. The safest thing is to have the history information be stored
+  // as a kind of user data in each wrapper. However, for now, we will just
+  // infer it from the role and type
+  std::string history, category;
+  if(role == MAIN_ROLE)
+    {
+    history = "AnatomicImage";
+    category = "Main Image";
+    }
+
+  else if(role == LABEL_ROLE)
+    {
+    history = "LabelImage";
+    category = "Segmentation Image";
+    }
 
-  // Detemine the type
-  MainImageType type = UpdateIRISMainImage(&io, force_type);
-  if(type == MAIN_SCALAR)
+  else if(role == OVERLAY_ROLE)
     {
-    // Save the filename for the UI
-    m_GlobalState->SetGreyFileName(filename);  
+    history = "AnatomicImage";
+    category = "Overlay Image";
     }
-  else if(type == MAIN_RGB)
+
+  else if(role == SNAP_ROLE)
     {
-    m_GlobalState->SetRGBFileName(filename);  
+    if(dynamic_cast<SpeedImageWrapper *>(layer))
+      {
+      history = "SpeedImage";
+      category = "Speed Image";
+      }
+
+    else if(dynamic_cast<LevelSetImageWrapper *>(layer))
+      {
+      history = "LevelSetImage";
+      category = "Level Set Image";
+      }
     }
-  else throw itk::ExceptionObject("Unsupported main image type");
 
-  return type;
+  // Create delegate
+  SmartPtr<DefaultSaveImageDelegate> delegate = DefaultSaveImageDelegate::New();
+  delegate->Initialize(this, layer, history);
+
+  // Return the delegate
+  return delegate.GetPointer();
 }
 
-IRISApplication::MainImageType 
-IRISApplication
-::LoadOverlayImage(const char *filename, MainImageType force_type)
+
+void IRISApplication::SaveProjectToRegistry(Registry &preg, const std::string proj_file_full)
 {
-  // Load the settings associated with this file
-  Registry regFull;
-  m_SystemInterface->FindRegistryAssociatedWithFile(filename, regFull);
-    
-  // Get the folder dealing with grey image properties
-  Registry &folder = regFull.Folder("Files.Grey");
+  // Clear the registry contents
+  preg.Clear();
 
-  // Create a native image IO object
-  GuidedNativeImageIO io;
-  io.ReadNativeImage(filename, folder);
+  // Get the directory in which the project will be saved
+  std::string project_dir = itksys::SystemTools::GetParentDirectory(proj_file_full.c_str());
+
+  // Put version information - later versions may not be compatible
+  preg["Version"] << SNAPCurrentVersionReleaseDate;
+
+  // Save the directory to the project file. This allows us to deal with the project
+  // being moved elsewhere in the filesystem
+  preg["SaveLocation"] << project_dir;
+
+  // Save each of the layers with 'saveable' roles
+  int i = 0;
+  for(LayerIterator it = GetCurrentImageData()->GetLayers(
+        MAIN_ROLE | LABEL_ROLE | OVERLAY_ROLE); !it.IsAtEnd(); ++it)
+    {
+    ImageWrapperBase *layer = it.GetLayer();
+
+    // Get the filename of the layer
+    const char *filename = layer->GetFileName();
+
+    // If the layer does not have a filename, skip it
+    if(!filename || strlen(filename) == 0)
+      continue;
+
+    // Get the full name of the image file
+    std::string layer_file_full = itksys::SystemTools::CollapseFullPath(filename);
+
+    // Create a folder for this layer
+    Registry &folder = preg.Folder(Registry::Key("Layers.Layer[%03d]", i++));
+
+    // Put the filename and relative filename into the folder
+    folder["AbsolutePath"] << layer_file_full;
+
+    // Put the role associated with the file into the folder
+    folder["Role"].PutEnum(SNAPRegistryIO::GetEnumMapLayerRole(), it.GetRole());
+
+    // Save the metadata associated with the layer
+    SaveMetaDataAssociatedWithLayer(layer, it.GetRole(), &folder);
+    }
+}
+
+void IRISApplication::SaveProject(const std::string &proj_file)
+{
+  // Header for ITK-SNAP projects
+  static const char *header =
+      "ITK-SNAP (itksnap.org) Project File\n"
+      "\n"
+      "This file can be moved/copied along with the images that it references\n"
+      "as long as the relative location of the images to the project file is \n"
+      "the same. Do not modify the SaveLocation entry, or this will not work.\n";
+
+  // Get the full name of the project file
+  std::string proj_file_full = itksys::SystemTools::CollapseFullPath(proj_file.c_str());
+
+  // Create a registry that will be used to save the project
+  Registry preg;
+
+  // Do the actual writing to the registry
+  SaveProjectToRegistry(preg, proj_file_full);
+
+  // Finally, save the registry
+  preg.WriteToXMLFile(proj_file_full.c_str(), header);
+
+  // Save the project filename
+  m_GlobalState->SetProjectFilename(proj_file_full.c_str());
+
+  // Update the history
+  m_SystemInterface->GetHistoryManager()->
+      UpdateHistory("Project", proj_file_full, false);
+
+  // Store the project registry
+  m_LastSavedProjectState = preg;
+}
+
+void IRISApplication::OpenProject(
+    const std::string &proj_file, IRISWarningList &warn)
+{
+  // Load the registry file
+  Registry preg;
+  preg.ReadFromXMLFile(proj_file.c_str());
+
+  // Get the full name of the project file
+  std::string proj_file_full = itksys::SystemTools::CollapseFullPath(proj_file.c_str());
+
+  // Get the directory in which the project will be saved
+  std::string project_dir = itksys::SystemTools::GetParentDirectory(proj_file_full.c_str());
+
+  // Read the location where the file was saved initially
+  std::string project_save_dir = preg["SaveLocation"][""];
+
+  // If the locations are different, we will attempt to find relative paths first
+  bool moved = (project_save_dir != project_dir);
+
+  // Read all the layers
+  std::string key;
+  bool main_loaded = false;
+  for(int i = 0;
+      preg.HasFolder(key = Registry::Key("Layers.Layer[%03d]", i));
+      i++)
+    {
+    // Get the key for the next image
+    Registry &folder = preg.Folder(key);
+
+    // Read the role
+    LayerRole role = folder["Role"].GetEnum(
+          SNAPRegistryIO::GetEnumMapLayerRole(), NO_ROLE);
+
+    // Validate the role
+    if(role == MAIN_ROLE && i != 0)
+      throw IRISException("Layer %d in a project may not be of type 'Main Image'", i);
+
+    if(role != MAIN_ROLE && i == 0)
+      throw IRISException("Layer 0 in a project must be of type 'Main Image'");
 
-  // Detemine the type
-  return AddIRISOverlayImage(&io, force_type);
+    if(role != MAIN_ROLE && role != LABEL_ROLE
+       && role != OVERLAY_ROLE)
+      throw IRISException("Layer %d has an unrecognized type", i);
+
+    // Get the filenames for the layer
+    std::string layer_file_full = folder["AbsolutePath"][""];
+
+    // If the project has moved, try finding a relative location
+    if(moved)
+      {
+      std::string relative_path = itksys::SystemTools::RelativePath(
+            project_save_dir.c_str(), layer_file_full.c_str());
+
+      std::string moved_file_full = itksys::SystemTools::CollapseFullPath(
+            relative_path.c_str(), project_dir.c_str());
+
+      if(itksys::SystemTools::FileExists(moved_file_full.c_str(), true))
+        layer_file_full = moved_file_full;
+      }
+
+    // Load the image and its metadata
+    LoadImage(layer_file_full.c_str(), role, warn, &folder);
+
+    // Check if the main has been loaded
+    if(role == MAIN_ROLE)
+      main_loaded = true;
+    }
+
+  // If main has not been loaded, throw an exception
+  if(!main_loaded)
+    throw IRISException("Empty or invalid project (main image not found in the project file).");
+
+  // Save the project filename
+  m_GlobalState->SetProjectFilename(proj_file_full.c_str());
+
+  // Update the history
+  m_SystemInterface->GetHistoryManager()->
+      UpdateHistory("Project", proj_file_full, false);
+
+  // Simulate saving the project into a registy that will be cached. This
+  // allows us to check later whether the project state has changed.
+  SaveProjectToRegistry(m_LastSavedProjectState, proj_file_full);
+}
+
+bool IRISApplication::IsProjectUnsaved()
+{
+  // Place the current state of the project into the registry
+  Registry reg_current;
+  SaveProjectToRegistry(reg_current, m_GlobalState->GetProjectFilename());
+
+  // Compare with the last saved state
+  return (reg_current != m_LastSavedProjectState);
+}
+
+bool IRISApplication::IsProjectFile(const char *filename)
+{
+  // This is pretty weak. What we really need is XML validation to check
+  // that this is a real registry, and then some minimal check to see that
+  // this is a project file
+  try
+  {
+  Registry preg;
+  preg.ReadFromXMLFile(filename);
+  return (preg.HasEntry("SaveLocation") && preg.HasEntry("Version"));
+  }
+  catch(...)
+  {
+  return false;
+  }
+}
+
+
+
+
+void IRISApplication::Quit()
+{
+  if(IsSnakeModeActive())
+    {
+    // Before quitting the application, we need to exit snake mode
+    SetCurrentImageDataToIRIS();
+    ReleaseSNAPImageData();
+    }
+
+  // Delete all the overlays
+  LayerIterator itovl = m_CurrentImageData->GetLayers(OVERLAY_ROLE);
+  while(!itovl.IsAtEnd())
+    {
+    UnloadOverlay(itovl.GetLayer());
+    itovl = m_CurrentImageData->GetLayers(OVERLAY_ROLE);
+    }
+
+  // Unload the main image
+  UnloadMainImage();
+}
+
+bool IRISApplication::IsMainImageLoaded() const
+{
+  return this->GetCurrentImageData()->IsMainLoaded();
 }
 
 
@@ -1331,30 +2186,6 @@ IRISApplication
 
 void 
 IRISApplication
-::LoadLabelImageFile(const char *filename)
-{
-  // Load the settings associated with this file
-  Registry regFull;
-  m_SystemInterface->FindRegistryAssociatedWithFile(filename, regFull);
-
-  // Get the folder dealing with grey image properties
-  // TODO: Figure out something about this!!!
-  Registry &regGrey = regFull.Folder("Files.Grey");
-
-  // Read the image in native format
-  GuidedNativeImageIO io;
-  io.ReadNativeImage(filename, regGrey);
-
-  // Set the image as the current grayscale image
-  UpdateIRISSegmentationImage(&io);
-
-  // Save the filename for the UI
-  m_GlobalState->SetSegmentationFileName(filename);
-  m_GlobalState->SetLastAssociatedPreprocessingFileName(filename);
-}
-
-void 
-IRISApplication
 ::ReorientImage(vnl_matrix_fixed<double, 3, 3> inDirection)
 {
   // This should only be possible in IRIS mode
@@ -1363,12 +2194,373 @@ IRISApplication
   // The main image should be loaded at this point
   assert(m_CurrentImageData->IsMainLoaded());
 
+  // Perform reorientation in the current image data
+  m_CurrentImageData->SetDirectionMatrix(inDirection);
+
+  /*
   // Compute a new coordinate transform object
   ImageCoordinateGeometry icg(
-    inDirection, m_DisplayToAnatomyRAI, 
+    inDirection, m_DisplayToAnatomyRAI,
     m_CurrentImageData->GetMain()->GetSize());
 
+
   // Send this coordinate transform to the image data
   m_CurrentImageData->SetImageGeometry(icg);
+  */
+
+  // Fire the pose change event
+  InvokeEvent(MainImagePoseChangeEvent());
+}
+
+void IRISApplication::LoadLabelDescriptions(const char *file)
+{
+  // Read the labels from file
+  this->m_ColorLabelTable->LoadFromFile(file);
+
+  // Reset the current drawing and overlay labels
+  m_GlobalState->SetDrawingColorLabel(m_ColorLabelTable->GetFirstValidLabel());
+  m_GlobalState->SetDrawOverFilter(DrawOverFilter());
+
+  // Update the history
+  m_SystemInterface->GetHistoryManager()->
+      UpdateHistory("LabelDescriptions", file, true);
+
+  // We also want to reset the label history at this point, as these are
+  // very different labels
+  m_LabelUseHistory->Reset();
+}
+
+void IRISApplication::SaveLabelDescriptions(const char *file)
+{
+  this->m_ColorLabelTable->SaveToFile(file);
+  m_SystemInterface->GetHistoryManager()->
+      UpdateHistory("LabelDescriptions", file, true);
+}
+
+bool IRISApplication::IsSnakeModeActive() const
+{
+  return (m_CurrentImageData == m_SNAPImageData);
+}
+
+bool IRISApplication::IsSnakeModeLevelSetActive() const
+{
+  return IsSnakeModeActive() && m_SNAPImageData->IsSnakeLoaded();
+}
+
+/*
+void IRISApplication::ComputeSNAPSpeedImage(CommandType *progressCB)
+{
+  assert(IsSnakeModeActive());
+  if(m_GlobalState->GetSnakeType() == EDGE_SNAKE)
+    {
+    m_SNAPImageData->DoEdgePreprocessing(progressCB);
+    }
+  else if(m_GlobalState->GetSnakeType() == IN_OUT_SNAKE)
+    {
+    m_SNAPImageData->DoInOutPreprocessing(progressCB);
+    }
+
+  // Mark the speed  image as valid
+  m_GlobalState->SetSpeedValid(true);
+
+  InvokeEvent(SpeedImageChangedEvent());
+}
+*/
+
+void IRISApplication::SetSnakeMode(SnakeType mode)
+{
+  // We must be in snake mode
+  assert(IsSnakeModeActive());
+
+  // We can't be changing the snake type while there is an active preprocessing
+  // mode. This should never happen in the code, so we use an assert
+  assert(m_PreprocessingMode == PREPROCESS_NONE);
+
+  // If the mode has changed, some modifications are needed
+  if(mode != m_GlobalState->GetSnakeType())
+    {
+    // Set the actual snake mode
+    m_GlobalState->SetSnakeType(mode);
+
+    // Set the speed to invalud
+    m_GlobalState->SetSpeedValid(false);
+
+    // Set the snake parameters. TODO: see how we did this in the old
+    // snap and preserve the information!!!
+    m_GlobalState->SetSnakeParameters(
+          mode == IN_OUT_SNAKE ?
+            SnakeParameters::GetDefaultInOutParameters() :
+            SnakeParameters::GetDefaultEdgeParameters());
+
+    // Clear the speed layer
+    m_SNAPImageData->InitializeSpeed();
+    }
+}
+
+SnakeType IRISApplication::GetSnakeMode() const
+{
+  return m_GlobalState->GetSnakeType();
+}
+
+void IRISApplication::LeaveGMMPreprocessingMode()
+{
+  m_GMMPreviewWrapper->DetachInputsAndOutputs();
+
+  // Before deleting the clustering engine, we store the mixture model
+  // The smart pointer mechanism makes sure the mixture model lives on
+  // even if the clustering engine is deleted
+  m_LastUsedMixtureModel = m_ClusteringEngine->GetMixtureModel();
+
+  // Update the m_time on the mixture model, so in the future we can test
+  // if it is current
+  m_LastUsedMixtureModel->Modified();
+
+  // Deallocate whatever was created for GMM processing
+  m_ClusteringEngine = NULL;
 }
 
+void IRISApplication::EnterGMMPreprocessingMode()
+{
+  // Create a new clustering engine with some samples
+  m_ClusteringEngine = UnsupervisedClustering::New();
+  m_ClusteringEngine->SetDataSource(m_SNAPImageData);
+  m_ClusteringEngine->InitializeClusters();
+
+  // Check if the last used mixture model matches the number of componetns
+  bool can_use_saved_mixture =
+      (m_LastUsedMixtureModel &&
+       m_LastUsedMixtureModel->GetNumberOfComponents() ==
+       m_ClusteringEngine->GetMixtureModel()->GetNumberOfComponents());
+
+  if(can_use_saved_mixture)
+    {
+    // Check if the m-time on any of the images in IRISImageData has been
+    // updated, indicating that this is new/different data
+    for(LayerIterator lit = m_IRISImageData->GetLayers(MAIN_ROLE | OVERLAY_ROLE);
+        !lit.IsAtEnd(); ++lit)
+      {
+      if(lit.GetLayer()->GetImageBase()->GetMTime() > m_LastUsedMixtureModel->GetMTime())
+        {
+        can_use_saved_mixture = false;
+        break;
+        }
+      }
+
+    // If the timestamp check has been passed, we can use the original mixture.
+    // TODO: clean up this code, currently it does a lot of unnecessary calls to Kmeans++
+    if(can_use_saved_mixture)
+      {
+      m_ClusteringEngine->SetNumberOfClusters(m_LastUsedMixtureModel->GetNumberOfGaussians());
+      m_ClusteringEngine->InitializeClusters();
+      m_ClusteringEngine->SetMixtureModel(m_LastUsedMixtureModel);
+      }
+    }
+
+  m_GMMPreviewWrapper->AttachInputs(m_SNAPImageData);
+  m_GMMPreviewWrapper->AttachOutputWrapper(m_SNAPImageData->GetSpeed());
+  m_GMMPreviewWrapper->SetParameters(m_ClusteringEngine->GetMixtureModel());
+}
+
+void IRISApplication::EnterRandomForestPreprocessingMode()
+{
+  // Create a random forest classification engine
+  m_ClassificationEngine = RFClassificationEngine::New();
+  m_ClassificationEngine->SetDataSource(m_SNAPImageData);
+
+  // Check if we can reuse the classifier from the last run
+  bool can_use_saved_classifier =
+      (m_LastUsedRFClassifier &&
+       m_LastUsedRFClassifierComponents ==
+       m_ClassificationEngine->GetNumberOfComponents());
+
+  if(can_use_saved_classifier)
+    {
+    // Check if the m-time on any of the images in IRISImageData has been
+    // updated, indicating that this is new/different data
+    for(LayerIterator lit = m_IRISImageData->GetLayers(MAIN_ROLE | OVERLAY_ROLE);
+        !lit.IsAtEnd(); ++lit)
+      {
+      if(lit.GetLayer()->GetImageBase()->GetMTime() > m_LastUsedRFClassifier->GetMTime())
+        {
+        can_use_saved_classifier = false;
+        break;
+        }
+      }
+
+    if(can_use_saved_classifier)
+      {
+      m_ClassificationEngine->SetClassifier(m_LastUsedRFClassifier);
+      }
+    }
+
+  // Connect to the preview wrapper
+  m_RandomForestPreviewWrapper->AttachInputs(m_SNAPImageData);
+  m_RandomForestPreviewWrapper->AttachOutputWrapper(m_SNAPImageData->GetSpeed());
+  m_RandomForestPreviewWrapper->SetParameters(m_ClassificationEngine->GetClassifier());
+}
+
+#include "RandomForestClassifier.h"
+
+void IRISApplication::LeaveRandomForestPreprocessingMode()
+{
+  m_RandomForestPreviewWrapper->DetachInputsAndOutputs();
+
+  // Before deleting the classification engine, we store the classifier
+  // The smart pointer mechanism makes sure the classifier lives on
+  // even if the engine is deleted
+  m_LastUsedRFClassifier = m_ClassificationEngine->GetClassifier();
+  m_LastUsedRFClassifierComponents = m_ClassificationEngine->GetNumberOfComponents();
+
+  // Update the m_time on the classifier, so in the future we can test
+  // if it is current
+  m_LastUsedRFClassifier->Modified();
+
+  // TODO: delete this code
+  // m_RandomForestPreviewWrapper->SetParameters(NULL);
+
+  // Clear the classification engine
+  m_ClassificationEngine = NULL;
+}
+
+void IRISApplication::EnterPreprocessingMode(PreprocessingMode mode)
+{
+  // Do not reenter the same mode
+  if(mode == m_PreprocessingMode)
+    return;
+
+  // Detach the current mode
+  switch(m_PreprocessingMode)
+    {
+    case PREPROCESS_THRESHOLD:
+      m_ThresholdPreviewWrapper->DetachInputsAndOutputs();
+      break;
+
+    case PREPROCESS_EDGE:
+      m_EdgePreviewWrapper->DetachInputsAndOutputs();
+      break;
+
+    case PREPROCESS_GMM:
+      this->LeaveGMMPreprocessingMode();
+      break;
+
+    case PREPROCESS_RF:
+      this->LeaveRandomForestPreprocessingMode();
+      break;
+
+    default:
+      break;
+    }
+
+  // As we enter the new mode, we also determine what the target snake mode should be
+  // (snake mode is either edge == Casseles or input = Zhu+Yuille)
+  SnakeType target_snake_type = m_GlobalState->GetSnakeType();
+
+  // Enter the new mode
+  switch(mode)
+    {
+    case PREPROCESS_THRESHOLD:
+      m_ThresholdPreviewWrapper->AttachInputs(m_SNAPImageData);
+      m_ThresholdPreviewWrapper->AttachOutputWrapper(m_SNAPImageData->GetSpeed());
+      target_snake_type = IN_OUT_SNAKE;
+      break;
+
+    case PREPROCESS_EDGE:
+      m_EdgePreviewWrapper->AttachInputs(m_SNAPImageData);
+      m_EdgePreviewWrapper->AttachOutputWrapper(m_SNAPImageData->GetSpeed());
+      target_snake_type = EDGE_SNAKE;
+      break;
+
+    case PREPROCESS_GMM:
+      this->EnterGMMPreprocessingMode();
+      target_snake_type = IN_OUT_SNAKE;
+      break;
+
+    case PREPROCESS_RF:
+      this->EnterRandomForestPreprocessingMode();
+      target_snake_type = IN_OUT_SNAKE;
+      break;
+
+    default:
+      break;
+    }
+
+  m_PreprocessingMode = mode;
+
+  // Reset the current snake parameters if necessary
+  if(m_GlobalState->GetSnakeType() != target_snake_type)
+    {
+    m_GlobalState->SetSnakeType(target_snake_type);
+    m_GlobalState->SetSnakeParameters(
+          target_snake_type == EDGE_SNAKE
+          ? SnakeParameters::GetDefaultEdgeParameters()
+          : SnakeParameters::GetDefaultInOutParameters());
+    }
+
+  // Record the mode if it's not a bogus mode
+  if(mode != PREPROCESS_NONE)
+    m_GlobalState->SetLastUsedPreprocessingMode(mode);
+}
+
+PreprocessingMode IRISApplication::GetPreprocessingMode() const
+{
+  return m_PreprocessingMode;
+}
+
+AbstractSlicePreviewFilterWrapper *
+IRISApplication
+::GetPreprocessingFilterPreviewer(PreprocessingMode mode)
+{
+  switch(mode)
+    {
+    case PREPROCESS_THRESHOLD:
+      return m_ThresholdPreviewWrapper;
+    case PREPROCESS_EDGE:
+      return m_EdgePreviewWrapper;
+    case PREPROCESS_GMM:
+      return m_GMMPreviewWrapper;
+    case PREPROCESS_RF:
+      return m_RandomForestPreviewWrapper;
+    default:
+      return NULL;
+    }
+}
+
+void
+IRISApplication
+::ApplyCurrentPreprocessingModeToSpeedVolume(itk::Command *progress)
+{
+  AbstractSlicePreviewFilterWrapper *wrapper =
+      this->GetPreprocessingFilterPreviewer(m_PreprocessingMode);
+
+  if(wrapper)
+    {
+    wrapper->ComputeOutputVolume(progress);
+    m_GlobalState->SetSpeedValid(true);
+    }
+}
+
+IRISApplication::BubbleArray&
+IRISApplication::GetBubbleArray()
+{
+  return m_BubbleArray;
+}
+
+bool IRISApplication::InitializeActiveContourPipeline()
+{
+  // Initialize the segmentation with current bubbles and parameters
+  if(m_SNAPImageData->InitializeSegmentation(
+       m_GlobalState->GetSnakeParameters(),
+       m_BubbleArray, m_GlobalState->GetDrawingColorLabel()))
+    {
+    // Fire an event indicating the layers have changed
+    InvokeEvent(LayerChangeEvent());
+    return true;
+    }
+
+  return false;
+}
+
+
+
+
+
diff --git a/Logic/Framework/IRISApplication.h b/Logic/Framework/IRISApplication.h
index 1bdeffb..313dbcc 100644
--- a/Logic/Framework/IRISApplication.h
+++ b/Logic/Framework/IRISApplication.h
@@ -32,7 +32,12 @@
   PURPOSE.  See the above copyright notices for more information. 
 
 =========================================================================*/
+
+#ifndef __IRISApplication_h_
+#define __IRISApplication_h_
+
 #include "ImageCoordinateTransform.h"
+#include "IRISDisplayGeometry.h"
 #include "itkImageRegion.h"
 #include "itkExceptionObject.h"
 #include "GlobalState.h"
@@ -40,19 +45,53 @@
 #include "itkCommand.h"
 #include "SystemInterface.h"
 #include "UndoDataManager.h"
+#include "SNAPEvents.h"
 
 // #include "itkImage.h"
 
 // Forward reference to the classes pointed at
 class GenericImageData;
+class IRISException;
 class IRISImageData;
 class SNAPImageData;
 class MeshExportSettings;
 class GuidedNativeImageIO;
+class ThresholdSettings;
+class EdgePreprocessingSettings;
+class AbstractSlicePreviewFilterWrapper;
+class UnsupervisedClustering;
+class RFClassificationEngine;
+class ImageWrapperBase;
+class MeshManager;
+class AbstractLoadImageDelegate;
+class AbstractSaveImageDelegate;
+class IRISWarningList;
+class GaussianMixtureModel;
+class RandomForestClassifier;
+struct IRISDisplayGeometry;
+class LabelUseHistory;
+
+
+template <class TTraits> class PresetManager;
+class ColorMapPresetTraits;
+typedef PresetManager<ColorMapPresetTraits> ColorMapPresetManager;
+
+template <class TFilterConfigTraits> class SlicePreviewFilterWrapper;
+class SmoothBinaryThresholdFilterConfigTraits;
+class EdgePreprocessingFilterConfigTraits;
+class GMMPreprocessingFilterConfigTraits;
+class RFPreprocessingFilterConfigTraits;
+template <typename TIn, typename TOut> class SmoothBinaryThresholdImageFilter;
+template <typename TIn, typename TOut> class EdgePreprocessingImageFilter;
+template <typename TIn, typename TVIn, typename TOut> class GMMClassifyImageFilter;
+
+
 namespace itk {
-  template <class TPixel, unsigned int VDimension> class OrientedImage;
+  template <class TPixel, unsigned int VDimension> class Image;
+  template <class TPixel, unsigned int VDimension> class VectorImage;
 }
 
+
 /**
  * \class IRISApplication
  * \brief This class encapsulates the highest level login of SNAP and IRIS.
@@ -70,31 +109,39 @@ namespace itk {
  * \sa IRISImageData
  * \sa SNAPImageData
  */
-class IRISApplication 
+class IRISApplication : public itk::Object
 {
 public:
+
+  irisITKObjectMacro(IRISApplication, itk::Object)
+
   // Typedefs
   typedef itk::ImageRegion<3> RegionType;
   typedef itk::Size<3> SizeType;
-  typedef itk::OrientedImage<GreyType,3> GreyImageType;
-  typedef itk::OrientedImage<RGBType,3> RGBImageType;
-  typedef itk::OrientedImage<LabelType,3> LabelImageType;
-  typedef itk::OrientedImage<float,3> SpeedImageType;
+
+  // The internal representation of anatomical images
+  typedef itk::VectorImage<GreyType, 3> AnatomyImageType;
+
+  typedef itk::Image<LabelType,3> LabelImageType;
+  typedef itk::Image<short ,3> SpeedImageType;
   typedef itk::Command CommandType;
   typedef UndoDataManager<LabelType> UndoManagerType;
 
-  // The main image can be of these types
-  enum MainImageType { MAIN_SCALAR, MAIN_RGB, MAIN_ANY };
+  // A drawing performed on a slice
+  typedef itk::Image<unsigned char, 2> SliceBinaryImageType;
 
-  /**
-   * Constructor for the IRIS/SNAP application
-   */
-  IRISApplication();
+  // Bubble array
+  typedef std::vector<Bubble> BubbleArray;
+
+  // Declare events fired by this object
+  FIRES(CursorUpdateEvent)
+  FIRES(MainImageDimensionsChangeEvent)
+  FIRES(MainImagePoseChangeEvent)
+  FIRES(LayerChangeEvent)
+  FIRES(SegmentationChangeEvent)
+  FIRES(SpeedImageChangedEvent)
+  FIRES(DisplayToAnatomyCoordinateMappingChangeEvent)
 
-  /**
-   * Destructor for the application
-   */
-  virtual ~IRISApplication();
 
   /**
    * Get image data related to IRIS operations
@@ -121,31 +168,84 @@ public:
    */
   void SetCurrentImageDataToSNAP();
 
+  /**
+    Whether we are currently in active contour mode or not
+    */
+  bool IsSnakeModeActive() const;
+
+  /**
+   * Whether there is currently a valid level set function
+   */
+  bool IsSnakeModeLevelSetActive() const;
+
+  /**
+   * Load an image using a delegate object. The delegate specializes the behavior
+   * of this class to different layer roles (main image, overlay). The warnings
+   * generated in the course of the IO operation are stored in the passed in
+   * warning list object;
+   */
+  void LoadImageViaDelegate(const char *fname,
+                            AbstractLoadImageDelegate *del,
+                            IRISWarningList &wl);
+
+  /**
+   * Load an image for a particular role using the default delegate for this role.
+   * This convenience method is currently implemented for MAIN, OVERLAY and LABEL
+   * image types. This method loads the associated settings and metadata for the
+   * image either from the user's image associations directory (default) or from
+   * the provided Registry object.
+   */
+  void LoadImage(const char *fname, LayerRole role,
+                 IRISWarningList &wl, Registry *meta_data_reg = NULL);
+
+  /**
+   * Create a delegate for saving an image interactively or non-interactively
+   * via a wizard.
+   */
+  SmartPtr<AbstractSaveImageDelegate> CreateSaveDelegateForLayer(
+      ImageWrapperBase *layer, LayerRole role);
+
   /** 
-   * Set a new main image for IRIS. This method is called to load either grey or
-   * RGB image data into IRISImageData. The parameter is the GuidedNativeImageIO,
-   * which holds an image in native format. The second parameter specified whether
-   * to force RGB or grey image, or to determine image type based on the data.
+   * Update the main image in IRIS. The first parameter is the IO object that
+   * has the image data loaded, and the second parameter is an optional pointer
+   * to a registry from which to read the metadata. If not provided, metadata
+   * will be read from the 'image association' files automatically generated
+   * as images are closed.
    */
-  MainImageType UpdateIRISMainImage(
-    GuidedNativeImageIO *nativeIO, MainImageType force_type);
+  void UpdateIRISMainImage(GuidedNativeImageIO *nativeIO, Registry *metadata = NULL);
 
   /**
-   * Add an overlay image into IRIS. This method is called to load either grey or
-   * RGB image data into IRISImageData. The parameter is the GuidedNativeImageIO,
-   * which holds an image in native format. The second parameter specified whether
-   * to force RGB or grey image, or to determine image type based on the data.
+   * Add an overlay image into IRIS.
    */
-  MainImageType AddIRISOverlayImage(
-    GuidedNativeImageIO *nativeIO, MainImageType force_type);
+  void AddIRISOverlayImage(GuidedNativeImageIO *nativeIO, Registry *metadata = NULL);
 
   /**
-   * Set a new grey image for the IRIS Image data.  This method is called when the
-   * grey image is loaded.  The prerequisite to this method is that the SNAP data
-   * not be active (CurrentImageData == IRISImageData).
+   * Remove a specific overlay
    */
-  void UnloadOverlays();
-  void UnloadOverlayLast();
+  void UnloadOverlay(ImageWrapperBase *ovl);
+
+  /**
+   * Remove all overlays
+   */
+  void UnloadAllOverlays();
+
+  /**
+   * Unload the main image layer
+   */
+  void UnloadMainImage();
+
+  /**
+   * Move layers (overlay for now) up and down in the list, changing their
+   * display order
+   */
+  void ChangeOverlayPosition(ImageWrapperBase *overlay, int dir);
+
+  /**
+   * Quit the application. This responds to the quit action in the main application.
+   * This unloads all layers. Additionally, when the application is in snake mode,
+   * it first cancels snake mode
+   */
+  void Quit();
 
   /** 
    * Update the IRIS image data with an external segmentation image (e.g., 
@@ -156,9 +256,14 @@ public:
   /** 
    * Clear the IRIS segmentation image
    */
-  void ClearIRISSegmentationImage();
+  void ResetIRISSegmentationImage();
 
-  /** 
+  /**
+   * Clear the SNAP segmentation image (active during pre-segmentation)
+   */
+  void ResetSNAPSegmentationImage();
+
+  /**
    * Update the SNAP image data with an external speed image (e.g., 
    * loaded from a file).
    */
@@ -172,6 +277,45 @@ public:
                                CommandType *progressCommand = NULL);
 
   /**
+    Enter given preprocessing mode. This activates the pipeline that can be
+    used to provide automatic on-the-fly preview of the preprocessing result
+    as the user moves the cursor or changes preprocessing parameters. When
+    preprocessing is done, or before switching to a new preprocessing mode,
+    call this method with PREPROCESS_NONE to disconnect the pipeline.
+    */
+  void EnterPreprocessingMode(PreprocessingMode mode);
+
+  /**
+    Uses the current preprocessing mode to compute the entire extents of the
+    speed image. This also sets the SpeedValid flag in GlobalState to true
+    */
+  void ApplyCurrentPreprocessingModeToSpeedVolume(itk::Command *progress = 0);
+
+  /**
+    Get the current preprocessing mode
+    */
+  PreprocessingMode GetPreprocessingMode() const;
+
+  /**
+    Get a pointer to the object that handles the preview pipeline for the
+    current preprocessing mode. This object can be used to toggle preview
+    and to execute the preprocessing filter. Returns NULL if the mode is
+    PREPROCESS_NONE
+    */
+  AbstractSlicePreviewFilterWrapper *GetPreprocessingFilterPreviewer(
+      PreprocessingMode mode);
+
+  /**
+    Get a reference to the bubble array
+    */
+  BubbleArray &GetBubbleArray();
+
+  /**
+    Initialize the SNAP active contour evolution with the bubbles.
+    */
+  bool InitializeActiveContourPipeline();
+
+  /**
    * Update IRIS image data with the segmentation contained in the SNAP image
    * data.
    */
@@ -180,27 +324,37 @@ public:
   /**
    * Get the segmentation label data
    */
-  irisGetMacro(ColorLabelTable, ColorLabelTable *);
+  irisGetMacro(ColorLabelTable, ColorLabelTable *)
+
+  /**
+   * Get the history of recently used color label combos
+   */
+  irisGetMacro(LabelUseHistory, LabelUseHistory *)
 
   /** Release the SNAP Image data */
   void ReleaseSNAPImageData();
   
   /** Update the display-anatomy mapping as an RAI code */
-  void SetDisplayToAnatomyRAI(const char *rai0,const char *rai1,const char *rai2);
+  void SetDisplayGeometry(const IRISDisplayGeometry &dispGeom);
+
+  /** Get the current display-anatomy mapping */
+  irisGetMacro(DisplayGeometry, const IRISDisplayGeometry &)
+
+  /** Does the current image have oblique orientation? */
+  bool IsImageOrientationOblique();
 
   /** Get the current image to anatomy RAI code */
   std::string GetImageToAnatomyRAI();
 
-  /** Get the current display to anatomy RAI code */
-  std::string GetDisplayToAnatomyRAI(unsigned int slice);
-
   /** Get the image axis for a given anatomical direction */
-  size_t GetImageDirectionForAnatomicalDirection(
+  int GetImageDirectionForAnatomicalDirection(
     AnatomicalDirection iAnat);
 
   /** Get the display window corresponding to an anatomical direction */
-  size_t GetDisplayWindowForAnatomicalDirection(
-    AnatomicalDirection iAnat);
+  int GetDisplayWindowForAnatomicalDirection(AnatomicalDirection iAnat) const;
+
+  /** Get the anatomical direction in the i-th display window */
+  AnatomicalDirection GetAnatomicalDirectionForDisplayWindow(int iWin) const;
 
   /**
    * Get the global state object
@@ -213,10 +367,17 @@ public:
   irisGetMacro(SystemInterface, SystemInterface *);
 
   /**
+   * Get the history manager
+   */
+  irisGetMacro(HistoryManager, HistoryManager *)
+
+  /**
    * Set the current cursor position.  This will cause all the active image
-   * wrappers to update their current slice numbers
+   * wrappers to update their current slice numbers. By default, the method
+   * does nothing if the passed in cursor position is the same as the current
+   * cursor position. When force is true, the cursor position is set regardless.
    */
-  void SetCursorPosition(const Vector3ui cursor);
+  void SetCursorPosition(const Vector3ui cursor, bool force = false);
 
   /**
    * Get the cursor position
@@ -229,15 +390,13 @@ public:
   void ExportSlice(AnatomicalDirection iSliceAnatomy, const char *file);
 
   /** Export voxel statistis to a file */
-  void ExportSegmentationStatistics(const char *file) 
-    throw(itk::ExceptionObject);
+  void ExportSegmentationStatistics(const char *file);
 
   /**
    * Export the 3D mesh to a file, using settings passed in the
    * MeshExportSettings structure.
    */
-  void ExportSegmentationMesh(const MeshExportSettings &sets, itk::Command *cmd)
-    throw(itk::ExceptionObject);
+  void ExportSegmentationMesh(const MeshExportSettings &sets, itk::Command *cmd);
 
   /** 
    * This method is used to selectively override labels in a target 
@@ -247,11 +406,45 @@ public:
   LabelType DrawOverLabel(LabelType iTarget);
 
   /**
+   * Method that signals the beginning of segmentation update operation. This
+   * method should be used in conjuction with UpdateSegmentationVoxel method
+   * to apply current drawing properties to a set of voxels
+   *
+   * These methods don't perform error checking - it's the user's responsibility
+   * to call them in the correct order. The methods are not currently reentrant
+   * (i.e., should not be used by multiple threads).
+   *
+   * TODO: this is currently only being used for spray paint. But this set of
+   * methods should be expanded with a method that works with itk iterators and
+   * should be made the main entrypoint for changing segmentations. This will
+   * especially be necessary for RLE segmentation management.
+   *
+   */
+  void BeginSegmentationUpdate(std::string undo_name);
+
+  /**
+   * Apply the current drawing label to a voxel. Depending on coverage mode
+   * and the voxel's current label, the label of the voxel may be changed
+   */
+  void UpdateSegmentationVoxel(const Vector3ui &pos);
+
+  /**
+   * Complete the segmentation update. Returns the actual number of voxels
+   * relabeled since BeginSegmentationUpdate();
+   */
+  int EndSegmentationUpdate();
+
+  /**
    * Really simple replacement of one label with another. Returns the 
    * number of voxels changed.
    */
   size_t ReplaceLabel(LabelType drawing, LabelType drawover);
 
+  /**
+    Number of voxels of a given label in the segmentation.
+    */
+  size_t GetNumberOfVoxelsWithLabel(LabelType label);
+
   /*
    * Cut the segmentation using a plane and relabed the segmentation
    * on the side of that plane
@@ -266,25 +459,22 @@ public:
                      const Vector3d &ray, 
                      Vector3i &hit) const;
 
+
+
   /**
-   * Load the main image from file. You can either specify that the main
-   * image is of a given type (grey vs. rgb) or you can let the program 
-   * decide dynamically, based on the number of components in the file
+   * Check if there is an image currently loaded in SNAP.
    */
-  MainImageType LoadMainImage(const char *filename, MainImageType force_type);
+  bool IsMainImageLoaded() const;
 
-  MainImageType LoadOverlayImage(const char *filename, MainImageType force_type);
+  /**
+    Load label descriptions from file
+    */
+  void LoadLabelDescriptions(const char *filename);
 
   /**
-   * This is the most high-level method to load a segmentation image. The
-   * segmentation image can only be loaded after the grey image has been 
-   * loaded and it must have the same dimensions
-   * 
-   * This function is deprecated and replaced by the more robust version
-   * in the ImageIOWizardLogic class!
-   *
-   */
-  void LoadLabelImageFile(const char *filename);
+    Save label descriptions to file
+    */
+  void SaveLabelDescriptions(const char *filename);
 
   /**
    * Store the current state as an undo point, allowing the user to revert
@@ -318,31 +508,210 @@ public:
    */
   void ReorientImage(vnl_matrix_fixed<double, 3, 3> inDirection);
 
-private:
+  /**
+    Apply a binary drawing performed on an orthogonal slice to the
+    main segmentation.
+    */
+  unsigned int UpdateSegmentationWithSliceDrawing(
+      SliceBinaryImageType *drawing,
+      const ImageCoordinateTransform &xfmSliceToImage,
+      double zSlice,
+      const std::string &undoTitle);
+
+  /** Get the pointer to the settings used for threshold-based preprocessing */
+  // irisGetMacro(ThresholdSettings, ThresholdSettings *)
+
+  /** Get the pointer to the settings used for edge-based preprocessing */
+  irisGetMacro(EdgePreprocessingSettings, EdgePreprocessingSettings *)
+
+  /** Get the object used to drive the unsupervised clustering */
+  irisGetMacro(ClusteringEngine, UnsupervisedClustering *)
+
+  /** Get the object used to drive the supervised classification */
+  irisGetMacro(ClassificationEngine, RFClassificationEngine *)
+
+  /** Set the current snake mode. This method should be called instead of the
+      method in GlobalState because when the snake mode is set, some changes
+      are made to the image data (having to do with setting up the preview
+      filters if they are available, and cleaning speed data) */
+  void SetSnakeMode(SnakeType mode);
+
+  /** Get the current snake mode (active contours must be active) */
+  SnakeType GetSnakeMode() const;
+
+  /** Get the object used to manage VTK mesh creation */
+  irisGetMacro(MeshManager, MeshManager *)
+
+  /** Get the preset manager for color maps */
+  irisGetMacro(ColorMapPresetManager, ColorMapPresetManager *)
+
+  // ----------------------- Project support ------------------------------
+
+  /**
+   * Save a project. This method requires that all the layers that can be
+   * saved in the project have a filename. The project will be written to
+   * the file in the Registry format. The name of the project will be stored.
+   *
+   * A project is reset (set to empty string) when a new main image is loaded.
+   */
+  void SaveProject(const std::string &proj_file);
+
+  /**
+   * Open an existing project.
+   */
+  void OpenProject(const std::string &proj_file, IRISWarningList &warn);
+
+  /**
+   * Check if the project has modified since the last time it was saved. This
+   * is a bit tricky to keep track of, because the project includes both the
+   * list of images and the parameters.
+   */
+  bool IsProjectUnsaved();
+
+  /**
+   * Check if a file constitutes a project. This needs to be done quickly,
+   * and since the files passed in might be binary, loading the file in
+   * memory is not an option
+   */
+  bool IsProjectFile(const char *filename);
+
+  // --------------------- End project support ----------------------------
+
+
+protected:
+
+  IRISApplication();
+  virtual ~IRISApplication();
+
+  // Map cursor from one image data to another
+  void TransferCursor(GenericImageData *source, GenericImageData *target);
+
   // Image data objects
   GenericImageData *m_CurrentImageData;
-  IRISImageData *m_IRISImageData;
-  SNAPImageData *m_SNAPImageData;
+  SmartPtr<IRISImageData> m_IRISImageData;
+  SmartPtr<SNAPImageData> m_SNAPImageData;
 
   // Color label data
-  ColorLabelTable *m_ColorLabelTable;
+  SmartPtr<ColorLabelTable> m_ColorLabelTable;
+
+  // Label use history
+  SmartPtr<LabelUseHistory> m_LabelUseHistory;
 
   // Global state object
   // TODO: Incorporate GlobalState into IRISApplication more nicely
-  GlobalState *m_GlobalState;
+  SmartPtr<GlobalState> m_GlobalState;
 
   // SystemInterface used to get things from the system
   SystemInterface *m_SystemInterface;
 
-  /** RAI between anatomy space and image space */
-  std::string m_DisplayToAnatomyRAI[3];
+  // History manager
+  HistoryManager *m_HistoryManager;
+
+  // Coordinate mapping between display space and anatomical space
+  IRISDisplayGeometry m_DisplayGeometry;
 
   // Undo data manager. Perhaps this should really be in IRISImageData, but
   // there is a lot of stuff here that is ambiguous in this way. The manager
   // stores 'deltas', i.e., differences between states of the segmentation
   // image. These deltas are compressed, allowing us to store a bunch of 
   // undo steps with little cost in performance or memory
-  
   UndoManagerType m_UndoManager;
+
+  // Settings for the speed preprocessing. Still not sure this is the best
+  // place to put this stuff!
+  SmartPtr<EdgePreprocessingSettings> m_EdgePreprocessingSettings;
+
+  // The last mixture model used for clustering. This is reused during repeated
+  // calls to the active contour segmentation, as long as the layers haven't
+  // been updated.
+  SmartPtr<GaussianMixtureModel> m_LastUsedMixtureModel;
+
+  // The threshold-based preview wrapper type
+  typedef SlicePreviewFilterWrapper<SmoothBinaryThresholdFilterConfigTraits>
+                                                   ThresholdPreviewWrapperType;
+
+  // The edge-based preview wrapper type
+  typedef SlicePreviewFilterWrapper<EdgePreprocessingFilterConfigTraits>
+                                           EdgePreprocessingPreviewWrapperType;
+
+  // The GMM preview wrapper type
+  typedef SlicePreviewFilterWrapper<GMMPreprocessingFilterConfigTraits>
+                                            GMMPreprocessingPreviewWrapperType;
+
+  // The GMM preview wrapper type
+  typedef SlicePreviewFilterWrapper<RFPreprocessingFilterConfigTraits>
+                                            RFPreprocessingPreviewWrapperType;
+
+  // The threshold-based wrapper
+  SmartPtr<ThresholdPreviewWrapperType> m_ThresholdPreviewWrapper;
+
+  // The edge-based wrapper
+  SmartPtr<EdgePreprocessingPreviewWrapperType> m_EdgePreviewWrapper;
+
+  // GMM-based preprocessing wrapper
+  SmartPtr<GMMPreprocessingPreviewWrapperType> m_GMMPreviewWrapper;
+
+  // Random forest preprocessing wrapper
+  SmartPtr<RFPreprocessingPreviewWrapperType> m_RandomForestPreviewWrapper;
+
+  // The EM classification object
+  SmartPtr<UnsupervisedClustering> m_ClusteringEngine;
+
+  // The Random Foreset classification object
+  SmartPtr<RFClassificationEngine> m_ClassificationEngine;
+
+  // The last classifier used for random forest segmentation. This is reused during
+  // repeated calls to the active contour segmentation, as long as the layers haven't
+  // been updated.
+  SmartPtr<RandomForestClassifier> m_LastUsedRFClassifier;
+
+  // The number of components for the last used RF classifier
+  int m_LastUsedRFClassifierComponents;
+
+  // Mesh object (used to manage meshes)
+  SmartPtr<MeshManager> m_MeshManager;
+
+  // Color map preset manager
+  SmartPtr<ColorMapPresetManager> m_ColorMapPresetManager;
+
+  // The currently hooked up preprocessing filter preview wrapper
+  PreprocessingMode m_PreprocessingMode;
+
+  // Array of bubbles
+  BubbleArray m_BubbleArray;
+
+  // State used in conjunction with BeginSegmentationUpdate/EndSegmentationUpdate
+  std::string m_SegmentationUpdateName;
+  unsigned int m_SegmentationChangeCount;
+
+  // Save metadata for a layer to the associations file
+  void SaveMetaDataAssociatedWithLayer(ImageWrapperBase *layer, int role,
+                                       Registry *override = NULL);
+  void LoadMetaDataAssociatedWithLayer(ImageWrapperBase *layer, int role,
+                                       Registry *override = NULL);
+
+  // Create layer-specific segmentation settings (threshold settings, e.g.)
+  void CreateSegmentationSettings(ImageWrapperBase *wrapper, LayerRole role);
+
+  // Helper functions for GMM mode enter/exit
+  void EnterGMMPreprocessingMode();
+  void LeaveGMMPreprocessingMode();
+
+  // Helper functions for RF mode enter/exit
+  void EnterRandomForestPreprocessingMode();
+  void LeaveRandomForestPreprocessingMode();
+
+  // ----------------------- Project support ------------------------------
+
+  // Cached state of the project at the time of last open/save. Used to check
+  // if the project has been modified.
+  Registry m_LastSavedProjectState;
+
+  // Internal method used by the project IO code
+  void SaveProjectToRegistry(Registry &preg, const std::string proj_file_full);
+
+  // Auto-adjust contrast of a layer on load
+  void AutoContrastLayerOnLoad(ImageWrapperBase *layer);
 };
 
+#endif // __IRISApplication_h_
diff --git a/Logic/Framework/IRISImageData.cxx b/Logic/Framework/IRISImageData.cxx
index b706c73..fac4e37 100644
--- a/Logic/Framework/IRISImageData.cxx
+++ b/Logic/Framework/IRISImageData.cxx
@@ -34,51 +34,36 @@
 =========================================================================*/
 // ITK Includes
 #include "IRISImageData.h"
+#include "itkImage.h"
 
-void
 IRISImageData
-::SetSegmentationImage(LabelImageType *newLabelImage)
+::IRISImageData()
 {
-  // Set the new segmentation image
-  GenericImageData::SetSegmentationImage(newLabelImage);
-  
-  // Update the undo wrapper to match
-  LabelImageWrapper::Iterator itUndo = m_UndoWrapper.GetImageIterator();
-  LabelImageWrapper::ConstIterator itSeg = m_LabelWrapper.GetImageConstIterator();
+}
 
-  while(!itUndo.IsAtEnd())
-    {
-    itUndo.Set(itSeg.Get());
-    ++itUndo;
-    ++itSeg;
-    }
+IRISImageData::~IRISImageData()
+{
 }
 
 void
 IRISImageData
-::SetGreyImage(GreyImageType *newGreyImage,
-                const ImageCoordinateGeometry &newGeometry,
-                const GreyTypeToNativeFunctor &native)
+::SetSegmentationImage(LabelImageType *newLabelImage)
 {
-  GenericImageData::SetGreyImage(
-    newGreyImage, newGeometry, native);
-  m_UndoWrapper.InitializeToWrapper(&m_LabelWrapper, (LabelType) 0);
+  // Set the new segmentation image
+  GenericImageData::SetSegmentationImage(newLabelImage);
 }
 
 void
 IRISImageData
-::SetRGBImage(RGBImageType *newRGBImage,
-              const ImageCoordinateGeometry &newGeometry)
+::ResetSegmentationImage()
 {
-  GenericImageData::SetRGBImage(newRGBImage, newGeometry);
-  m_UndoWrapper.InitializeToWrapper(&m_LabelWrapper, (LabelType) 0);
+  GenericImageData::ResetSegmentationImage();
 }
 
 void
 IRISImageData
 ::UnloadMainImage()
 {
-  m_UndoWrapper.Reset();
   GenericImageData::UnloadMainImage();
 }
 
diff --git a/Logic/Framework/IRISImageData.h b/Logic/Framework/IRISImageData.h
index 3dd2c50..b357b2d 100644
--- a/Logic/Framework/IRISImageData.h
+++ b/Logic/Framework/IRISImageData.h
@@ -45,19 +45,10 @@
 class IRISImageData : public GenericImageData
 {
 public:
+  irisITKObjectMacro(IRISImageData, GenericImageData)
 
-  IRISImageData(IRISApplication *parent)
-    : GenericImageData(parent) {}
-  virtual ~IRISImageData() {};
-
-  /**
-   * Access the segmentation image (read only access allowed 
-   * to preserve state)
-   */
-  LabelImageWrapper* GetUndoImage() {
-    assert(m_MainImageWrapper->IsInitialized() && m_UndoWrapper.IsInitialized());
-    return &m_UndoWrapper;
-  }
+  typedef Superclass::ImageBaseType ImageBaseType;
+  typedef Superclass::AnatomicImageType AnatomicImageType;
 
   /**
    * We override the parent's SetSegmentationImage in order to initialize the
@@ -65,29 +56,19 @@ public:
    */
   void SetSegmentationImage(LabelImageType *newLabelImage);
 
-  void SetGreyImage(
-    GreyImageType *newGreyImage,
-    const ImageCoordinateGeometry &newGeometry,
-    const GreyTypeToNativeFunctor &native);
+  /**
+   * We override the parent's ResetSegmentationImage in order to initialize the
+   * undo wrapper to match.
+   */
+  void ResetSegmentationImage();
 
-  void SetRGBImage(RGBImageType *newRGBImage,
-                   const ImageCoordinateGeometry &newGeometry);
 
   virtual void UnloadMainImage();
 
 protected:
 
-  // Starting with SNAP 1.6, the IRISImageData object will store a second
-  // copy of the segmentation image for the purpose of implementing fast 
-  // undo functionality. This image is used to support situations where we
-  // want to allow multiple updates to the segmentation image between saving
-  // 'undo points'. This is necessary for paintbrush operation, since it would
-  // be too expensive to store an undo point for every movement of the paintbrush
-  // (and it would be difficult for the user too). So this UndoWrapper stores the
-  // segmentation image _at the last undo point_. See IRISApplication::StoreUndoPoint
-  // for details.
-  LabelImageWrapper m_UndoWrapper;
-
+  IRISImageData();
+  virtual ~IRISImageData();
 };
 
 #endif
diff --git a/Logic/Framework/ImageIODelegates.cxx b/Logic/Framework/ImageIODelegates.cxx
new file mode 100644
index 0000000..6d3f29b
--- /dev/null
+++ b/Logic/Framework/ImageIODelegates.cxx
@@ -0,0 +1,259 @@
+#include "ImageIODelegates.h"
+#include "GuidedNativeImageIO.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "HistoryManager.h"
+
+
+/* =============================
+   Abstract Classes
+   ============================= */
+
+void LoadAnatomicImageDelegate
+::ValidateHeader(GuidedNativeImageIO *io, IRISWarningList &wl)
+{
+  typedef itk::ImageIOBase IOB;
+
+  IOB::IOComponentType ct = io->GetComponentTypeInNativeImage();
+  if(ct > IOB::SHORT)
+    {
+    wl.push_back(
+          IRISWarning(
+            "Warning: Loss of Precision."
+            "You are opening an image with 32-bit or greater precision, "
+            "but ITK-SNAP only provides 16-bit precision. "
+            "Intensity values reported in ITK-SNAP may differ slightly from the "
+            "actual values in the image."
+            ));
+    }
+}
+
+
+/* =============================
+   MAIN Image
+   ============================= */
+void
+LoadMainImageDelegate
+::UnloadCurrentImage()
+{
+  m_Driver->UnloadMainImage();
+}
+
+void
+LoadMainImageDelegate
+::UpdateApplicationWithImage(GuidedNativeImageIO *io)
+{
+  // Update the IRIS driver
+  m_Driver->UpdateIRISMainImage(io, this->GetMetaDataRegistry());
+}
+
+
+/* =============================
+   OVERLAY Image
+   ============================= */
+
+void
+LoadOverlayImageDelegate
+::UnloadCurrentImage()
+{
+  // TODO: what do we do here? Are we always adding an overlay? What about
+  // on an undo in a wizard?
+}
+
+void
+LoadOverlayImageDelegate
+::UpdateApplicationWithImage(GuidedNativeImageIO *io)
+{
+  m_Driver->AddIRISOverlayImage(io, this->GetMetaDataRegistry());
+
+}
+
+
+void
+LoadOverlayImageDelegate
+::ValidateHeader(GuidedNativeImageIO *io, IRISWarningList &wl)
+{
+  // Do the parent's check
+  LoadAnatomicImageDelegate::ValidateHeader(io, wl);
+
+  // Now check for dimensions mismatch
+  GenericImageData *id = m_Driver->GetCurrentImageData();
+
+  // Check the dimensions, throw exception
+  Vector3ui szSeg = io->GetDimensionsOfNativeImage();
+  Vector3ui szMain = id->GetMain()->GetSize();
+  if(szSeg != szMain)
+    {
+    throw IRISException("Error: Mismatched Dimensions. "
+                        "The size of the overlay image (%d x %d x %d) "
+                        "does not match the size of the main image "
+                        "(%d x %d x %d). Images must have the same dimensions.",
+                        szSeg[0], szSeg[1], szSeg[2],
+                        szMain[0], szMain[1], szMain[2]);
+    }
+}
+
+
+/* =============================
+   SEGMENTATION Image
+   ============================= */
+
+void
+LoadSegmentationImageDelegate
+::ValidateHeader(GuidedNativeImageIO *io, IRISWarningList &wl)
+{
+  GenericImageData *id = m_Driver->GetCurrentImageData();
+
+  // Check the dimensions, throw exception
+  Vector3ui szSeg = io->GetDimensionsOfNativeImage();
+  Vector3ui szMain = id->GetMain()->GetSize();
+  if(szSeg != szMain)
+    {
+    throw IRISException("Error: Mismatched Dimensions. "
+                        "The size of the segmentation image (%d x %d x %d) "
+                        "does not match the size of the main image "
+                        "(%d x %d x %d). Images must have the same dimensions.",
+                        szSeg[0], szSeg[1], szSeg[2],
+                        szMain[0], szMain[1], szMain[2]);
+    }
+
+  // Check the number of components
+  if(io->GetNumberOfComponentsInNativeImage() != 1)
+    {
+    throw IRISException("Error: Multicomponent Image. "
+                        "The segmentation image has multiple (%d) components, "
+                        "but only one component is supported by ITK-SNAP.",
+                        io->GetNumberOfComponentsInNativeImage());
+    }
+}
+
+void
+LoadSegmentationImageDelegate
+::ValidateImage(GuidedNativeImageIO *io, IRISWarningList &wl)
+{
+  // Get the two images to compare
+  GenericImageData *id = m_Driver->GetCurrentImageData();
+  itk::ImageBase<3> *main = id->GetMain()->GetImageBase();
+  itk::ImageBase<3> *native = io->GetNativeImage();
+
+  // Check the header properties
+  // Check if there is a discrepancy in the header fields. This will not
+  // preclude the user from loading the image, but it will generate a
+  // warning, hopefully leading users to adopt more flexible file formats
+  bool match_spacing = true, match_origin = true, match_direction = true;
+
+  for(unsigned int i = 0; i < 3; i++)
+    {
+    if(main->GetSpacing()[i] != native->GetSpacing()[i])
+      match_spacing = false;
+
+    if(main->GetOrigin()[i] != native->GetOrigin()[i])
+      match_origin = false;
+
+    for(size_t j = 0; j < 3; j++)
+      {
+      double diff = fabs(main->GetDirection()(i,j) - native->GetDirection()(i,j));
+      if(diff > 1.0e-4)
+        match_direction = false;
+      }
+    }
+
+  if(!match_spacing || !match_origin || !match_direction)
+    {
+    // Come up with a warning message
+    std::string object, verb;
+    if(!match_spacing && !match_origin && !match_direction)
+      { object = "spacing, origin and orientation"; }
+    else if (!match_spacing && !match_origin)
+      { object = "spacing and origin"; }
+    else if (!match_spacing && !match_direction)
+      { object = "spacing and orientation"; }
+    else if (!match_origin && !match_direction)
+      { object = "origin and orientation";}
+    else if (!match_spacing)
+      { object = "spacing"; }
+    else if (!match_direction)
+      { object = "orientation";}
+    else if (!match_origin)
+      { object = "origin"; }
+
+    // Create an alert box
+    wl.push_back(IRISWarning(
+                   "Warning: Header Mismatch."
+                   "There is a mismatch between the header of the image that you are "
+                   "loading and the header of the main image currently open in ITK-SNAP. "
+                   "The images have different %s. "
+                   "ITK-SNAP will ignore the header in the image you are loading.",
+                   object.c_str()));
+    }
+}
+
+void
+LoadSegmentationImageDelegate
+::UpdateApplicationWithImage(GuidedNativeImageIO *io)
+{
+  m_Driver->UpdateIRISSegmentationImage(io);
+}
+
+void
+LoadSegmentationImageDelegate
+::UnloadCurrentImage()
+{
+  // It is unnecessary to unload the current segmentation image, because that
+  // just will reinitialize it with zeros. It's safe to just do nothing.
+}
+
+
+void
+DefaultSaveImageDelegate::Initialize(
+    IRISApplication *driver,
+    ImageWrapperBase *wrapper,
+    const std::string &histname,
+    bool trackInLocalHistory)
+{
+  AbstractSaveImageDelegate::Initialize(driver);
+  m_Wrapper = wrapper;
+  m_Track = trackInLocalHistory;
+  this->AddHistoryName(histname);
+}
+
+void DefaultSaveImageDelegate::AddHistoryName(const std::string &histname)
+{
+  m_HistoryNames.push_back(histname);
+}
+
+const char *DefaultSaveImageDelegate::GetHistoryName()
+{
+  return m_HistoryNames.front().c_str();
+}
+
+
+void DefaultSaveImageDelegate
+::SaveImage(const std::string &fname, GuidedNativeImageIO *io,
+            Registry &reg, IRISWarningList &wl)
+{
+  try
+    {
+    m_SaveSuccessful = false;
+    m_Wrapper->WriteToFile(fname.c_str(), reg);
+    m_SaveSuccessful = true;
+
+    m_Wrapper->SetFileName(fname);
+    for(std::list<std::string>::const_iterator it = m_HistoryNames.begin();
+        it != m_HistoryNames.end(); ++it)
+      {
+      m_Driver->GetHistoryManager()->UpdateHistory(*it, fname, m_Track);
+      }
+    }
+  catch(std::exception &exc)
+    {
+    throw exc;
+   }
+}
+
+const char *DefaultSaveImageDelegate::GetCurrentFilename()
+{
+  return m_Wrapper->GetFileName();
+}
+
+
diff --git a/Logic/Framework/ImageIODelegates.h b/Logic/Framework/ImageIODelegates.h
new file mode 100644
index 0000000..211e984
--- /dev/null
+++ b/Logic/Framework/ImageIODelegates.h
@@ -0,0 +1,183 @@
+#ifndef IMAGEIODELEGATES_H
+#define IMAGEIODELEGATES_H
+
+#include "SNAPCommon.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "IRISException.h"
+#include <vector>
+
+class IRISApplication;
+class IRISWarningList;
+class ImageWrapperBase;
+
+class IRISWarningList : public std::vector<IRISWarning> {};
+
+/**
+  A parent class for all IO delegates. Child objects must implement the
+  virtual members defined in this class. Delegates are used to specialize
+  the behavior of image IO wizards, as well as to load images from
+  command line.
+  */
+class AbstractLoadImageDelegate : public itk::Object
+{
+public:
+
+  irisITKAbstractObjectMacro(AbstractLoadImageDelegate, itk::Object)
+
+  virtual void Initialize(IRISApplication *driver)
+    { m_Driver = driver; }
+
+  /**
+   * Set the registry that will be used to load image-level and project-level
+   * metadata associated with the image. If the registry is not specified, the
+   * code will attempt to load it from the automatically created image
+   * association files (created every time an image is closed). The registry
+   * should contain a folder LayerMetaData for the layer-specific stuff (e.g.,
+   * colormap, etc). For layers in the "MAIN Image" role, it can contain a
+   * folder "ProjectMetaData" as well.
+   */
+  irisGetSetMacro(MetaDataRegistry, Registry *)
+
+  virtual void ValidateHeader(GuidedNativeImageIO *io, IRISWarningList &wl) {}
+  virtual void ValidateImage(GuidedNativeImageIO *io, IRISWarningList &wl) {}
+  virtual void UnloadCurrentImage() = 0;
+  virtual void UpdateApplicationWithImage(GuidedNativeImageIO *io) = 0;
+
+protected:
+  AbstractLoadImageDelegate() : m_MetaDataRegistry(NULL) {}
+  virtual ~AbstractLoadImageDelegate() {}
+
+  IRISApplication *m_Driver;
+
+private:
+  Registry *m_MetaDataRegistry;
+};
+
+class LoadAnatomicImageDelegate : public AbstractLoadImageDelegate
+{
+public:
+
+  irisITKAbstractObjectMacro(LoadAnatomicImageDelegate, AbstractLoadImageDelegate)
+
+  virtual void ValidateHeader(GuidedNativeImageIO *io, IRISWarningList &wl);
+
+protected:
+  LoadAnatomicImageDelegate() {}
+  virtual ~LoadAnatomicImageDelegate() {}
+};
+
+class LoadMainImageDelegate : public LoadAnatomicImageDelegate
+{
+public:
+
+  irisITKObjectMacro(LoadMainImageDelegate, LoadAnatomicImageDelegate)
+
+  void UnloadCurrentImage();
+  void UpdateApplicationWithImage(GuidedNativeImageIO *io);
+
+protected:
+  LoadMainImageDelegate() {}
+  virtual ~LoadMainImageDelegate() {}
+
+};
+
+class LoadOverlayImageDelegate : public LoadAnatomicImageDelegate
+{
+public:
+
+  irisITKObjectMacro(LoadOverlayImageDelegate, LoadAnatomicImageDelegate)
+
+  void UnloadCurrentImage();
+  void UpdateApplicationWithImage(GuidedNativeImageIO *io);
+  void ValidateHeader(GuidedNativeImageIO *io, IRISWarningList &wl);
+
+protected:
+  LoadOverlayImageDelegate() {}
+  virtual ~LoadOverlayImageDelegate() {}
+};
+
+class LoadSegmentationImageDelegate : public AbstractLoadImageDelegate
+{
+public:
+
+  irisITKObjectMacro(LoadSegmentationImageDelegate, AbstractLoadImageDelegate)
+
+  virtual void ValidateHeader(GuidedNativeImageIO *io, IRISWarningList &wl);
+  virtual void ValidateImage(GuidedNativeImageIO *io, IRISWarningList &wl);
+  void UnloadCurrentImage();
+  void UpdateApplicationWithImage(GuidedNativeImageIO *io);
+
+protected:
+  LoadSegmentationImageDelegate() {}
+  virtual ~LoadSegmentationImageDelegate() {}
+};
+
+
+class AbstractSaveImageDelegate : public itk::Object
+{
+public:
+
+  irisITKAbstractObjectMacro(AbstractSaveImageDelegate, itk::Object)
+
+  virtual void Initialize(IRISApplication *driver)
+    { m_Driver = driver; m_SaveSuccessful = false; }
+
+  virtual void SaveImage(
+      const std::string &fname,
+      GuidedNativeImageIO *io,
+      Registry &reg,
+      IRISWarningList &wl) = 0;
+
+  virtual const char *GetCurrentFilename() = 0;
+
+  virtual const char *GetHistoryName() = 0;
+
+  /**
+   * Has the file been saves successfully after the call to SaveImage?
+   */
+  bool IsSaveSuccessful() { return m_SaveSuccessful; }
+
+protected:
+  AbstractSaveImageDelegate() {}
+  virtual ~AbstractSaveImageDelegate() {}
+
+  IRISApplication *m_Driver;
+  bool m_SaveSuccessful;
+};
+
+class DefaultSaveImageDelegate : public AbstractSaveImageDelegate
+{
+public:
+  irisITKObjectMacro(DefaultSaveImageDelegate, AbstractSaveImageDelegate)
+
+  virtual void Initialize(IRISApplication *driver,
+                          ImageWrapperBase *wrapper,
+                          const std::string &histname,
+                          bool trackInLocalHistory = true);
+
+  // Add a history name to update when the filename is saved. It is possible
+  // for multiple history names to be updated
+  void AddHistoryName(const std::string &histname);
+
+  virtual const char *GetHistoryName();
+
+  virtual void SaveImage(
+      const std::string &fname,
+      GuidedNativeImageIO *io,
+      Registry &reg,
+      IRISWarningList &wl);
+
+  virtual const char *GetCurrentFilename();
+
+protected:
+
+  DefaultSaveImageDelegate() {}
+  virtual ~DefaultSaveImageDelegate() {}
+
+  ImageWrapperBase *m_Wrapper;
+  std::list<std::string> m_HistoryNames;
+  bool m_Track;
+};
+
+#endif // IMAGEIODELEGATES_H
diff --git a/Logic/Framework/LayerAssociation.h b/Logic/Framework/LayerAssociation.h
new file mode 100644
index 0000000..455238c
--- /dev/null
+++ b/Logic/Framework/LayerAssociation.h
@@ -0,0 +1,80 @@
+#ifndef LAYERASSOCIATION_H
+#define LAYERASSOCIATION_H
+
+#include <SNAPCommon.h>
+
+class ImageWrapperBase;
+class GenericImageData;
+class IRISApplication;
+
+template<class TObject, class TLayer>
+struct DefaultLayerAssociationFactoryDelegate
+{
+  TObject * New(TLayer *layer) { return new TObject(layer); }
+};
+
+template <class TObject>
+struct LayerAssociationObjectWrapper
+{
+  operator TObject * () { return m_Object; }
+
+  LayerAssociationObjectWrapper(TObject *p = NULL)
+  {
+    m_Object = p;
+    m_Visit = 0;
+  }
+
+  TObject *m_Object;
+  unsigned long m_Visit;
+};
+
+/**
+  This is an object than maintains a one-to-one association between all layers
+  in an IRISApplication and objects of some user-defined type.
+  Calling Update() will create new objects for new layers that have appeared
+  and delete objects associated with layers that have disappeared.
+
+  The user can pass in a delegate factory object, which can be used to create
+  new instances of the Object.
+  */
+template<class TObject,
+         class TFilter = ImageWrapperBase,
+         class TFactoryDelegate =
+           DefaultLayerAssociationFactoryDelegate<TObject, TFilter> >
+class LayerAssociation
+{
+public:
+  typedef LayerAssociation<TObject, TFilter> Self;
+  typedef LayerAssociationObjectWrapper<TObject> RHS;
+
+  LayerAssociation();
+  virtual ~LayerAssociation();
+
+  void SetSource(IRISApplication *app);
+
+  // Set the delegate, provided in case you need a delegate with some
+  // special functionality.
+  irisSetMacro(Delegate, const TFactoryDelegate &)
+  irisGetMacro(Delegate, const TFactoryDelegate &)
+
+  // Allow lookup by layer directly
+  RHS & operator [] (const TFilter *p);
+
+  bool HasLayer(const TFilter *p);
+
+  void Update();
+
+protected:
+  typedef std::map<unsigned long, RHS> LayerMap;
+  typedef typename LayerMap::iterator iterator;
+  typedef typename LayerMap::const_iterator const_iterator;
+
+  LayerMap m_LayerMap;
+  IRISApplication *m_Source;
+  TFactoryDelegate m_Delegate;
+  unsigned long m_VisitCounter;
+
+};
+
+
+#endif // LAYERASSOCIATION_H
diff --git a/Logic/Framework/LayerAssociation.txx b/Logic/Framework/LayerAssociation.txx
new file mode 100644
index 0000000..dbf5f32
--- /dev/null
+++ b/Logic/Framework/LayerAssociation.txx
@@ -0,0 +1,112 @@
+#ifndef __Layer_Association_txx__
+#define __Layer_Association_txx__
+
+#include "LayerAssociation.h"
+#include "IRISApplication.h"
+#include "GenericImageData.h"
+#include "IRISImageData.h"
+#include "SNAPImageData.h"
+#include "ImageWrapperBase.h"
+
+template<class TObject, class TFilter, class TFactoryDelegate>
+LayerAssociation<TObject, TFilter, TFactoryDelegate>
+::LayerAssociation()
+{
+  m_Source = NULL;
+  m_VisitCounter = 0;
+}
+
+template<class TObject, class TFilter, class TFactoryDelegate>
+LayerAssociation<TObject, TFilter, TFactoryDelegate>
+::~LayerAssociation()
+{
+  SetSource(NULL);
+}
+
+
+template<class TObject, class TFilter, class TFactoryDelegate>
+void
+LayerAssociation<TObject, TFilter, TFactoryDelegate>
+::Update()
+{
+  m_VisitCounter++;
+
+  // Iterate over all the objects in the image data
+  if(m_Source)
+    {
+    // Iterate over all of the image data objects in IRISApplication
+    GenericImageData *id[] = {m_Source->GetIRISImageData(),
+                              m_Source->GetSNAPImageData()};
+
+    for(int k = 0; k < 2; k++)
+      {
+      if(id[k])
+        {
+        for(LayerIterator lit = id[k]->GetLayers(); !lit.IsAtEnd(); ++lit)
+          {
+          ImageWrapperBase *wb = lit.GetLayer();
+          TFilter *wf = dynamic_cast<TFilter *>(wb);
+          if(wf && wf->IsInitialized())
+            {
+            iterator it = m_LayerMap.find(wf->GetUniqueId());
+            if(it != m_LayerMap.end())
+              {
+              // Mark it as visited
+              it->second.m_Visit = m_VisitCounter;
+              }
+            else
+              {
+              RHS rhs(m_Delegate.New(wf));
+              rhs.m_Visit = m_VisitCounter;
+              m_LayerMap.insert(std::make_pair(wf->GetUniqueId(), rhs));
+              }
+            }
+          }
+        }
+      }
+    }
+
+  // Safely delete the objects that have not been visited
+  iterator it = m_LayerMap.begin();
+  while(it != m_LayerMap.end())
+    {
+    if(it->second.m_Visit != m_VisitCounter)
+      {
+      delete (TObject *) it->second;
+      m_LayerMap.erase(it++);
+      }
+    else
+      it++;
+    }
+}
+
+template<class TObject, class TFilter, class TFactoryDelegate>
+void
+LayerAssociation<TObject, TFilter, TFactoryDelegate>
+::SetSource(IRISApplication *source)
+{
+  if(source != m_Source)
+    {
+    m_Source = source;
+    this->Update();
+    }
+}
+
+template<class TObject, class TFilter, class TFactoryDelegate>
+typename LayerAssociation<TObject, TFilter, TFactoryDelegate>::RHS &
+LayerAssociation<TObject, TFilter, TFactoryDelegate>
+::operator [] (const TFilter *p)
+{
+  return m_LayerMap[p->GetUniqueId()];
+}
+
+template<class TObject, class TFilter, class TFactoryDelegate>
+bool
+LayerAssociation<TObject, TFilter, TFactoryDelegate>
+::HasLayer(const TFilter *p)
+{
+  return p && m_LayerMap.find(p->GetUniqueId()) != m_LayerMap.end();
+}
+
+
+#endif // __Layer_Association_txx__
diff --git a/Logic/Framework/LayerIterator.cxx b/Logic/Framework/LayerIterator.cxx
new file mode 100644
index 0000000..2f87d81
--- /dev/null
+++ b/Logic/Framework/LayerIterator.cxx
@@ -0,0 +1,219 @@
+#include "LayerIterator.h"
+#include "GenericImageData.h"
+#include "ImageWrapperBase.h"
+
+
+LayerIterator
+::LayerIterator(
+    GenericImageData *data, int role_filter)
+{
+  // Store the source information
+  m_ImageData = data;
+  m_RoleFilter = role_filter;
+
+  // Populate role names
+  if(m_RoleDefaultNames.size() == 0)
+    {
+    m_RoleDefaultNames.insert(std::make_pair(MAIN_ROLE, "Main Image"));
+    m_RoleDefaultNames.insert(std::make_pair(OVERLAY_ROLE, "Overlay"));
+    m_RoleDefaultNames.insert(std::make_pair(LABEL_ROLE, "Segmentation"));
+    m_RoleDefaultNames.insert(std::make_pair(SNAP_ROLE, "SNAP Image"));
+    }
+
+  // Move to the beginning
+  MoveToBegin();
+}
+
+LayerIterator& LayerIterator
+::MoveToBegin()
+{
+  // Initialize to point to the first wrapper in the first role, even if
+  // this is an invalid configuration
+  m_RoleIter = m_ImageData->m_Wrappers.begin();
+  if(m_RoleIter != m_ImageData->m_Wrappers.end())
+    m_WrapperInRoleIter = m_RoleIter->second.begin();
+
+  // Move up until we find a valid role or end
+  while(!IsAtEnd() && !IsPointingToListableLayer())
+    {
+    MoveToNextTrialPosition();
+    }
+
+  return *this;
+}
+
+bool LayerIterator
+::IsAtEnd() const
+{
+  // We are at end when there are no roles left
+  return m_RoleIter == m_ImageData->m_Wrappers.end();
+}
+
+
+LayerIterator& LayerIterator
+::MoveToEnd()
+{
+  m_RoleIter = m_ImageData->m_Wrappers.end();
+  return *this;
+}
+
+LayerIterator& LayerIterator
+::Find(ImageWrapperBase *value)
+{
+  // Just a linear search - we won't have so many wrappers!
+  MoveToBegin();
+  while(!this->IsAtEnd() && this->GetLayer() != value)
+    ++(*this);
+  return *this;
+}
+
+void LayerIterator::MoveToNextTrialPosition()
+{
+  // If we are at the end of storage, that's it
+  if(m_RoleIter == m_ImageData->m_Wrappers.end())
+    return;
+
+  // If we are at the end of a chain of wrappers, or if the current role
+  // is not a valid role, go to the start of the next role
+  else if(m_WrapperInRoleIter == m_RoleIter->second.end() ||
+     !(m_RoleFilter & m_RoleIter->first))
+    {
+    ++m_RoleIter;
+    if(m_RoleIter != m_ImageData->m_Wrappers.end())
+      m_WrapperInRoleIter = m_RoleIter->second.begin();
+
+    }
+
+  // Otherwise, advance the iterator in the wrapper chain
+  else
+    ++m_WrapperInRoleIter;
+}
+
+bool LayerIterator::IsPointingToListableLayer() const
+{
+  // I split this up for debugging
+
+  // Are we at end of roles?
+  if(m_RoleIter == m_ImageData->m_Wrappers.end())
+    return false;
+
+  // Are we in a valid role?
+  LayerRole lr = m_RoleIter->first;
+  if((m_RoleFilter & lr) == 0)
+    return false;
+
+  // In our role, are we at the end?
+  if(m_WrapperInRoleIter == m_RoleIter->second.end())
+    return false;
+
+  // Is the layer null?
+  if((*m_WrapperInRoleIter).IsNull())
+    return false;
+
+  return true;
+}
+
+LayerIterator &
+LayerIterator::operator ++()
+{
+  do
+    {
+    MoveToNextTrialPosition();
+    }
+  while(!IsAtEnd() && !IsPointingToListableLayer());
+
+  return *this;
+}
+
+LayerIterator &
+LayerIterator::operator +=(int k)
+{
+  for(int i = 0; i < k; i++)
+    ++(*this);
+  return *this;
+}
+
+ImageWrapperBase * LayerIterator::GetLayer() const
+{
+  assert(IsPointingToListableLayer());
+  return (*m_WrapperInRoleIter);
+}
+
+ScalarImageWrapperBase * LayerIterator::GetLayerAsScalar() const
+{
+  return dynamic_cast<ScalarImageWrapperBase *>(this->GetLayer());
+}
+
+VectorImageWrapperBase * LayerIterator::GetLayerAsVector() const
+{
+  return dynamic_cast<VectorImageWrapperBase *>(this->GetLayer());
+}
+
+LayerRole
+LayerIterator::GetRole() const
+{
+  assert(IsPointingToListableLayer());
+  return m_RoleIter->first;
+}
+
+int LayerIterator::GetPositionInRole() const
+{
+  return (int)(m_WrapperInRoleIter - m_RoleIter->second.begin());
+}
+
+int LayerIterator::GetNumberOfLayersInRole()
+{
+  assert(IsPointingToListableLayer());
+  return m_RoleIter->second.size();
+}
+
+bool LayerIterator::IsFirstInRole() const
+{
+  assert(IsPointingToListableLayer());
+  int pos = m_WrapperInRoleIter - m_RoleIter->second.begin();
+  return (pos == 0);
+}
+
+bool LayerIterator::IsLastInRole() const
+{
+  assert(IsPointingToListableLayer());
+  int pos = m_WrapperInRoleIter - m_RoleIter->second.begin();
+  return (pos == m_RoleIter->second.size() - 1);
+}
+
+bool LayerIterator::operator ==(const LayerIterator &it)
+{
+  // Two iterators are equal if they both point to the same location
+  // or both are at the end.
+  if(this->IsAtEnd())
+    return it.IsAtEnd();
+  else if(it.IsAtEnd())
+    return false;
+  else
+    return this->GetLayer() == it.GetLayer();
+}
+
+bool LayerIterator::operator !=(const LayerIterator &it)
+{
+  return !((*this) == it);
+}
+
+std::map<LayerRole, std::string> LayerIterator::m_RoleDefaultNames;
+
+
+void LayerIterator::Print(const char *what) const
+{
+  std::cout << "LI with filter " << m_RoleFilter << " operation " << what << std::endl;
+  if(this->IsAtEnd())
+    {
+    std::cout << "  AT END" << std::endl;
+    }
+  else
+    {
+    std::cout << "  Role:         " << m_RoleDefaultNames[this->GetRole()] << std::endl;
+    std::cout << "  Pos. in Role: "
+              << (int)(m_WrapperInRoleIter - m_RoleIter->second.begin()) << " of "
+              << (int) m_RoleIter->second.size() << std::endl;
+    std::cout << "  Valid:        " << this->IsPointingToListableLayer() << std::endl;
+    }
+}
diff --git a/Logic/Framework/LayerIterator.h b/Logic/Framework/LayerIterator.h
new file mode 100644
index 0000000..1524e8e
--- /dev/null
+++ b/Logic/Framework/LayerIterator.h
@@ -0,0 +1,97 @@
+#ifndef LAYERITERATOR_H
+#define LAYERITERATOR_H
+
+#include "SNAPCommon.h"
+#include <map>
+#include <vector>
+
+class GenericImageData;
+class ImageWrapperBase;
+class ScalarImageWrapperBase;
+class VectorImageWrapperBase;
+
+/**
+ * An iterator for moving through layers in the GenericImageData class
+ */
+class LayerIterator
+{
+public:
+
+  LayerIterator(GenericImageData *data, int role_filter = ALL_ROLES);
+
+  bool IsAtEnd() const;
+
+  // Move to the end
+  LayerIterator &MoveToBegin();
+
+  // Move to the end
+  LayerIterator &MoveToEnd();
+
+  // Move to a specific layer, or end if the layer is not found
+  LayerIterator &Find(ImageWrapperBase *value);
+
+  LayerIterator & operator++();
+
+  LayerIterator & operator+=(int k);
+
+  /** Get the layer being pointed to */
+  ImageWrapperBase *GetLayer() const;
+
+  /** Get the layer being pointed to, cast as Scalar (or NULL) */
+  ScalarImageWrapperBase *GetLayerAsScalar() const;
+
+  /** Get the layer being pointed to, cast as Gray (or NULL) */
+  VectorImageWrapperBase *GetLayerAsVector() const;
+
+  /** Get the role of the current layer */
+  LayerRole GetRole() const;
+
+  /** Get the position of the current layer within its role */
+  int GetPositionInRole() const;
+
+  /** Get the number of layers in the role of current layer */
+  int GetNumberOfLayersInRole();
+
+  /** Check if this is the first/last layer in its role */
+  bool IsFirstInRole() const;
+  bool IsLastInRole() const;
+
+  void Print(const char *) const;
+
+  /** Compare two iterators */
+  bool operator == (const LayerIterator &it);
+  bool operator != (const LayerIterator &it);
+
+private:
+
+  typedef std::vector<SmartPtr<ImageWrapperBase> > WrapperList;
+  typedef WrapperList::const_iterator WrapperListIterator;
+
+  typedef std::map<LayerRole, WrapperList> WrapperRoleMap;
+  typedef WrapperRoleMap::iterator WrapperRoleIterator;
+
+  // Pointer to the parent data
+  GenericImageData *m_ImageData;
+
+  // The filter defining which roles to iterate
+  int m_RoleFilter;
+
+  // A pair of iterators that define the state of this iterator
+  WrapperRoleIterator m_RoleIter;
+  WrapperListIterator m_WrapperInRoleIter;
+
+  // Internal method that advances the internal iterators by one step,
+  // regardless of whether that makes the iterator point to a valid layer
+  // or not
+  void MoveToNextTrialPosition();
+
+  // Check if the iterator is pointing to a valid layer
+  bool IsPointingToListableLayer() const;
+
+  // Default names for wrappers
+  static std::map<LayerRole, std::string> m_RoleDefaultNames;
+};
+
+
+
+#endif // LAYERITERATOR_H
diff --git a/Logic/Framework/SNAPImageData.cxx b/Logic/Framework/SNAPImageData.cxx
index 4e00ebf..7db1c1a 100644
--- a/Logic/Framework/SNAPImageData.cxx
+++ b/Logic/Framework/SNAPImageData.cxx
@@ -46,34 +46,36 @@
 #include "itkDanielssonDistanceMapImageFilter.h"
 #include "itkSubtractImageFilter.h"
 #include "itkUnaryFunctorImageFilter.h"
+#include "itkFastMutexLock.h"
 
+#include "SmoothBinaryThresholdImageFilter.h"
 #include "GlobalState.h"
 #include "EdgePreprocessingImageFilter.h"
 #include "IRISVectorTypesToITKConversion.h"
-#include "LabelImageWrapper.h"
-#include "LevelSetImageWrapper.h"
 #include "SignedDistanceFilter.h"
-#include "SmoothBinaryThresholdImageFilter.h"
-#include "SpeedImageWrapper.h"
-
-
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "ThresholdSettings.h"
+#include "ColorMap.h"
 #include "SNAPImageData.h"
 
+#include "SlicePreviewFilterWrapper.h"
+#include "PreprocessingFilterConfigTraits.h"
+
 
 SNAPImageData
-::SNAPImageData(IRISApplication *parent)
-: GenericImageData(parent)
+::SNAPImageData()
 {
-  // Update the list of linked wrappers
-  m_MainWrappers.push_back(&m_SpeedWrapper);
-  m_MainWrappers.push_back(&m_SnakeInitializationWrapper);
-  m_MainWrappers.push_back(&m_SnakeWrapper);
+  // Set the names of the wrapeprs
 
   // Initialize the level set driver to NULL
   m_LevelSetDriver = NULL;
 
   // Set the initial label color
   m_SnakeColorLabel = 0;
+
+  // Create the mutex lock
+  m_LevelSetPipelineMutexLock = itk::FastMutexLock::New();
 }
 
 
@@ -89,74 +91,21 @@ SNAPImageData
 ::InitializeSpeed()
 {
   // The Grey image wrapper should be present
-  assert(m_GreyWrapper.IsInitialized());
+  assert(m_MainImageWrapper->IsInitialized());
 
   // Intialize the speed based on the current grey image
-  m_SpeedWrapper.InitializeToWrapper(&m_GreyWrapper, 0.0f);
-}
-
-void 
-SNAPImageData
-::DoEdgePreprocessing(const EdgePreprocessingSettings &settings,
-                      itk::Command *progressCallback)
-{ 
-  // Define an edge filter to use for preprocessing
-  typedef EdgePreprocessingImageFilter<
-    GreyImageWrapper::ImageType,SpeedImageWrapper::ImageType> FilterType;
-  
-  // Configure the edge filter
-  FilterType::Pointer filter = FilterType::New();
-  
-  // Pass the settings to the filter
-  filter->SetEdgePreprocessingSettings(settings);
-
-  // Set the filter's input
-  filter->SetInput(m_GreyWrapper.GetImage());
-
-  // Provide a progress callback (if one is provided)
-  if(progressCallback)
-    filter->AddObserver(itk::ProgressEvent(),progressCallback);
-
-  // Run the filter on the whole image
-  filter->UpdateLargestPossibleRegion();
-  
-  // Pass the output of the filter to the speed wrapper
-  m_SpeedWrapper.SetImage(filter->GetOutput());
-  
-  // Dismantle this pipeline
-  m_SpeedWrapper.GetImage()->DisconnectPipeline();
-}
-
-void 
-SNAPImageData
-::DoInOutPreprocessing(const ThresholdSettings &settings,
-                       itk::Command *progressCallback)
-{
-  // Define an edge filter to use for preprocessing
-  typedef SmoothBinaryThresholdImageFilter<
-    GreyImageWrapper::ImageType,SpeedImageWrapper::ImageType> FilterType;
-  
-  // Create an edge filter for whole-image preprocessing
-  FilterType::Pointer filter = FilterType::New();
-  
-  // Pass the settings to the filter
-  filter->SetThresholdSettings(settings);
-
-  // Set the filter's input
-  filter->SetInput(m_GreyWrapper.GetImage());
+  if(m_SpeedWrapper.IsNull())
+    {
+    m_SpeedWrapper = SpeedImageWrapper::New();
+    m_SpeedWrapper->SetDefaultNickname("Speed Image");
+    PushBackImageWrapper(SNAP_ROLE, m_SpeedWrapper.GetPointer());
+    }
 
-  // Provide a progress callback (if one is provided)
-  if(progressCallback)
-    filter->AddObserver(itk::ProgressEvent(),progressCallback);
+  m_SpeedWrapper->InitializeToWrapper(m_MainImageWrapper, (GreyType) 0);
+  InvokeEvent(LayerChangeEvent());
 
-  // Run the filter
-  filter->UpdateLargestPossibleRegion();
-  
-  // Pass the output of the filter to the speed wrapper
-  m_SpeedWrapper.SetImage(filter->GetOutput());
-  
-  // Dismantle this pipeline
-  m_SpeedWrapper.GetImage()->DisconnectPipeline();
+  // Here or after it's computed?
+  m_SpeedWrapper->SetAlpha(1.0);
 }
 
 SpeedImageWrapper* 
@@ -164,71 +113,67 @@ SNAPImageData
 ::GetSpeed() 
 {
   // Make sure it exists
-  assert(m_SpeedWrapper.IsInitialized());
-  return &m_SpeedWrapper;
+  assert(IsSpeedLoaded());
+  return m_SpeedWrapper;
 }
 
 bool 
 SNAPImageData
 ::IsSpeedLoaded() 
 {
-  return m_SpeedWrapper.IsInitialized();
-}
-
-LevelSetImageWrapper* 
-SNAPImageData
-::GetSnakeInitialization() 
-{
-  assert(m_SnakeInitializationWrapper.IsInitialized());
-  return &m_SnakeInitializationWrapper;
-}
-
-bool 
-SNAPImageData
-::IsSnakeInitializationLoaded() 
-{
-  return (m_SnakeInitializationWrapper.IsInitialized());
+  return m_SpeedWrapper && m_SpeedWrapper->IsInitialized();
 }
 
 LevelSetImageWrapper* 
 SNAPImageData
 ::GetSnake() 
 {
-  assert(m_SnakeWrapper.IsInitialized());
-  return &m_SnakeWrapper;
+  assert(IsSnakeLoaded());
+  return m_SnakeWrapper;
 }
 
 bool 
 SNAPImageData
 ::IsSnakeLoaded() 
 {
-  return (m_SnakeWrapper.IsInitialized());
+  return (m_SnakeWrapper && m_SnakeWrapper->IsInitialized());
 }
 
+
 bool
 SNAPImageData
 ::InitializeSegmentation(
   const SnakeParameters &parameters, 
   const std::vector<Bubble> &bubbles, unsigned int labelColor)
 {
-  assert(m_SpeedWrapper.IsInitialized());
+  assert(IsSpeedLoaded());
 
   // Inside/outside values
-  const float INSIDE_VALUE = -1.0, OUTSIDE_VALUE = 1.0;
+  const float INSIDE_VALUE = -4.0, OUTSIDE_VALUE = 4.0;
   
   // Store the label color
   m_SnakeColorLabel = labelColor;
 
   // Types of images used here
-  typedef itk::OrientedImage<float,3> FloatImageType;
+  typedef itk::Image<float,3> FloatImageType;
+
+  // If a initialization wrapper does not exist, create it
+  if(!m_SnakeWrapper)
+    {
+    m_SnakeWrapper = LevelSetImageWrapper::New();
+    m_SnakeWrapper->SetDefaultNickname("Evolving Contour");
+    PushBackImageWrapper(SNAP_ROLE, m_SnakeWrapper.GetPointer());
+    }
 
   // Initialize the level set initialization wrapper, set pixels to OUTSIDE_VALUE
-  m_SnakeInitializationWrapper.InitializeToWrapper(&m_GreyWrapper, OUTSIDE_VALUE);
+  m_SnakeWrapper->InitializeToWrapper(m_MainImageWrapper, OUTSIDE_VALUE);
+
+  InvokeEvent(LayerChangeEvent());
 
   // Create the initial level set image by merging the segmentation data from
   // IRIS region with the bubbles
-  LabelImageType::Pointer imgInput = m_LabelWrapper.GetImage();
-  FloatImageType::Pointer imgLevelSet = m_SnakeInitializationWrapper.GetImage();
+  LabelImageType::Pointer imgInput = m_LabelWrapper->GetImage();
+  FloatImageType::Pointer imgLevelSet = m_SnakeWrapper->GetImage();
 
   // Get the target region. This really should be a region relative to the IRIS image
   // data, not an image into a needless copy of an IRIS region.
@@ -241,8 +186,8 @@ SNAPImageData
   TargetIterator itTarget(imgLevelSet,region);
 
   // During the copy loop, compute the extents of the initialization
-  Vector3l bbLower(reinterpret_cast<const long *>(region.GetSize().GetSize()));
-  Vector3l bbUpper(reinterpret_cast<const long *>(region.GetIndex().GetIndex()));
+  Vector3l bbLower = region.GetSize();
+  Vector3l bbUpper = region.GetIndex();
 
   unsigned long nInitVoxels = 0;
 
@@ -253,7 +198,7 @@ SNAPImageData
     if(itSource.Value() == m_SnakeColorLabel)
       {
       // Expand the bounding box accordingly
-      Vector3l point(itTarget.GetIndex().GetIndex());
+      Vector3l point = itTarget.GetIndex();
       bbLower = vector_min(bbLower,point);
       bbUpper = vector_max(bbUpper,point);
       
@@ -313,8 +258,8 @@ SNAPImageData
     regBubble.Crop(region);
 
     // Stretch the overall bounding box if necessary
-    bbLower = vector_min(bbLower,Vector3l(idxLower.GetIndex()));
-    bbUpper = vector_max(bbUpper,Vector3l(idxUpper.GetIndex()));
+    bbLower = vector_min(bbLower,Vector3l(idxLower));
+    bbUpper = vector_max(bbUpper,Vector3l(idxUpper));
 
     // Create an iterator with an index to fill out the bubble
     TargetIterator itThisBubble(imgLevelSet, regBubble);
@@ -343,12 +288,16 @@ SNAPImageData
   // voxels
   if (nInitVoxels == 0) 
     {
-    m_SnakeInitializationWrapper.Reset();
+    this->RemoveImageWrapper(SNAP_ROLE, m_SnakeWrapper);
+    m_SnakeWrapper = NULL;
+    InvokeEvent(LayerChangeEvent());
     return false;
     }
 
   // Make sure that the correct color label is being used
-  m_SnakeInitializationWrapper.SetColorLabel(m_ColorLabel);
+  // TODO: restore this functionality once you figure out how to display
+  // level set representations properly !!!
+  // m_SnakeInitializationWrapper->SetColorLabel(m_ColorLabel);
 
   // Initialize the snake driver
   InitalizeSnakeDriver(parameters);
@@ -364,12 +313,12 @@ SNAPImageData
 {
   m_ExternalAdvectionField = VectorImageType::New();
   m_ExternalAdvectionField->SetRegions(
-    m_SpeedWrapper.GetImage()->GetBufferedRegion());
+    m_SpeedWrapper->GetImage()->GetBufferedRegion());
   m_ExternalAdvectionField->Allocate();
   m_ExternalAdvectionField->SetSpacing(
-    m_GreyWrapper.GetImage()->GetSpacing());
+    m_MainImageWrapper->GetImageBase()->GetSpacing());
   m_ExternalAdvectionField->SetOrigin(
-    m_GreyWrapper.GetImage()->GetOrigin());
+    m_MainImageWrapper->GetImageBase()->GetOrigin());
 
   typedef itk::ImageRegionConstIterator<FloatImageType> Iterator;
   Iterator itX(imgX,imgX->GetBufferedRegion());
@@ -423,22 +372,31 @@ SNAPImageData
   // Copy the configuration parameters
   m_CurrentSnakeParameters = p;
 
+  // Enter a thread-safe section
+  m_LevelSetPipelineMutexLock->Lock();
+
   // Initialize the snake driver and pass the parameters
   m_LevelSetDriver = new SNAPLevelSetDriver3d(
-    m_SnakeInitializationWrapper.GetImage(),
-    m_SpeedWrapper.GetImage(),
+    m_SnakeWrapper->GetImage(),
+    m_SpeedWrapper->GetImage(),
     m_CurrentSnakeParameters,
     m_ExternalAdvectionField);
 
-  // Initialize the level set wrapper with the image from the level set 
-  // driver and other settings from the other wrappers
-  m_SnakeWrapper.InitializeToWrapper(
-    &m_GreyWrapper,m_LevelSetDriver->GetCurrentState());
-  m_SnakeWrapper.GetImage()->SetOrigin( m_GreyWrapper.GetImage()->GetOrigin() );
-  m_SnakeWrapper.GetImage()->SetSpacing( m_GreyWrapper.GetImage()->GetSpacing() );
-  
-  // Make sure that the correct color label is being used
-  m_SnakeWrapper.SetColorLabel(m_ColorLabel);
+  // This makes sure that m_SnakeWrapper->IsDrawable() returns true
+  m_SnakeWrapper->SetImage(m_LevelSetDriver->GetCurrentState());
+  m_SnakeWrapper->GetImage()->Modified();
+
+  // Finish thread-safe section
+  m_LevelSetPipelineMutexLock->Unlock();
+
+  // Fire events (layers changed and level set image changed)
+  this->InvokeEvent(LayerChangeEvent());
+  this->InvokeEvent(LevelSetImageChangeEvent());
+
+  // Why use segmentation's alpha?
+  m_SnakeWrapper->SetAlpha(
+        (unsigned char)(255 * m_Parent->GetGlobalState()->GetSegmentationAlpha()));
+
 }
 
 void 
@@ -449,7 +407,33 @@ SNAPImageData
   assert(m_LevelSetDriver);
 
   // Pass through to the level set driver
+
+  // Enter a thread-safe section
+  m_LevelSetPipelineMutexLock->Lock();
+
+  // clock_t c1 = clock();
   m_LevelSetDriver->Run(nIterations);
+  // clock_t c2 = clock();
+
+  // Leave a thread-safe section
+  m_LevelSetPipelineMutexLock->Unlock();
+
+  /*
+  std::cout << (c2 - c1) * 1.0 / (CLOCKS_PER_SEC * nIterations)
+            << " sec per iteration." << std::endl; */
+
+  // Fire the update event
+  this->InvokeEvent(LevelSetImageChangeEvent());
+}
+
+bool
+SNAPImageData
+::IsEvolutionConverged()
+{
+  // Make the method reentrant
+  itk::MutexLockHolder<itk::FastMutexLock> holder(*m_LevelSetPipelineMutexLock);
+
+  return m_LevelSetDriver->IsEvolutionConverged();
 }
 
 void 
@@ -459,11 +443,17 @@ SNAPImageData
   // Should be in level set mode
   assert(m_LevelSetDriver);
 
+  // Enter a thread-safe section
+  m_LevelSetPipelineMutexLock->Lock();
+
   // Pass through to the level set driver
   m_LevelSetDriver->Restart();
 
-  // Update the image pointed to by the snake wrapper
-  m_SnakeWrapper.SetImage(m_LevelSetDriver->GetCurrentState());
+  // Leave a thread-safe section
+  m_LevelSetPipelineMutexLock->Unlock();
+
+  // Fire the update event
+  this->InvokeEvent(LevelSetImageChangeEvent());
 }
 
 void 
@@ -473,8 +463,17 @@ SNAPImageData
   // Should be in level set mode
   assert(m_LevelSetDriver);
 
+  // Enter a thread-safe section
+  m_LevelSetPipelineMutexLock->Lock();
+
   // Delete the level set driver and all the problems that go along with it
   delete m_LevelSetDriver; m_LevelSetDriver = NULL;
+
+  // Leave a thread-safe section
+  m_LevelSetPipelineMutexLock->Unlock();
+
+  // Fire the update event
+  this->InvokeEvent(LevelSetImageChangeEvent());
 }
 
 void 
@@ -503,10 +502,99 @@ SNAPImageData
   return m_LevelSetDriver->GetCurrentState();
 }
 
-SNAPLevelSetFunction<SpeedImageWrapper::ImageType> *
+SNAPLevelSetDriver<3>::LevelSetFunctionType *
 SNAPImageData
 ::GetLevelSetFunction()
 {
   return m_LevelSetDriver->GetLevelSetFunction();
 }
 
+void
+SNAPImageData
+::InitializeToROI(GenericImageData *source,
+                  const SNAPSegmentationROISettings &roi,
+                  itk::Command *progressCommand)
+{
+  // Get the source main wrapper
+  ImageWrapperBase *srcMain = source->GetMain();
+
+  // Extract the ROI into a generic type
+  SmartPtr<ImageWrapperBase> roiMain = srcMain->ExtractROI(roi, progressCommand);
+
+  // Assign the new wrapper to the target
+  this->SetMainImageInternal(roiMain);
+
+  // Copy metadata
+  this->CopyLayerMetadata(this->GetMain(), source->GetMain());
+
+  // Repeat all of this for the overlays
+  for(LayerIterator lit = source->GetLayers(OVERLAY_ROLE);
+      !lit.IsAtEnd(); ++lit)
+    {
+    // Do the same for all the anatomic wrappers
+    SmartPtr<ImageWrapperBase> roiOvl =
+        lit.GetLayer()->ExtractROI(roi, progressCommand);
+
+    // Add the overlay
+    this->AddOverlayInternal(roiOvl);
+
+    // Copy metadata
+    this->CopyLayerMetadata(this->GetLastOverlay(), lit.GetLayer());
+    }
+}
+
+void SNAPImageData::CopyLayerMetadata(
+    ImageWrapperBase *target, ImageWrapperBase *source)
+{
+  // Nickname
+  target->SetDefaultNickname(source->GetNickname());
+
+  // This is a little bit of overhead, but not enough to be a big deal:
+  // we just save the display mapping to a Registry and then restore it
+  // in the target wrapper.
+  Registry folder;
+  source->GetDisplayMapping()->Save(folder);
+  target->GetDisplayMapping()->Restore(folder);
+
+  // Threshold settings. These should be copied for each scalar component
+  if(source->IsScalar())
+    {
+    target->SetUserData("ThresholdSettings", source->GetUserData("ThresholdSettings"));
+    }
+  else
+    {
+    // Copy threshold settings for all the scalar components
+    VectorImageWrapperBase *v_source = dynamic_cast<VectorImageWrapperBase *>(source);
+    VectorImageWrapperBase *v_target = dynamic_cast<VectorImageWrapperBase *>(target);
+
+    for(ScalarRepresentationIterator it(v_source); !it.IsAtEnd(); ++it)
+      {
+      ImageWrapperBase *c_source = v_source->GetScalarRepresentation(it);
+      ImageWrapperBase *c_target = v_target->GetScalarRepresentation(it);
+      c_target->SetUserData("ThresholdSettings", c_source->GetUserData("ThresholdSettings"));
+      }
+    }
+
+  // TODO: alpha, stickiness?
+}
+
+
+void SNAPImageData::UnloadAll()
+{
+  // Unload all the data
+  this->UnloadOverlays();
+  this->UnloadMainImage();
+
+  // We need to unload all the SNAP layers
+  while(this->m_Wrappers[SNAP_ROLE].size())
+    PopBackImageWrapper(SNAP_ROLE);
+  m_SpeedWrapper = NULL;
+  m_SnakeWrapper = NULL;
+
+  InvokeEvent(LayerChangeEvent());
+}
+
+
+
+
+
diff --git a/Logic/Framework/SNAPImageData.h b/Logic/Framework/SNAPImageData.h
index 6dd0455..b1ea91b 100644
--- a/Logic/Framework/SNAPImageData.h
+++ b/Logic/Framework/SNAPImageData.h
@@ -38,24 +38,27 @@
 #include "SNAPCommon.h"
 #include "IRISException.h"
 
-#include "GreyImageWrapper.h"
 #include "GlobalState.h"
 #include "ColorLabel.h"
 #include "ImageCoordinateGeometry.h"
 
 #include "IRISImageData.h"
 #include "SnakeParameters.h"
-#include "SpeedImageWrapper.h"
-#include "LevelSetImageWrapper.h"
 
-
-#include "EdgePreprocessingSettings.h"
-#include "ThresholdSettings.h"
+#include "SNAPLevelSetDriver.h"
 
 #include <vector>
 
 #include "SNAPLevelSetFunction.h"
-template <unsigned int VDimension> class SNAPLevelSetDriver;
+#include "itkImageAdaptor.h"
+
+namespace itk {
+  class Command;
+  class FastMutexLock;
+}
+
+class SNAPSegmentationROISettings;
+
 
 /**
  * \class SNAPImageData
@@ -68,29 +71,33 @@ template <unsigned int VDimension> class SNAPLevelSetDriver;
 class SNAPImageData : public GenericImageData 
 {
 public:
+  irisITKObjectMacro(SNAPImageData, GenericImageData)
+
+  // This class fires LevelSetImageChangeEvent
+  FIRES(LevelSetImageChangeEvent)
 
   // The type of the internal level set image
-  typedef itk::OrientedImage<float,3> FloatImageType;
-  typedef FloatImageType LevelSetImageType;
+  typedef itk::Image<float,3>                                   FloatImageType;
+  typedef Superclass::AnatomicImageType                      AnatomicImageType;
+  typedef SpeedImageWrapper::ImageType                          SpeedImageType;
+  typedef LevelSetImageWrapper::ImageType                    LevelSetImageType;
 
-  SNAPImageData(IRISApplication *m_Parent);
-  ~SNAPImageData();
+  /** Initialize to an ROI from another image data object */
+  void InitializeToROI(GenericImageData *source,
+                       const SNAPSegmentationROISettings &roi,
+                       itk::Command *progressCommand);
+
+  /**
+    Unload all images in the SNAP image data, releasing memory and returning
+    this object to initial state.
+    */
+  void UnloadAll();
 
   /** 
    * Get the preprocessed (speed) image wrapper
    */
   SpeedImageWrapper* GetSpeed();
 
-  /** A high level method to perform edge preprocessing on the grey image and
-   * store the result in the speed image wrapper */
-  void DoEdgePreprocessing(
-    const EdgePreprocessingSettings &settings,itk::Command *progressCallback = 0);  
-
-  /** A high level method to perform in-out preprocessing on the grey image and
-   * store the result in the speed image wrapper */
-  void DoInOutPreprocessing(
-    const ThresholdSettings &settings,itk::Command *progressCallback = 0);
-
   /**
    * Initialize the Speed image wrapper to blank data
    */
@@ -100,7 +107,7 @@ public:
    * Clear the preprocessed (speed) image (discard data, etc)
    */
   void ClearSpeed()
-    { m_SpeedWrapper.Reset(); }
+    { m_SpeedWrapper->Reset(); }
 
   /**
    * Check the preprocessed image for validity
@@ -114,7 +121,7 @@ public:
    * Clear the current snake (discard data, etc)
    */
   void ClearSnake()
-    { m_SnakeWrapper.Reset(); }
+    { m_SnakeWrapper->Reset(); }
 
   /**
    * Check the current snake for validity
@@ -159,6 +166,9 @@ public:
   /** Revert the segmentation to the beginning */
   void RestartSegmentation();
 
+  /** Check for convergence */
+  bool IsEvolutionConverged();
+
   /** Update the segmentation parameters, can be done either from the 
    * segmentation pipeline callback or on the fly.  This method is smart enough 
    * to reinitialize the level set driver if the Solver parameter changes */
@@ -191,9 +201,23 @@ public:
 
   /** This method is public for testing purposes.  It will give a pointer to 
    * the level set function used internally for segmentation */
-  SNAPLevelSetFunction<SpeedImageWrapper::ImageType> *GetLevelSetFunction();
+  SNAPLevelSetDriver<3>::LevelSetFunctionType *GetLevelSetFunction();
+
+  /**
+   * SNAPImageData provides a mutex lock that prevents multiple threads from
+   * causing the level set pipeline to update at once. In particular this
+   * can happen if the meshes are being generated from the level set data
+   * in a background thread
+   */
+  irisGetMacro(LevelSetPipelineMutexLock, itk::FastMutexLock *)
+
   
-private:
+protected:
+
+  SNAPImageData();
+  ~SNAPImageData();
+
+
 
   /** A functor for inverting an image */
   class InvertFunctor {
@@ -202,6 +226,11 @@ private:
       { return input == 0 ? 1 : 0; }
   };
 
+  /** Copy nickname, settings, and other such junk from IRIS to SNAP during
+   * initialization */
+  void CopyLayerMetadata(ImageWrapperBase *target, ImageWrapperBase *source);
+
+
   /** Initialize the driver used to control the snake.  This driver is used to
    * run the snake several iterations at a time, without resetting the filter
    * between iteration blocks.  After executing each block of iterations, the
@@ -226,25 +255,12 @@ private:
   /** A callback made after an update in the segmentation pipeline */
   CommandPointer m_SegmentationUpdateCallback;
 
-  /** Get the snake initialization image */
-  LevelSetImageWrapper* GetSnakeInitialization();
-
-  /** Clear the snake initialization image (discard data, etc) */
-  void ClearSnakeInitialization()
-    { m_SnakeInitializationWrapper.Reset(); }
-
-  /** Check the snake initialization image for validity */
-  bool IsSnakeInitializationLoaded();
-
   // Speed image adata
-  SpeedImageWrapper m_SpeedWrapper;
+  SmartPtr<SpeedImageWrapper> m_SpeedWrapper;
 
   // Wrapper around the level set image
-  LevelSetImageWrapper m_SnakeWrapper;
+  SmartPtr<LevelSetImageWrapper> m_SnakeWrapper;
   
-  // Snake initialization data (initial distance transform
-  LevelSetImageWrapper m_SnakeInitializationWrapper;
-
   // Snake driver
   SNAPLevelSetDriver<3> *m_LevelSetDriver;
 
@@ -256,7 +272,7 @@ private:
 
   // Typedefs for defining the advection image that can be loaded externally
   typedef itk::FixedArray<float, 3> VectorType;
-  typedef itk::OrientedImage< VectorType, 3> VectorImageType;
+  typedef itk::Image< VectorType, 3> VectorImageType;
   typedef itk::SmartPointer<VectorImageType> VectorImagePointer;
 
   // The advection image
@@ -264,9 +280,16 @@ private:
 
   // The color label that is used for this segmentation
   ColorLabel m_ColorLabel;
+
+  // SNAPImageData provides a mutex lock that prevents multiple threads from
+  // causing the level set pipeline to update at once.
+  SmartPtr<itk::FastMutexLock> m_LevelSetPipelineMutexLock;
 };
 
 
 
 
+
+
+
 #endif
diff --git a/Logic/Framework/UndoDataManager.h b/Logic/Framework/UndoDataManager.h
index 1693ebf..8652e8f 100644
--- a/Logic/Framework/UndoDataManager.h
+++ b/Logic/Framework/UndoDataManager.h
@@ -95,6 +95,14 @@ public:
       unsigned long GetUniqueID() const
         { return m_UniqueID; }
 
+      Delta & operator = (const Delta &other)
+      {
+        m_Array = other.m_Array;
+        m_CurrentLength = other.m_CurrentLength;
+        m_LastValue = other.m_LastValue;
+        return *this;
+      }
+
     protected:
       typedef std::pair<size_t, TPixel> RLEPair;
       typedef std::vector<RLEPair> RLEArray;
@@ -118,6 +126,11 @@ public:
   bool IsRedoPossible();
   Delta *GetDeltaForRedo();
 
+  Delta *GetCumulativeDelta()
+    { return m_CumulativeDelta; }
+
+  void SetCumulativeDelta(Delta *);
+
   size_t GetNumberOfDeltas()
     { return m_DeltaList.size(); }
 
@@ -138,4 +151,6 @@ private:
   DList m_DeltaList;
   DIterator m_Position;
   size_t m_TotalSize, m_MinDeltas, m_MaxTotalSize;
+
+  Delta *m_CumulativeDelta;
 };
diff --git a/Logic/Framework/UndoDataManager.txx b/Logic/Framework/UndoDataManager.txx
index ad4cbfd..24bf20a 100644
--- a/Logic/Framework/UndoDataManager.txx
+++ b/Logic/Framework/UndoDataManager.txx
@@ -45,6 +45,7 @@ UndoDataManager<TPixel>
   this->m_MaxTotalSize = nMaxTotalSize;
   this->m_TotalSize = 0;
   m_Position = m_DeltaList.begin();
+  m_CumulativeDelta = NULL;
 }
 
 template<typename TPixel>
@@ -156,3 +157,14 @@ UndoDataManager<TPixel>
     }
   return sd;
 }
+
+
+template<typename TPixel>
+void
+UndoDataManager<TPixel>
+::SetCumulativeDelta(Delta *delta)
+{
+  if(m_CumulativeDelta)
+    delete m_CumulativeDelta;
+  m_CumulativeDelta = delta;
+}
diff --git a/Logic/ImageWrapper/CPUImageToGPUImageFilter.h b/Logic/ImageWrapper/CPUImageToGPUImageFilter.h
new file mode 100755
index 0000000..4981299
--- /dev/null
+++ b/Logic/ImageWrapper/CPUImageToGPUImageFilter.h
@@ -0,0 +1,106 @@
+/*=========================================================================
+ *
+ *  Copyright Insight Software Consortium
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0.txt
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *=========================================================================*/
+#ifndef __CPUImageToGPUImageFilter_h
+#define __CPUImageToGPUImageFilter_h
+
+#include "itkGPUImage.h"
+#include "itkGPUKernelManager.h"
+#include "itkImageSource.h"
+
+/** \class CPUImageToGPUImageFilter
+ *
+ * \brief class to abstract the behaviour of the GPU filters.
+ *
+ * CPUImageToGPUImageFilter is the GPU version of ImageToImageFilter.
+ * This class can accept both CPU and GPU image as input and output,
+ * and apply filter accordingly. If GPU is available for use, then
+ * GPUGenerateData() is called. Otherwise, GenerateData() in the
+ * parent class (i.e., ImageToImageFilter) will be called.
+ *
+ * \ingroup ITKGPUCommon
+ */
+template< class TGPUOutputImage >
+class CPUImageToGPUImageFilter : public itk::ImageSource< TGPUOutputImage >
+{
+public:
+  /** Standard class typedefs. */
+  typedef CPUImageToGPUImageFilter               Self;
+  typedef itk::ImageSource< TGPUOutputImage >         Superclass;
+  typedef itk::SmartPointer< Self >                   Pointer;
+  typedef itk::SmartPointer< const Self >             ConstPointer;
+
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(CPUImageToGPUImageFilter, TParentImageFilter);
+
+  /** Superclass typedefs. */
+  typedef typename Superclass::DataObjectIdentifierType DataObjectIdentifierType;
+  typedef typename Superclass::OutputImageRegionType    OutputImageRegionType;
+  typedef typename Superclass::OutputImagePixelType     OutputImagePixelType;
+
+  /** Some convenient typedefs. */
+  typedef TGPUOutputImage                       OutputImageType;
+  typedef typename TGPUOutputImage::Pointer     OutputImagePointer;
+
+  typedef typename TGPUOutputImage::Superclass  InputImageType;
+  typedef typename InputImageType::Pointer      InputImagePointer;
+  typedef typename InputImageType::ConstPointer InputImageConstPointer;
+  typedef typename InputImageType::RegionType   InputImageRegionType;
+  typedef typename InputImageType::PixelType    InputImagePixelType;
+
+  /** ImageDimension constants */
+  itkStaticConstMacro(InputImageDimension, unsigned int, InputImageType::ImageDimension);
+  itkStaticConstMacro(OutputImageDimension, unsigned int, OutputImageType::ImageDimension);
+
+  /** Set/Get the image input of this process object.  */
+  using Superclass::SetInput;
+  virtual void SetInput(const InputImageType *image);
+
+  void GenerateData();
+
+  virtual void GraftOutput(itk::DataObject *output);
+
+  virtual void GraftOutput(const DataObjectIdentifierType & key, itk::DataObject *output);
+
+protected:
+  CPUImageToGPUImageFilter();
+  ~CPUImageToGPUImageFilter();
+
+  virtual void PrintSelf(std::ostream & os, itk::Indent indent) const;
+
+  //virtual void GPUGenerateData() {  }
+
+  // GPU kernel manager
+  typename itk::GPUKernelManager::Pointer m_GPUKernelManager;
+
+  // GPU kernel handle - kernel should be defined in specific filter (not in the
+  // base class)
+  //int m_KernelHandle;
+
+private:
+  CPUImageToGPUImageFilter(const Self &); //purposely not implemented
+  void operator=(const Self &);        //purposely not implemented
+
+};
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "CPUImageToGPUImageFilter.hxx"
+#endif
+
+#endif
diff --git a/Logic/ImageWrapper/CPUImageToGPUImageFilter.hxx b/Logic/ImageWrapper/CPUImageToGPUImageFilter.hxx
new file mode 100755
index 0000000..0e9a799
--- /dev/null
+++ b/Logic/ImageWrapper/CPUImageToGPUImageFilter.hxx
@@ -0,0 +1,96 @@
+/*=========================================================================
+ *
+ *  Copyright Insight Software Consortium
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0.txt
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *=========================================================================*/
+#ifndef __CPUImageToGPUImageFilter_hxx
+#define __CPUImageToGPUImageFilter_hxx
+
+#include "CPUImageToGPUImageFilter.h"
+#include "itkImageAlgorithm.h"
+
+template< class TGPUOutputImage >
+CPUImageToGPUImageFilter< TGPUOutputImage >::CPUImageToGPUImageFilter()
+{
+  m_GPUKernelManager = itk::GPUKernelManager::New();
+}
+
+template< class TGPUOutputImage >
+CPUImageToGPUImageFilter< TGPUOutputImage >::~CPUImageToGPUImageFilter()
+{
+}
+
+template< class TGPUOutputImage >
+void
+CPUImageToGPUImageFilter< TGPUOutputImage >::PrintSelf(std::ostream & os,
+  itk::Indent indent) const
+{
+  Superclass::PrintSelf(os, indent);
+  os << indent << "CPUImageToGPUImageFilter " << std::endl;
+}
+
+/**
+ *
+ */
+template< class TGPUOutputImage >
+void
+CPUImageToGPUImageFilter< TGPUOutputImage >
+::SetInput(const InputImageType *input)
+{
+  // Process object is not const-correct so the const_cast is required here
+  this->ProcessObject::SetNthInput( 0,
+                                    const_cast< InputImageType * >( input ) );
+}
+
+template< class TGPUOutputImage >
+void
+CPUImageToGPUImageFilter< TGPUOutputImage >::GenerateData()
+{
+  OutputImagePointer output =  dynamic_cast< OutputImageType * >( this->GetOutput() );
+  InputImagePointer input = dynamic_cast< InputImageType * >( this->GetPrimaryInput() );
+
+  //output = OutputImageType::New();
+  output->CopyInformation( input );
+
+  //output->SetLargestPossibleRegion( input->GetLargestPossibleRegion() );
+  //output->SetRequestedRegion( input->GetRequestedRegion() );
+  //output->SetBufferedRegion( input->GetBufferedRegion() );
+  //output->Allocate();
+  //output->OutputImageType::Superclass::Graft(input);
+
+  output->SetBufferedRegion( output->GetRequestedRegion() );
+  output->Allocate();
+  itk::ImageAlgorithm::Copy(input.GetPointer(), output.GetPointer(), output->GetBufferedRegion(), output->GetBufferedRegion());
+}
+
+template< class TGPUOutputImage >
+void
+CPUImageToGPUImageFilter< TGPUOutputImage >::GraftOutput(itk::DataObject *output)
+{
+  OutputImagePointer otPtr = dynamic_cast< OutputImageType * >( this->GetOutput() );
+
+  otPtr->Graft( output );
+}
+
+template< class TGPUOutputImage >
+void
+CPUImageToGPUImageFilter< TGPUOutputImage >::GraftOutput(const DataObjectIdentifierType & key, itk::DataObject *output)
+{
+  OutputImagePointer otPtr = dynamic_cast< OutputImageType * >( this->ProcessObject::GetOutput(key) );
+
+  otPtr->Graft( output );
+}
+
+#endif
diff --git a/Logic/ImageWrapper/CommonRepresentationPolicy.cxx b/Logic/ImageWrapper/CommonRepresentationPolicy.cxx
new file mode 100644
index 0000000..9e35e6a
--- /dev/null
+++ b/Logic/ImageWrapper/CommonRepresentationPolicy.cxx
@@ -0,0 +1,101 @@
+#include "CommonRepresentationPolicy.h"
+#include "ImageWrapperTraits.h"
+#include "itkCastImageFilter.h"
+#include "itkVectorImageToImageAdaptor.h"
+
+template<class TOutputPixel, class TWrapperTraits>
+InPlaceScalarImageWrapperCommonRepresentation<TOutputPixel, TWrapperTraits>
+::InPlaceScalarImageWrapperCommonRepresentation()
+{
+  m_Image = NULL;
+}
+
+template<class TOutputPixel, class TWrapperTraits>
+InPlaceScalarImageWrapperCommonRepresentation<TOutputPixel, TWrapperTraits>
+::~InPlaceScalarImageWrapperCommonRepresentation()
+{
+  m_Image = NULL;
+}
+
+template<class TOutputPixel, class TWrapperTraits>
+typename InPlaceScalarImageWrapperCommonRepresentation<TOutputPixel, TWrapperTraits>::OutputImageType *
+InPlaceScalarImageWrapperCommonRepresentation<TOutputPixel, TWrapperTraits>
+::GetOutput(ScalarImageWrapperBase::ExportChannel channel)
+{
+  return m_Image;
+}
+
+template<class TOutputPixel, class TWrapperTraits>
+void
+InPlaceScalarImageWrapperCommonRepresentation<TOutputPixel, TWrapperTraits>
+::UpdateInputImage(InputImageType *image)
+{
+  m_Image = image;
+}
+
+
+template<class TOutputPixel, class TWrapperTraits>
+CastingScalarImageWrapperCommonRepresentation<TOutputPixel, TWrapperTraits>
+::CastingScalarImageWrapperCommonRepresentation()
+{
+  // Allocate the filters
+  for(int i = 0; i < ScalarImageWrapperBase::CHANNEL_COUNT; i++)
+    {
+    CastFilterPointer caster = CastFilterType::New();
+    m_CastFilter.push_back(caster);
+    }
+}
+
+template<class TOutputPixel, class TWrapperTraits>
+CastingScalarImageWrapperCommonRepresentation<TOutputPixel, TWrapperTraits>
+::~CastingScalarImageWrapperCommonRepresentation()
+{
+}
+
+template<class TOutputPixel, class TWrapperTraits>
+void
+CastingScalarImageWrapperCommonRepresentation<TOutputPixel, TWrapperTraits>
+::UpdateInputImage(InputImageType *image)
+{
+  // Update the inputs
+  for(int i = 0; i < ScalarImageWrapperBase::CHANNEL_COUNT; i++)
+    m_CastFilter[i]->SetInput(image);
+}
+
+template<class TOutputPixel, class TWrapperTraits>
+typename CastingScalarImageWrapperCommonRepresentation<TOutputPixel, TWrapperTraits>::OutputImageType *
+CastingScalarImageWrapperCommonRepresentation<TOutputPixel, TWrapperTraits>
+::GetOutput(ScalarImageWrapperBase::ExportChannel channel)
+{
+  return m_CastFilter[channel]->GetOutput();
+}
+
+template class CastingScalarImageWrapperCommonRepresentation<
+    GreyType, GreyComponentImageWrapperTraits >;
+
+template class CastingScalarImageWrapperCommonRepresentation<
+    GreyType, GreyVectorMagnitudeImageWrapperTraits >;
+
+template class CastingScalarImageWrapperCommonRepresentation<
+    GreyType, GreyVectorMaxImageWrapperTraits >;
+
+template class CastingScalarImageWrapperCommonRepresentation<
+    GreyType, GreyVectorMeanImageWrapperTraits >;
+
+template class InPlaceScalarImageWrapperCommonRepresentation<
+    GreyType, SpeedImageWrapperTraits >;
+
+template class InPlaceScalarImageWrapperCommonRepresentation<
+    GreyType, GreyAnatomicScalarImageWrapperTraits >;
+
+template class CastingScalarImageWrapperCommonRepresentation<
+    GreyType, LevelSetImageWrapperTraits >;
+
+template class CastingScalarImageWrapperCommonRepresentation<
+    GreyType, GreyAnatomicScalarImageWrapperTraits >;
+
+
+
+
+
+
diff --git a/Logic/ImageWrapper/CommonRepresentationPolicy.h b/Logic/ImageWrapper/CommonRepresentationPolicy.h
new file mode 100644
index 0000000..b479ddf
--- /dev/null
+++ b/Logic/ImageWrapper/CommonRepresentationPolicy.h
@@ -0,0 +1,107 @@
+#ifndef SCALARIMAGEWRAPPERCOMMONREPRESENTATION_H
+#define SCALARIMAGEWRAPPERCOMMONREPRESENTATION_H
+
+#include "ImageWrapperBase.h"
+
+namespace itk
+{
+template<class TIn, class TOut> class CastImageFilter;
+}
+
+/**
+ * The parent class for the hierarchy of ScalarImageWrapper policy classes
+ * that allow the internal image in the ScalarImageWrapper to be cast to
+ * an itk::Image in some common format. The resust of casting to a common
+ * format can be used in downstream pipelines without needing to know what
+ * the format of the internal image was
+ */
+template <class TOutputPixel>
+class AbstractScalarImageWrapperCommonRepresentation
+{
+public:
+  typedef itk::Image<TOutputPixel, 3> OutputImageType;
+
+  /**
+   * Export the image to a common format
+   * @see ScalarImageWrapperBase::GetCommonFormatImage
+   */
+  virtual OutputImageType *GetOutput(ScalarImageWrapperBase::ExportChannel channel) = 0;
+};
+
+/**
+ * This implementation of the policy is for use by ScalarImageWrappers whose
+ * internal image is a plain itk::Image of TOutputPixel type. No casting takes
+ * place in that case, and the output image simply shares the pixel container
+ * with the image stored in the ScalarImageWrapper.
+ */
+template <class TOutputPixel, class TWrapperTraits>
+class InPlaceScalarImageWrapperCommonRepresentation
+    : public AbstractScalarImageWrapperCommonRepresentation<TOutputPixel>
+{
+public:
+  typedef AbstractScalarImageWrapperCommonRepresentation<TOutputPixel> Superclass;
+  typedef typename Superclass::OutputImageType                 OutputImageType;
+  typedef typename TWrapperTraits::ImageType                    InputImageType;
+
+  InPlaceScalarImageWrapperCommonRepresentation();
+  ~InPlaceScalarImageWrapperCommonRepresentation();
+
+  OutputImageType *GetOutput(ScalarImageWrapperBase::ExportChannel channel);
+
+  void UpdateInputImage(InputImageType *image);
+
+private:
+  SmartPtr<OutputImageType> m_Image;
+};
+
+/**
+ * This implementation of the policy uses an itk cast filter. This is used when
+ * the image stored in the ScalarImageWrapper does not have the type needed for
+ * export.
+ */
+template <class TOutputPixel, class TWrapperTraits>
+class CastingScalarImageWrapperCommonRepresentation
+    : public AbstractScalarImageWrapperCommonRepresentation<TOutputPixel>
+{
+public:
+  typedef AbstractScalarImageWrapperCommonRepresentation<TOutputPixel> Superclass;
+  typedef typename Superclass::OutputImageType                 OutputImageType;
+  typedef typename TWrapperTraits::ImageType                    InputImageType;
+
+  CastingScalarImageWrapperCommonRepresentation();
+  ~CastingScalarImageWrapperCommonRepresentation();
+
+  OutputImageType *GetOutput(ScalarImageWrapperBase::ExportChannel channel);
+
+  void UpdateInputImage(InputImageType *image);
+
+private:
+  typedef itk::CastImageFilter<InputImageType, OutputImageType> CastFilterType;
+  typedef SmartPtr<CastFilterType>                           CastFilterPointer;
+
+  // Array of casting filters
+  std::vector<CastFilterPointer> m_CastFilter;
+};
+
+/**
+ * A null implementation of the above policy, intended for classes that do not
+ * need to be cast to any output type. The representation always returns NULL
+ * in GetOutput().
+ */
+template <class TOutputPixel, class TWrapperTraits>
+class NullScalarImageWrapperCommonRepresentation
+    : public AbstractScalarImageWrapperCommonRepresentation<TOutputPixel>
+{
+public:
+  typedef AbstractScalarImageWrapperCommonRepresentation<TOutputPixel> Superclass;
+  typedef typename Superclass::OutputImageType                 OutputImageType;
+  typedef typename TWrapperTraits::ImageType                    InputImageType;
+
+  OutputImageType *GetOutput(ScalarImageWrapperBase::ExportChannel channel)
+    { return NULL; }
+
+  void UpdateInputImage(InputImageType *) {};
+
+};
+
+#endif // SCALARIMAGEWRAPPERCOMMONREPRESENTATION_H
diff --git a/Logic/ImageWrapper/DisplayMappingPolicy.cxx b/Logic/ImageWrapper/DisplayMappingPolicy.cxx
new file mode 100644
index 0000000..fed5a4e
--- /dev/null
+++ b/Logic/ImageWrapper/DisplayMappingPolicy.cxx
@@ -0,0 +1,975 @@
+#include "DisplayMappingPolicy.h"
+#include "ImageWrapperTraits.h"
+#include "ColorLabelTable.h"
+#include "LabelToRGBAFilter.h"
+#include "IntensityCurveVTK.h"
+#include "IntensityToColorLookupTableImageFilter.h"
+#include "LookupTableIntensityMappingFilter.h"
+#include "RGBALookupTableIntensityMappingFilter.h"
+#include "ColorMap.h"
+#include "ScalarImageHistogram.h"
+#include "itkMinimumMaximumImageFilter.h"
+#include "itkVectorImageToImageAdaptor.h"
+#include "IRISException.h"
+#include "itkCommand.h"
+#include "itkUnaryFunctorImageFilter.h"
+#include "InputSelectionImageFilter.h"
+#include "Rebroadcaster.h"
+
+
+/* ===============================================================
+    ColorLabelTableDisplayMappingPolicy implementation
+   =============================================================== */
+
+
+template<class TWrapperTraits>
+ColorLabelTableDisplayMappingPolicy<TWrapperTraits>
+::ColorLabelTableDisplayMappingPolicy()
+{
+  m_Wrapper = NULL;
+}
+
+template<class TWrapperTraits>
+ColorLabelTableDisplayMappingPolicy<TWrapperTraits>
+::~ColorLabelTableDisplayMappingPolicy()
+{
+
+}
+
+template<class TWrapperTraits>
+void
+ColorLabelTableDisplayMappingPolicy<TWrapperTraits>
+::Initialize(WrapperType *wrapper)
+{
+  // Initialize the wrapper
+  m_Wrapper = wrapper;
+
+  // Initialize the filters
+  for(unsigned int i=0; i<3; i++)
+    {
+    m_RGBAFilter[i] = RGBAFilterType::New();
+    m_RGBAFilter[i]->SetInput(wrapper->GetSlice(i));
+    m_RGBAFilter[i]->SetColorTable(NULL);
+    }
+
+}
+
+template <class TWrapperTraits>
+void
+ColorLabelTableDisplayMappingPolicy<TWrapperTraits>
+::UpdateImagePointer(ImageType *image)
+{
+  // Nothing to do here, since we are connected to the slices?
+}
+
+template<class TWrapperTraits>
+typename ColorLabelTableDisplayMappingPolicy<TWrapperTraits>::DisplaySlicePointer
+ColorLabelTableDisplayMappingPolicy<TWrapperTraits>
+::GetDisplaySlice(unsigned int slice)
+{
+  return m_RGBAFilter[slice]->GetOutput();
+}
+
+template<class TWrapperTraits>
+void
+ColorLabelTableDisplayMappingPolicy<TWrapperTraits>
+::SetLabelColorTable(ColorLabelTable *labels)
+{
+  // Set the new table
+  for(unsigned int i=0;i<3;i++)
+    m_RGBAFilter[i]->SetColorTable(labels);
+
+  // Propagate the events from to color label table to the wrapper
+  Rebroadcaster::Rebroadcast(labels, SegmentationLabelChangeEvent(),
+                             m_Wrapper, WrapperDisplayMappingChangeEvent());
+
+  Rebroadcaster::Rebroadcast(labels, SegmentationLabelConfigurationChangeEvent(),
+                             m_Wrapper, WrapperDisplayMappingChangeEvent());
+}
+
+template<class TWrapperTraits>
+ColorLabelTable *
+ColorLabelTableDisplayMappingPolicy<TWrapperTraits>
+::GetLabelColorTable() const
+{
+  return m_RGBAFilter[0]->GetColorTable();
+}
+
+
+/* ===============================================================
+    CachingCurveAndColorMapDisplayMappingPolicy implementation
+   =============================================================== */
+
+template<class TWrapperTraits>
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::CachingCurveAndColorMapDisplayMappingPolicy()
+{
+  m_Wrapper = NULL;
+}
+
+template<class TWrapperTraits>
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::~CachingCurveAndColorMapDisplayMappingPolicy()
+{
+
+}
+
+template<class TWrapperTraits>
+void
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::Initialize(WrapperType *wrapper)
+{
+  // Initialize the intensity curve
+  m_Wrapper = wrapper;
+
+  // Initialize the LUT filter
+  m_LookupTableFilter = LookupTableFilterType::New();
+
+  // Initialize the colormap
+  m_ColorMap = ColorMap::New();
+  m_ColorMap->SetToSystemPreset(
+        static_cast<ColorMap::SystemPreset>(TWrapperTraits::DefaultColorMap));
+  this->SetColorMap(m_ColorMap);
+
+  // Initialize the intensity curve
+  m_IntensityCurveVTK = IntensityCurveVTK::New();
+  m_IntensityCurveVTK->Initialize();
+  this->SetIntensityCurve(m_IntensityCurveVTK);
+
+  // Initialize the filters that apply the LUT
+  for(unsigned int i=0; i<3; i++)
+    {
+    m_IntensityFilter[i] = IntensityFilterType::New();
+    m_IntensityFilter[i]->SetLookupTable(m_LookupTableFilter->GetOutput());
+    }
+}
+
+template <class TWrapperTraits>
+void
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::UpdateImagePointer(ImageType *image)
+{
+  // Hook up the image to the filter
+  m_LookupTableFilter->SetInput(m_Wrapper->GetImage());
+
+  // Hook up the min/max filters
+  m_LookupTableFilter->SetImageMinInput(m_Wrapper->GetMinMaxFilter()->GetMinimumOutput());
+  m_LookupTableFilter->SetImageMaxInput(m_Wrapper->GetMinMaxFilter()->GetMaximumOutput());
+
+  for(unsigned int i=0; i<3; i++)
+    {
+    m_IntensityFilter[i]->SetInput(m_Wrapper->GetSlice(i));
+    m_IntensityFilter[i]->SetImageMinInput(m_Wrapper->GetMinMaxFilter()->GetMinimumOutput());
+    m_IntensityFilter[i]->SetImageMaxInput(m_Wrapper->GetMinMaxFilter()->GetMaximumOutput());
+    }
+}
+
+template<class TWrapperTraits>
+void
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::CopyDisplayPipeline(const Self *reference)
+{
+  // Copy the lookup table filter. Not sure we need to do this, or just set
+  // it to NULL.
+  m_LookupTableFilter = reference->m_LookupTableFilter;
+
+  // Configure the per-slice filters
+  for(unsigned int i=0; i<3; i++)
+    {
+    m_IntensityFilter[i]->SetLookupTable(m_LookupTableFilter->GetOutput());
+    m_IntensityFilter[i]->SetImageMinInput(m_LookupTableFilter->GetImageMinInput());
+    m_IntensityFilter[i]->SetImageMaxInput(m_LookupTableFilter->GetImageMaxInput());
+    }
+
+  // Copy the color map and the intensity curve
+  this->SetColorMap(reference->m_ColorMap);
+  this->SetIntensityCurve(reference->m_IntensityCurveVTK);
+}
+
+template<class TWrapperTraits>
+void
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::SetReferenceIntensityRange(ComponentObjectType *refMin, ComponentObjectType *refMax)
+{
+  m_LookupTableFilter->SetImageMinInput(refMin);
+  m_LookupTableFilter->SetImageMaxInput(refMax);
+}
+
+template<class TWrapperTraits>
+void
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::ClearReferenceIntensityRange()
+{
+  m_LookupTableFilter->SetImageMinInput(m_Wrapper->GetMinMaxFilter()->GetMinimumOutput());
+  m_LookupTableFilter->SetImageMaxInput(m_Wrapper->GetMinMaxFilter()->GetMaximumOutput());
+}
+
+template<class TWrapperTraits>
+void
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::DeepCopyIntensityMap(WrapperType *srcWrapper)
+{
+  Self *s = srcWrapper->GetDisplayMapping();
+  const IntensityCurveInterface *ici = s->m_IntensityCurveVTK;
+  m_IntensityCurveVTK->Initialize(ici->GetControlPointCount());
+  for(size_t i = 0; i < m_IntensityCurveVTK->GetControlPointCount(); i++)
+    {
+    float t, x;
+    ici->GetControlPoint(i, t, x);
+    m_IntensityCurveVTK->UpdateControlPoint(i, t, x);
+    }
+}
+
+template<class TWrapperTraits>
+Vector2d
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::GetNativeImageRangeForCurve()
+{
+  return Vector2d(m_Wrapper->GetImageMinNative(), m_Wrapper->GetImageMaxNative());
+}
+
+template<class TWrapperTraits>
+const ScalarImageHistogram *
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::GetHistogram(int nBins)
+{
+  return m_Wrapper->GetHistogram(nBins);
+}
+
+template<class TWrapperTraits>
+typename CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>::DisplaySlicePointer
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::GetDisplaySlice(unsigned int dim)
+{
+  return m_IntensityFilter[dim]->GetOutput();
+}
+
+template<class TWrapperTraits>
+ColorMap *
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::GetColorMap() const
+{
+  return m_ColorMap;
+}
+
+template<class TWrapperTraits>
+IntensityCurveInterface *
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::GetIntensityCurve() const
+{
+  return m_IntensityCurveVTK;
+}
+
+template<class TWrapperTraits>
+void
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::SetIntensityCurve(IntensityCurveInterface *curve)
+{
+  m_IntensityCurveVTK = static_cast<IntensityCurveVTK *>(curve);
+
+  // Connect the curve to the LUT filter
+  m_LookupTableFilter->SetIntensityCurve(m_IntensityCurveVTK);
+
+  // Connect modified events from the color map to appropriate events
+  // from the image wrapper
+  Rebroadcaster::Rebroadcast(m_IntensityCurveVTK, itk::ModifiedEvent(),
+                             m_Wrapper, WrapperDisplayMappingChangeEvent());
+}
+
+template<class TWrapperTraits>
+void
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::SetColorMap(ColorMap *map)
+{
+  m_ColorMap = map;
+
+  // Attach the color map to the LUT filter
+  m_LookupTableFilter->SetColorMap(m_ColorMap);
+
+  // Connect modified events from the color map to appropriate events
+  // from the image wrapper
+  Rebroadcaster::Rebroadcast(m_ColorMap, itk::ModifiedEvent(),
+                             m_Wrapper, WrapperDisplayMappingChangeEvent());
+}
+
+template<class TWrapperTraits>
+void
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::Save(Registry &reg)
+{
+  m_IntensityCurveVTK->SaveToRegistry(reg.Folder("Curve"));
+  m_ColorMap->SaveToRegistry(reg.Folder("ColorMap"));
+}
+
+template<class TWrapperTraits>
+void
+CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>
+::Restore(Registry &reg)
+{
+  m_IntensityCurveVTK->LoadFromRegistry(reg.Folder("Curve"));
+  m_ColorMap->LoadFromRegistry(reg.Folder("ColorMap"));
+}
+
+
+
+
+
+
+
+
+/* ===============================================================
+    AbstractContinuousImageDisplayMappingPolicy implementation
+   =============================================================== */
+
+void
+AbstractContinuousImageDisplayMappingPolicy
+::AutoFitContrast()
+{
+  // Get the histogram with the current number of bins
+  const ScalarImageHistogram *hist = this->GetHistogram(0);
+
+  // Integrate the histogram until reaching 0.1%
+  double imin = hist->GetBinMin(0);
+  double ilow = imin;
+  size_t accum = 0;
+  size_t accum_goal = hist->GetTotalSamples() / 1000;
+  for(size_t i = 0; i < hist->GetSize(); i++)
+    {
+    if(accum + hist->GetFrequency(i) < accum_goal)
+      {
+      accum += hist->GetFrequency(i);
+      ilow = hist->GetBinMax(i);
+      }
+    else break;
+    }
+
+  // Same, but from above
+  double imax = hist->GetBinMax(hist->GetSize() - 1);
+  double ihigh = imax;
+  accum = 0;
+  for(int i = (int) hist->GetSize() - 1; i >= 0; i--)
+    {
+    if(accum + hist->GetFrequency(i) < accum_goal)
+      {
+      accum += hist->GetFrequency(i);
+      ihigh = hist->GetBinMin(i);
+      }
+    else break;
+    }
+
+  // If for some reason the window is off, we set everything to max/min
+  if(ilow >= ihigh)
+    { ilow = imin; ihigh = imax; }
+
+  // Compute the unit coordinate values that correspond to min and max
+  Vector2d irange = this->GetNativeImageRangeForCurve();
+  double factor = 1.0 / (irange[1] - irange[0]);
+  double t0 = factor * (ilow - irange[0]);
+  double t1 = factor * (ihigh - irange[0]);
+
+  // Set the window and level
+  this->GetIntensityCurve()->ScaleControlPointsToWindow((float) t0, (float) t1);
+}
+
+bool AbstractContinuousImageDisplayMappingPolicy::IsContrastInDefaultState()
+{
+  return this->GetIntensityCurve()->IsInDefaultState();
+}
+
+/* ===============================================================
+    LinearColorMapDisplayMappingPolicy implementation
+   =============================================================== */
+
+template <class TWrapperTraits>
+LinearColorMapDisplayMappingPolicy<TWrapperTraits>
+::LinearColorMapDisplayMappingPolicy()
+{
+  m_ColorMap = ColorMap::New();
+  m_ColorMap->SetToSystemPreset(
+        static_cast<ColorMap::SystemPreset>(TWrapperTraits::DefaultColorMap));
+
+  m_Wrapper = NULL;
+
+  // Initialize the functor - based on the hard-coded range of the
+  // intensity values encoded in the traits
+  float imin, imax;
+  TWrapperTraits::GetFixedIntensityRange(imin, imax);
+  m_Functor.m_Shift = imin;
+  m_Functor.m_Scale = 1.0 / (imax - imin);
+  m_Functor.m_ColorMap = m_ColorMap;
+
+  for(int i = 0; i < 3; i++)
+    {
+    m_Filter[i] = IntensityFilterType::New();
+    m_Filter[i]->SetFunctor(m_Functor);
+
+    // The color map is added as a 'named' input of the filter. This ensures
+    // that as the colormap is modified, the filter will be updated
+    m_Filter[i]->SetInput("colormap", m_ColorMap);
+    }
+
+}
+
+template <class TWrapperTraits>
+LinearColorMapDisplayMappingPolicy<TWrapperTraits>
+::~LinearColorMapDisplayMappingPolicy()
+{
+
+}
+
+
+template <class TWrapperTraits>
+void
+LinearColorMapDisplayMappingPolicy<TWrapperTraits>
+::Initialize(WrapperType *wrapper)
+{
+  m_Wrapper = wrapper;
+
+  for(int i = 0; i < 3; i++)
+    {
+    m_Filter[i]->SetInput(wrapper->GetSlice(i));
+    }
+
+  Rebroadcaster::Rebroadcast(m_ColorMap, itk::ModifiedEvent(),
+                             m_Wrapper, WrapperDisplayMappingChangeEvent());
+}
+
+template <class TWrapperTraits>
+void
+LinearColorMapDisplayMappingPolicy<TWrapperTraits>
+::UpdateImagePointer(ImageType *image)
+{
+  // Nothing to do here, since we are connected to the slices?
+}
+
+
+template <class TWrapperTraits>
+typename LinearColorMapDisplayMappingPolicy<TWrapperTraits>::DisplaySlicePointer
+LinearColorMapDisplayMappingPolicy<TWrapperTraits>
+::GetDisplaySlice(unsigned int slice)
+{
+  return m_Filter[slice]->GetOutput();
+}
+
+
+template <class TWrapperTraits>
+inline typename LinearColorMapDisplayMappingPolicy<TWrapperTraits>::DisplayPixelType
+LinearColorMapDisplayMappingPolicy<TWrapperTraits>::MappingFunctor
+::operator()(PixelType in)
+{
+  double v = (in - m_Shift) * m_Scale;
+  return m_ColorMap->MapIndexToRGBA(v);
+}
+
+template <class TWrapperTraits>
+bool
+LinearColorMapDisplayMappingPolicy<TWrapperTraits>::MappingFunctor
+::operator!=(const MappingFunctor &comp)
+{
+  return (comp.m_ColorMap != m_ColorMap)
+      || (comp.m_Shift != m_Shift)
+      || (comp.m_Scale != m_Scale);
+}
+
+
+
+template <class TWrapperTraits>
+void
+LinearColorMapDisplayMappingPolicy<TWrapperTraits>
+::Save(Registry &reg)
+{
+  m_ColorMap->SaveToRegistry(reg.Folder("ColorMap"));
+}
+
+template <class TWrapperTraits>
+void
+LinearColorMapDisplayMappingPolicy<TWrapperTraits>
+::Restore(Registry &reg)
+{
+  m_ColorMap->LoadFromRegistry(reg.Folder("ColorMap"));
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ===============================================================
+    MultiChannelDisplayMode implementation
+   =============================================================== */
+
+
+MultiChannelDisplayMode::MultiChannelDisplayMode()
+{
+  UseRGB = false;
+  SelectedScalarRep = SCALAR_REP_COMPONENT;
+  SelectedComponent = 0;
+}
+
+MultiChannelDisplayMode::MultiChannelDisplayMode(
+    bool use_rgb, ScalarRepresentation rep,
+    int comp)
+  : UseRGB(use_rgb), SelectedScalarRep(rep),
+    SelectedComponent(comp)
+{
+
+}
+
+MultiChannelDisplayMode::MultiChannelDisplayMode(int value)
+{
+  UseRGB = false;
+  SelectedScalarRep = SCALAR_REP_COMPONENT;
+  SelectedComponent = 0;
+}
+
+MultiChannelDisplayMode
+MultiChannelDisplayMode::DefaultForRGB()
+{
+  MultiChannelDisplayMode mode;
+  mode.UseRGB = true;
+  return mode;
+}
+
+void MultiChannelDisplayMode::Save(Registry &reg)
+{
+  reg["UseRGB"] << UseRGB;
+  reg["SelectedScalarRep"].PutEnum(GetScalarRepNames(), SelectedScalarRep);
+  reg["SelectedComponent"] << SelectedComponent;
+}
+
+MultiChannelDisplayMode
+MultiChannelDisplayMode::Load(Registry &reg)
+{
+  MultiChannelDisplayMode mode;
+  mode.UseRGB = reg["UseRGB"][mode.UseRGB];
+  mode.SelectedScalarRep = reg["SelectedScalarRep"].GetEnum(
+        GetScalarRepNames(), mode.SelectedScalarRep);
+  mode.SelectedComponent = reg["SelectedComponent"][mode.SelectedComponent];
+  return mode;
+}
+
+RegistryEnumMap<ScalarRepresentation> &
+MultiChannelDisplayMode::GetScalarRepNames()
+{
+  static RegistryEnumMap<ScalarRepresentation> namemap;
+  if(namemap.Size() == 0)
+    {
+    namemap.AddPair(SCALAR_REP_COMPONENT, "Component");
+    namemap.AddPair(SCALAR_REP_MAGNITUDE, "Magnitude");
+    namemap.AddPair(SCALAR_REP_MAX, "Maximum");
+    namemap.AddPair(SCALAR_REP_AVERAGE, "Average");
+    }
+  return namemap;
+}
+
+int MultiChannelDisplayMode::GetHashValue() const
+{
+  if(UseRGB)
+    return 10000;
+
+  if(SelectedScalarRep != SCALAR_REP_COMPONENT)
+    return SelectedScalarRep * 100;
+
+  return SelectedComponent;
+}
+
+bool operator < (const MultiChannelDisplayMode &a, const MultiChannelDisplayMode &b)
+{
+  return a.GetHashValue() < b.GetHashValue();
+}
+
+
+
+/* ===============================================================
+    MultiChannelDisplayMappingPolicy implementation
+   =============================================================== */
+
+template <class TWrapperTraits>
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::MultiChannelDisplayMappingPolicy()
+{
+  m_Animate = false;
+}
+
+template <class TWrapperTraits>
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::~MultiChannelDisplayMappingPolicy()
+{
+}
+
+
+
+
+template <class TWrapperTraits>
+void
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::Initialize(WrapperType *wrapper)
+{
+  // Save the wrapper pointer
+  m_Wrapper = wrapper;
+
+  // Modified events from the display policy fire as modification events
+  // for the wrapper
+  Rebroadcaster::Rebroadcast(this, itk::ModifiedEvent(),
+                             wrapper, WrapperMetadataChangeEvent());
+  Rebroadcaster::Rebroadcast(this, itk::ModifiedEvent(),
+                             wrapper, WrapperDisplayMappingChangeEvent());
+}
+
+template <class TWrapperTraits>
+void
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::UpdateImagePointer(ImageType *image)
+{
+  // Component wrappers
+  typedef typename WrapperType::ComponentWrapperType ComponentWrapperType;
+
+  // Initialize the display slice selectors
+  for(unsigned int i=0; i<3; i++)
+    m_DisplaySliceSelector[i] = DisplaySliceSelector::New();
+
+  // If the number of components is 3, set up the RGB pipeline
+  if(m_Wrapper->GetNumberOfComponents() == 3)
+    {
+    m_LUTGenerator = GenerateLUTFilter::New();
+    m_LUTGenerator->SetInput(m_Wrapper->GetImage());
+    m_LUTGenerator->SetImageMinInput(m_Wrapper->GetImageMinObject());
+    m_LUTGenerator->SetImageMaxInput(m_Wrapper->GetImageMaxObject());
+    m_LUTGenerator->SetIntensityCurve(
+          m_Wrapper->GetComponentWrapper(0)->GetIntensityCurve());
+
+    // Initialize the filters that apply the LUT
+    for(unsigned int i=0; i<3; i++)
+      {
+      m_RGBMapper[i] = ApplyLUTFilter::New();
+      m_RGBMapper[i]->SetLookupTable(m_LUTGenerator->GetOutput());
+
+      for(unsigned int j=0; j<3; j++)
+        {
+        ComponentWrapperType *comp = m_Wrapper->GetComponentWrapper(j);
+        m_RGBMapper[i]->SetInput(j, comp->GetSlice(i));
+        }
+
+      // Add this filter as the input to the selector
+      m_DisplaySliceSelector[i]->AddSelectableInput(
+            MultiChannelDisplayMode(true, SCALAR_REP_COMPONENT),
+            m_RGBMapper[i]->GetOutput());
+      }
+    }
+  else
+    {
+    m_LUTGenerator = NULL;
+    for(unsigned int j=0; j<3; j++)
+      m_RGBMapper[j] = NULL;
+    }
+
+  // Get the reference component wrapper whose properties will be shared
+  // with the other components
+  typedef typename WrapperType::ComponentWrapperType ComponentWrapper;
+  ComponentWrapper *first_comp = static_cast<ComponentWrapper *>(
+        m_Wrapper->GetComponentWrapper(0));
+
+  // The min/max for this LUT should be the global min/max, overriding
+  // the default, which is component-wise min/max.
+  first_comp->GetDisplayMapping()->SetReferenceIntensityRange(
+        m_Wrapper->GetImageMinObject(), m_Wrapper->GetImageMaxObject());
+
+  // Configure all the component wrappers display mappings
+  for(int j = 0; j < NUMBER_OF_SCALAR_REPS; j++)
+    {
+    ScalarRepresentation rep =
+        static_cast<ScalarRepresentation>(
+          SCALAR_REP_COMPONENT + j);
+
+    int nc = (j == 0) ? m_Wrapper->GetNumberOfComponents() : 1;
+    for(int k = 0; k < nc; k++)
+      {
+      // Get the component/derived wrapper
+      ScalarImageWrapperBase *sw = m_Wrapper->GetScalarRepresentation(rep, k);
+
+      // Try casting to the component type
+      ComponentWrapper *cw = dynamic_cast<ComponentWrapper *>(sw);
+      if(cw && cw != first_comp)
+        {
+        // Copy the LUT from the first comp to the current component.
+        cw->GetDisplayMapping()->CopyDisplayPipeline(first_comp->GetDisplayMapping());
+        }
+
+      else if(cw != first_comp)
+        {
+        AbstractContinuousImageDisplayMappingPolicy *dp =
+            static_cast<AbstractContinuousImageDisplayMappingPolicy *>(
+              sw->GetDisplayMapping());
+
+        // Copy the LUT from the first comp to the current component.
+        dp->SetColorMap(first_comp->GetColorMap());
+        }
+
+      // Pass inputs to the slice selector
+      for(int i = 0; i < 3; i++)
+        {
+        m_DisplaySliceSelector[i]->AddSelectableInput(
+              MultiChannelDisplayMode(false, rep, k),
+              sw->GetDisplaySlice(i));
+        }
+      }
+    }
+
+  // Set display mode to default
+  SetDisplayMode(MultiChannelDisplayMode());
+}
+
+template <class TWrapperTraits>
+void
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::SetDisplayMode(MultiChannelDisplayMode mode)
+{
+  // Store the mode
+  m_DisplayMode = mode;
+
+  // Select the proper output in the selection filters
+  for(int i = 0; i < 3; i++)
+    m_DisplaySliceSelector[i]->SetSelectedInput(mode);
+
+  // Point to the selected scalar representation
+  int nc = m_Wrapper->GetNumberOfComponents();
+  if(mode.UseRGB)
+    {
+    if(nc != 3)
+      throw IRISException("RGB mode requested for %d component image", nc);
+    m_ScalarRepresentation = NULL;
+    }
+  else
+    {
+    if(mode.SelectedComponent >= nc || mode.SelectedComponent < 0)
+      throw IRISException("Requested component for display %d "
+                          "is not in valid range [0, %d]",
+                          mode.SelectedComponent, nc);
+    m_ScalarRepresentation =
+        m_Wrapper->GetScalarRepresentation(
+          mode.SelectedScalarRep, mode.SelectedComponent);
+    if(m_ScalarRepresentation == NULL)
+      std::cerr << "NULL!!!" << std::endl;
+    }
+
+  // Invoke the modified event
+  this->InvokeEvent(itk::ModifiedEvent());
+}
+
+
+template <class TWrapperTraits>
+typename MultiChannelDisplayMappingPolicy<TWrapperTraits>::DisplaySlicePointer
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::GetDisplaySlice(unsigned int slice)
+{
+  return m_DisplaySliceSelector[slice]->GetOutput();
+}
+
+template <class TWrapperTraits>
+IntensityCurveInterface *
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::GetIntensityCurve() const
+{
+  if(m_ScalarRepresentation)
+    {
+    return m_ScalarRepresentation->GetIntensityCurve();
+    }
+  else
+    {
+    return m_LUTGenerator->GetIntensityCurve();
+    }
+}
+
+template <class TWrapperTraits>
+ColorMap *
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::GetColorMap() const
+{
+  if(m_ScalarRepresentation)
+    {
+    return m_ScalarRepresentation->GetColorMap();
+    }
+  else return NULL;
+}
+
+template <class TWrapperTraits>
+void
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::SetColorMap(ColorMap *map)
+{
+  // TODO: do we really need an implementation?
+}
+
+
+template <class TWrapperTraits>
+bool
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::IsContrastMultiComponent() const
+{
+  if(m_DisplayMode.UseRGB || m_Animate)
+    return true;
+
+  return false;
+}
+
+
+template<class TWrapperTraits>
+Vector2d
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::GetNativeImageRangeForCurve()
+{
+  double cmin, cmax;
+
+  // The native range is global componentwise max/min when we are in RGB mode
+  // or when we are in single component mode (because the curves are shared
+  // between these display modes).
+  if(m_DisplayMode.UseRGB ||
+     m_DisplayMode.SelectedScalarRep == SCALAR_REP_COMPONENT)
+    {
+    cmin = m_Wrapper->GetImageMinNative();
+    cmax = m_Wrapper->GetImageMaxNative();
+    }
+
+  // Otherwise, when displaying a derived component, the image range is specific
+  // to that component (the component has its own curve).
+  else
+    {
+    cmin = m_ScalarRepresentation->GetImageMinNative();
+    cmax = m_ScalarRepresentation->GetImageMaxNative();
+    }
+
+  return Vector2d(cmin, cmax);
+}
+
+template<class TWrapperTraits>
+const ScalarImageHistogram *
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::GetHistogram(int nBins)
+{
+  if(m_DisplayMode.UseRGB)
+    {
+    // In RGB mode, we should return a pooled histogram of the data.
+    return m_Wrapper->GetHistogram(nBins);
+    }
+  else
+    {
+    // Otherwise, we return the component-specific histogram
+    return m_ScalarRepresentation->GetHistogram(nBins);
+    }
+
+}
+
+
+template<class TWrapperTraits>
+void
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::AutoFitContrast()
+{
+  // It's safe to just call the parent's method
+  Superclass::AutoFitContrast();
+}
+
+
+template <class TWrapperTraits>
+void
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::Save(Registry &folder)
+{
+  // If the image has only one component, use the scalar representation
+  if(m_Wrapper->GetNumberOfComponents() == 1)
+    {
+    m_ScalarRepresentation->GetDisplayMapping()->Save(folder);
+    }
+  else
+    {
+    // We need to save the properties for each of the relevant scalar
+    // representations.
+    for(int i = 0; i < NUMBER_OF_SCALAR_REPS; i++)
+      {
+      ScalarRepresentation rep = static_cast<ScalarRepresentation>(i);
+      std::string repname = MultiChannelDisplayMode::GetScalarRepNames()[rep];
+
+      // Get the scalar representation in question
+      ScalarImageWrapperBase *scalar = m_Wrapper->GetScalarRepresentation(rep);
+
+      // Save its properties
+      scalar->GetDisplayMapping()->Save(folder.Folder(repname));
+      }
+
+    // We also need to state what the current representation is and whether
+    // we are using RGB mode
+    m_DisplayMode.Save(folder);
+    }
+}
+
+template <class TWrapperTraits>
+void
+MultiChannelDisplayMappingPolicy<TWrapperTraits>
+::Restore(Registry &folder)
+{
+  // If the image has only one component, use the scalar representation
+  if(m_Wrapper->GetNumberOfComponents() == 1)
+    {
+    m_ScalarRepresentation->GetDisplayMapping()->Restore(folder);
+    }
+  else
+    {
+    // We need to restore the properties for each of the relevant scalar
+    // representations.
+    for(int i = 0; i < NUMBER_OF_SCALAR_REPS; i++)
+      {
+      ScalarRepresentation rep = static_cast<ScalarRepresentation>(i);
+      std::string repname = MultiChannelDisplayMode::GetScalarRepNames()[rep];
+
+      // Get the scalar representation in question
+      ScalarImageWrapperBase *scalar = m_Wrapper->GetScalarRepresentation(rep);
+
+      // Save its properties
+      scalar->GetDisplayMapping()->Restore(folder.Folder(repname));
+      }
+
+    // Restore the display mode
+    MultiChannelDisplayMode mode = MultiChannelDisplayMode::Load(folder);
+
+    // Make sure the display mode is compatible
+    if(m_Wrapper && mode.UseRGB && m_Wrapper->GetNumberOfComponents() != 3)
+      mode = MultiChannelDisplayMode();
+
+    if(m_Wrapper && mode.SelectedComponent >= m_Wrapper->GetNumberOfComponents())
+      mode = MultiChannelDisplayMode();
+
+    this->SetDisplayMode(mode);
+    }
+}
+
+
+template class ColorLabelTableDisplayMappingPolicy<LabelImageWrapperTraits>;
+
+template class LinearColorMapDisplayMappingPolicy<LevelSetImageWrapperTraits>;
+template class LinearColorMapDisplayMappingPolicy<SpeedImageWrapperTraits>;
+
+template class MultiChannelDisplayMappingPolicy<AnatomicImageWrapperTraits<GreyType> >;
+
+template class CachingCurveAndColorMapDisplayMappingPolicy<
+    ComponentImageWrapperTraits<GreyType> >;
+template class CachingCurveAndColorMapDisplayMappingPolicy<
+    AnatomicScalarImageWrapperTraits<GreyType> >;
+template class CachingCurveAndColorMapDisplayMappingPolicy<
+    VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMagnitudeFunctor> >;
+template class CachingCurveAndColorMapDisplayMappingPolicy<
+    VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMaxFunctor> >;
+template class CachingCurveAndColorMapDisplayMappingPolicy<
+    VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMeanFunctor> >;
+
+
+
+
diff --git a/Logic/ImageWrapper/DisplayMappingPolicy.h b/Logic/ImageWrapper/DisplayMappingPolicy.h
new file mode 100644
index 0000000..6e5c43d
--- /dev/null
+++ b/Logic/ImageWrapper/DisplayMappingPolicy.h
@@ -0,0 +1,552 @@
+#ifndef DISPLAYMAPPINGPOLICY_H
+#define DISPLAYMAPPINGPOLICY_H
+
+#include "ImageWrapperBase.h"
+#include "itkDataObject.h"
+#include "itkObjectFactory.h"
+#include "IntensityToColorLookupTableImageFilter.h"
+
+class ColorLabelTable;
+class LabelToRGBAFilter;
+class IntensityCurveVTK;
+class Registry;
+template <class TEnum> class RegistryEnumMap;
+template <class T, class U> class LookupTableIntensityMappingFilter;
+template <class T> class RGBALookupTableIntensityMappingFilter;
+template <class T, typename U> class InputSelectionImageFilter;
+
+/**
+ * @brief An abstract class describing intensity mapping between image
+ * intensities stored internally in an itk image and RGBA intensities
+ * displayed to the user. This class is a parent in a hierarchy of
+ * policies used to customize ImageWrapper behavior.
+ */
+class AbstractDisplayMappingPolicy : public itk::DataObject
+{
+public:
+
+  irisITKAbstractObjectMacro(AbstractDisplayMappingPolicy, itk::DataObject)
+
+  typedef ImageWrapperBase::DisplaySliceType DisplaySliceType;
+  typedef ImageWrapperBase::DisplaySlicePointer DisplaySlicePointer;
+
+  virtual IntensityCurveInterface *GetIntensityCurve() const = 0;
+  virtual ColorMap *GetColorMap() const = 0;
+
+  virtual DisplaySlicePointer GetDisplaySlice(unsigned int slice) = 0;
+
+  virtual void Save(Registry &folder) = 0;
+  virtual void Restore(Registry &folder) = 0;
+};
+
+class AbstractColorLabelTableDisplayMappingPolicy : public AbstractDisplayMappingPolicy
+{
+public:
+
+  irisITKAbstractObjectMacro(AbstractColorLabelTableDisplayMappingPolicy,
+                             AbstractDisplayMappingPolicy)
+
+  /**
+   * Set the table of color labels used to produce color slice images
+   */
+  virtual void SetLabelColorTable(ColorLabelTable *labels) = 0;
+
+  /**
+   * Get the color label table
+   */
+  virtual ColorLabelTable *GetLabelColorTable() const = 0;
+};
+
+template <class TWrapperTraits>
+class ColorLabelTableDisplayMappingPolicy
+    : public AbstractColorLabelTableDisplayMappingPolicy
+{
+public:
+
+  irisITKObjectMacro(ColorLabelTableDisplayMappingPolicy<TWrapperTraits>,
+                     AbstractColorLabelTableDisplayMappingPolicy)
+
+  typedef typename TWrapperTraits::WrapperType WrapperType;
+  typedef typename TWrapperTraits::ImageType ImageType;
+  typedef itk::Image<LabelType, 2> InputSliceType;
+  typedef ImageWrapperBase::DisplaySliceType DisplaySliceType;
+  typedef ImageWrapperBase::DisplaySlicePointer DisplaySlicePointer;
+
+  /**
+   * Set the table of color labels used to produce color slice images
+   */
+  void SetLabelColorTable(ColorLabelTable *labels);
+
+  /**
+   * Get the color label table
+   */
+  ColorLabelTable *GetLabelColorTable() const;
+
+  void Initialize(WrapperType *wrapper);
+  void UpdateImagePointer(ImageType *image);
+
+  DisplaySlicePointer GetDisplaySlice(unsigned int slice);
+
+  virtual IntensityCurveInterface *GetIntensityCurve() const { return NULL; }
+  virtual ColorMap *GetColorMap() const { return NULL; }
+
+  virtual void Save(Registry &folder) {}
+  virtual void Restore(Registry &folder) {}
+
+protected:
+
+  ColorLabelTableDisplayMappingPolicy();
+  ~ColorLabelTableDisplayMappingPolicy();
+
+  typedef LabelToRGBAFilter RGBAFilterType;
+  typedef SmartPtr<RGBAFilterType> RGBAFilterPointer;
+
+  RGBAFilterPointer m_RGBAFilter[3];
+  WrapperType *m_Wrapper;
+};
+
+/**
+ * @brief The parent class for the policies that involve curve-based mappings,
+ * for both scalar and vector images.
+ */
+class AbstractContinuousImageDisplayMappingPolicy : public AbstractDisplayMappingPolicy
+{
+public:
+  irisITKAbstractObjectMacro(AbstractContinuousImageDisplayMappingPolicy,
+                             AbstractDisplayMappingPolicy)
+
+  virtual IntensityCurveInterface *GetIntensityCurve() const = 0;
+
+  /**
+   * @brief Get the intensity range relative to which the contrast mapping
+   * curve is constructed. This is primarily used when displaying the curve
+   * to the user.
+   * @return Vector containing min/max of the curve range (in native units)
+   */
+  virtual Vector2d GetNativeImageRangeForCurve() = 0;
+
+  /**
+   * @brief Get the histogram associated with the current state of the display
+   * policy. For single-component layers, this method just returns the
+   * component's histogram. For multi-component layers, it may return the
+   * pooled histogram, e.g., when the display is in RGB mode
+   * @param nBins Number of bins desired in the histogram
+   */
+  virtual const ScalarImageHistogram *GetHistogram(int nBins) = 0;
+
+  virtual void SetColorMap(ColorMap *map) = 0;
+
+  /**
+   * Automatically fit the contrast mapping based on the percentiles of
+   * the image histogram.
+   * TODO: the accuracy of this is currently limited by the bin size in
+   * the histogram. At some point, it may make sense to have separate
+   * histograms for display and for auto-fitting.
+   */
+  virtual void AutoFitContrast();
+
+  /**
+   * Has the intensity curve been adjusted from its default (reset) state?
+   */
+  virtual bool IsContrastInDefaultState();
+
+};
+
+class AbstractCachingAndColorMapDisplayMappingPolicy
+    : public AbstractContinuousImageDisplayMappingPolicy
+{
+public:
+  irisITKAbstractObjectMacro(AbstractCachingAndColorMapDisplayMappingPolicy,
+                             AbstractContinuousImageDisplayMappingPolicy)
+
+};
+
+
+
+
+
+
+
+
+template<class TWrapperTraits>
+class CachingCurveAndColorMapDisplayMappingPolicy
+    : public AbstractCachingAndColorMapDisplayMappingPolicy
+{
+public:
+
+  irisITKObjectMacro(CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>,
+                     AbstractCachingAndColorMapDisplayMappingPolicy)
+
+  typedef typename TWrapperTraits::WrapperType WrapperType;
+  typedef typename TWrapperTraits::ImageType ImageType;
+  typedef typename ImageType::PixelType PixelType;
+  typedef typename TWrapperTraits::ComponentType ComponentType;
+  typedef itk::Image<PixelType, 2> InputSliceType;
+
+  typedef ImageWrapperBase::DisplaySliceType DisplaySliceType;
+  typedef ImageWrapperBase::DisplaySlicePointer DisplaySlicePointer;
+  typedef ImageWrapperBase::DisplayPixelType DisplayPixelType;
+
+  // Lookup table
+  typedef itk::Image<DisplayPixelType, 1>                     LookupTableType;
+
+  // Min/Max inputs
+  typedef itk::SimpleDataObjectDecorator<ComponentType>   ComponentObjectType;
+
+
+  /**
+   * @brief Copy the LUT, intensity curve, and color map from another display
+   * mapping. This allows memory savings by sharing the LUT among multiple
+   * wrappers. This is used with components on a multi-component image
+   */
+  void CopyDisplayPipeline(const Self *reference);
+
+  void DeepCopyIntensityMap(WrapperType *srcWrapper);
+
+  /**
+   * Set the reference intensity range for the lookup table and intensity curve.
+   * This means that the LUT is constructed not between the image min and image
+   * max, but between some other pair of values. This is useful when the image
+   * in the imagewrapper is a subregion of another image, or when the image is
+   * a component of a multi-component image.
+   */
+  void SetReferenceIntensityRange(ComponentObjectType *refMin,
+                                  ComponentObjectType *refMax);
+
+  void ClearReferenceIntensityRange();
+
+  Vector2d GetNativeImageRangeForCurve();
+
+  virtual const ScalarImageHistogram *GetHistogram(int nBins);
+
+
+  /**
+   * Get the display slice in a given direction.  To change the
+   * display slice, call parent's MoveToSlice() method
+   */
+  DisplaySlicePointer GetDisplaySlice(unsigned int dim);
+
+  /**
+    Get a pointer to the colormap
+    */
+  ColorMap *GetColorMap () const;
+
+  void SetColorMap(ColorMap *map);
+
+  /**
+   * Get a pointer to the intensity curve
+   */
+  virtual IntensityCurveInterface *GetIntensityCurve() const;
+
+  /**
+   * Set a new intensity curve
+   */
+  void SetIntensityCurve(IntensityCurveInterface *curve);
+
+  void Initialize(WrapperType *wrapper);
+  void UpdateImagePointer(ImageType *image);
+
+  virtual void Save(Registry &folder);
+  virtual void Restore(Registry &folder);
+
+
+protected:
+
+  CachingCurveAndColorMapDisplayMappingPolicy();
+  ~CachingCurveAndColorMapDisplayMappingPolicy();
+
+
+  // Filter that generates the lookup table
+  typedef IntensityToColorLookupTableImageFilter<
+              ImageType, LookupTableType>               LookupTableFilterType;
+
+  // Filter that applies the lookup table to slices
+  typedef LookupTableIntensityMappingFilter<
+                InputSliceType, DisplaySliceType>         IntensityFilterType;
+
+
+  // LUT generator
+  SmartPtr<LookupTableFilterType> m_LookupTableFilter;
+
+  // Filters for the three slice directions
+  SmartPtr<IntensityFilterType> m_IntensityFilter[3];
+
+  /**
+   * Implementation of the intensity curve funcitonality. The intensity map
+   * transforms input intensity values into the range [0 1], which serves as
+   * the input into the color map transform.
+   */
+  SmartPtr<IntensityCurveVTK> m_IntensityCurveVTK;
+
+  /**
+    * Color map, which maps intensity values normalized to the range [0 1]
+    * to output RGB values
+    */
+  SmartPtr<ColorMap> m_ColorMap;
+
+  WrapperType *m_Wrapper;
+
+};
+
+
+/*
+template<class TWrapperTraits>
+class SpeedImageWrapperDisplayPolicy
+    : public LinearColorMapDisplayMappingPolicy
+{
+public:
+  irisITKObjectMacro(SpeedImageWrapperDisplayPolicy<TWrapperTraits>,
+                     CachingCurveAndColorMapDisplayMappingPolicy<TWrapperTraits>)
+
+  void UpdateImagePointer(ImageType *image);
+
+protected:
+
+  SpeedImageWrapperDisplayPolicy() {}
+  virtual ~SpeedImageWrapperDisplayPolicy() {}
+
+};
+*/
+
+
+
+
+
+
+/**
+ * This little struct describes the behavior of the multichannel display
+ * mapping policy
+ */
+struct MultiChannelDisplayMode
+{
+  /**
+   * Whether or not components are mapped to RGB channels. This is only
+   * allowed if the image has 3 components
+   */
+  bool UseRGB;
+
+  /**
+   * When not in RGB mode, which scalar representation is selected for
+   * display. Only used if UseRGB is false.
+   */
+  ScalarRepresentation SelectedScalarRep;
+
+  /**
+   * When the scalar representation is 'component', which component is
+   * selected for display.
+   */
+  int SelectedComponent;
+
+  /** Default constructor - select first component */
+  MultiChannelDisplayMode();
+
+  /** Default constructor - select first component */
+  MultiChannelDisplayMode(bool use_rgb,
+                          ScalarRepresentation rep,
+                          int comp = 0);
+
+  /** Constructor from an integer, used for compatibility purposes, allowing
+   * zero to be cast to the default mode state */
+  MultiChannelDisplayMode(int value);
+
+  /** Initialize for RGB mode */
+  static MultiChannelDisplayMode DefaultForRGB();
+
+  /** Save to registry */
+  void Save(Registry &reg);
+
+  /** Restore from registry */
+  static MultiChannelDisplayMode Load(Registry &reg);
+
+  static RegistryEnumMap<ScalarRepresentation> &GetScalarRepNames();
+
+  /** Get a hash value for this struct - for ordering purposes */
+  int GetHashValue() const;
+
+  /** Comparison operators */
+  bool operator == (const MultiChannelDisplayMode &mode) const
+    { return GetHashValue() == mode.GetHashValue(); }
+
+  bool operator != (const MultiChannelDisplayMode &mode) const
+    { return GetHashValue() != mode.GetHashValue(); }
+};
+
+bool operator < (const MultiChannelDisplayMode &a, const MultiChannelDisplayMode &b);
+
+/**
+ * Display mapping policy for speed and level set images, i.e., images that
+ * have a defined range of intensity and a colormap that takes them from
+ * intensity values to display RGB values. This policy can work with both
+ * integral and floating point types.
+ */
+class AbstractLinearColorMapDisplayMappingPolicy : public AbstractDisplayMappingPolicy
+{
+public:
+  irisITKAbstractObjectMacro(AbstractLinearColorMapDisplayMappingPolicy,
+                             AbstractContinuousImageDisplayMappingPolicy)
+
+};
+
+namespace itk {
+  template <class TInput,class TOutput,class TFunctor>
+    class UnaryFunctorImageFilter;
+}
+
+template <class TWrapperTraits>
+class LinearColorMapDisplayMappingPolicy
+    : public AbstractLinearColorMapDisplayMappingPolicy
+{
+public:
+
+  irisITKObjectMacro(LinearColorMapDisplayMappingPolicy<TWrapperTraits>,
+                     AbstractLinearColorMapDisplayMappingPolicy)
+
+  typedef typename TWrapperTraits::WrapperType WrapperType;
+  typedef typename TWrapperTraits::ImageType ImageType;
+  typedef typename ImageType::PixelType PixelType;
+
+  typedef itk::Image<PixelType, 2> InputSliceType;
+  typedef ImageWrapperBase::DisplaySliceType DisplaySliceType;
+  typedef ImageWrapperBase::DisplaySlicePointer DisplaySlicePointer;
+  typedef ImageWrapperBase::DisplayPixelType DisplayPixelType;
+
+  void Initialize(WrapperType *wrapper);
+  void UpdateImagePointer(ImageType *image);
+
+  virtual DisplaySlicePointer GetDisplaySlice(unsigned int slice);
+
+  virtual IntensityCurveInterface *GetIntensityCurve() const { return NULL; }
+
+  virtual void Save(Registry &folder);
+  virtual void Restore(Registry &folder);
+
+  irisGetMacro(ColorMap, ColorMap *)
+
+  protected:
+
+  LinearColorMapDisplayMappingPolicy();
+  virtual ~LinearColorMapDisplayMappingPolicy();
+
+  class MappingFunctor
+  {
+  public:
+    DisplayPixelType operator()(PixelType in);
+    double m_Scale, m_Shift;
+    ColorMap *m_ColorMap;
+    bool operator != (const MappingFunctor &f);
+  };
+
+  typedef itk::UnaryFunctorImageFilter
+    <InputSliceType, DisplaySliceType, MappingFunctor> IntensityFilterType;
+  typedef SmartPtr<IntensityFilterType> IntensityFilterPointer;
+
+  IntensityFilterPointer m_Filter[3];
+  MappingFunctor m_Functor;
+
+  SmartPtr<ColorMap> m_ColorMap;
+  WrapperType *m_Wrapper;
+};
+
+
+class AbstractMultiChannelDisplayMappingPolicy
+    : public AbstractContinuousImageDisplayMappingPolicy
+{
+public:
+  irisITKAbstractObjectMacro(AbstractMultiChannelDisplayMappingPolicy,
+                             AbstractContinuousImageDisplayMappingPolicy)
+
+  irisVirtualGetMacro(DisplayMode, MultiChannelDisplayMode)
+  irisVirtualSetMacro(DisplayMode, MultiChannelDisplayMode)
+
+  irisVirtualGetMacro(Animate, bool)
+  irisVirtualSetMacro(Animate, bool)
+
+};
+
+template <class TWrapperTraits>
+class MultiChannelDisplayMappingPolicy
+    : public AbstractMultiChannelDisplayMappingPolicy
+{
+public:
+
+  irisITKObjectMacro(MultiChannelDisplayMappingPolicy<TWrapperTraits>,
+                     AbstractMultiChannelDisplayMappingPolicy)
+
+
+  typedef typename TWrapperTraits::WrapperType WrapperType;
+  typedef typename TWrapperTraits::ImageType ImageType;
+  typedef typename ImageType::PixelType PixelType;
+  typedef typename ImageType::InternalPixelType InternalPixelType;
+
+  typedef itk::Image<InternalPixelType, 2> InputSliceType;
+
+  typedef ImageWrapperBase::DisplaySliceType DisplaySliceType;
+  typedef ImageWrapperBase::DisplaySlicePointer DisplaySlicePointer;
+  typedef ImageWrapperBase::DisplayPixelType DisplayPixelType;
+
+  void Initialize(WrapperType *wrapper);
+  void UpdateImagePointer(ImageType *image);
+
+  /** Set the display mode */
+  virtual void SetDisplayMode(MultiChannelDisplayMode mode);
+
+  /** Get the display mode */
+  irisGetMacro(DisplayMode, MultiChannelDisplayMode)
+
+  /** Get/Set the animation status */
+  irisGetSetMacro(Animate, bool)
+
+  DisplaySlicePointer GetDisplaySlice(unsigned int slice);
+
+  Vector2d GetNativeImageRangeForCurve();
+  virtual const ScalarImageHistogram *GetHistogram(int nBins);
+
+  /**
+   * @brief Returns true when the display mode is such that the image min, max
+   * and histogram used for contrast adjustment purposes use intensities pooled
+   * from all of the components. This is the case when the components are being
+   * animated or when display is in RGB mode.
+   */
+  bool IsContrastMultiComponent() const;
+
+  virtual IntensityCurveInterface *GetIntensityCurve() const;
+  virtual ColorMap *GetColorMap() const;
+  virtual void SetColorMap(ColorMap *map);
+
+  virtual void Save(Registry &folder);
+  virtual void Restore(Registry &folder);
+
+  virtual void AutoFitContrast();
+
+  irisGetMacro(ScalarRepresentation, ScalarImageWrapperBase *)
+
+protected:
+
+  MultiChannelDisplayMappingPolicy();
+  ~MultiChannelDisplayMappingPolicy();
+
+  typedef RGBALookupTableIntensityMappingFilter<InputSliceType> ApplyLUTFilter;
+  typedef itk::Image<unsigned char, 1>                         LookupTableType;
+
+  typedef MultiComponentImageToScalarLookupTableImageFilter<ImageType, LookupTableType>
+                                                             GenerateLUTFilter;
+
+  MultiChannelDisplayMode m_DisplayMode;
+
+  bool m_Animate;
+
+  ScalarImageWrapperBase *m_ScalarRepresentation;
+  WrapperType *m_Wrapper;
+
+  SmartPtr<GenerateLUTFilter> m_LUTGenerator;
+  SmartPtr<ApplyLUTFilter> m_RGBMapper[3];
+
+  // Filters used to select the right pipeline for display
+  typedef InputSelectionImageFilter<
+    DisplaySliceType, MultiChannelDisplayMode> DisplaySliceSelector;
+  SmartPtr<DisplaySliceSelector> m_DisplaySliceSelector[3];
+};
+
+
+
+#endif // DISPLAYMAPPINGPOLICY_H
diff --git a/Logic/ImageWrapper/GreyImageWrapper.cxx b/Logic/ImageWrapper/GreyImageWrapper.cxx
deleted file mode 100644
index 2b7e4f1..0000000
--- a/Logic/ImageWrapper/GreyImageWrapper.cxx
+++ /dev/null
@@ -1,202 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: GreyImageWrapper.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/06/28 18:45:08 $
-  Version:   $Revision: 1.19 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "GreyImageWrapper.h"
-#include "UnaryFunctorCache.h"
-#include "ImageWrapper.txx"
-#include "ScalarImageWrapper.txx"
-
-#include "itkFunctionBase.h"
-#include "itkUnaryFunctorImageFilter.h"
-
-
-// Create an instance of ImageWrapper of appropriate type
-template class ImageWrapper<GreyType>;
-template class ScalarImageWrapper<GreyType>;
-
-GreyImageWrapper
-::GreyImageWrapper()
-: ScalarImageWrapper<GreyType> ()
-{
-  // Initialize the intensity curve
-  m_IntensityCurveVTK = IntensityCurveVTK::New();
-  m_IntensityCurveVTK->Initialize();
-
-  // Initialize the intensity functor
-  m_IntensityFunctor.m_IntensityMap = m_IntensityCurveVTK;
-
-  // Instantiate the cache
-  m_IntensityMapCache = CacheType::New();
-
-  // Set the target of the cache
-  m_IntensityMapCache->SetInputFunctor(&m_IntensityFunctor);
-
-  // Instantiate the filters
-  for(unsigned int i=0;i<3;i++) 
-  {
-    m_IntensityFilter[i] = IntensityFilterType::New();
-    m_IntensityFilter[i]->SetFunctor(m_IntensityMapCache->GetCachingFunctor());
-    m_IntensityFilter[i]->SetInput(m_Slicer[i]->GetOutput());
-  }
-
-  // By default, reference range is not used
-  m_FlagUseReferenceIntensityRange = false;
-}
-
-GreyImageWrapper
-::~GreyImageWrapper()
-{
-  for (size_t i = 0; i < 3; ++i)
-    {
-    m_IntensityFilter[i] = NULL;
-    }
-  m_IntensityMapCache = NULL;
-  m_IntensityCurveVTK = NULL;
-}
-
-void GreyImageWrapper
-::SetReferenceIntensityRange(GreyType refMin, GreyType refMax)
-{
-  m_FlagUseReferenceIntensityRange = true;
-  m_ReferenceIntensityMin = refMin;
-  m_ReferenceIntensityMax = refMax;  
-}
-
-void GreyImageWrapper
-::ClearReferenceIntensityRange()
-{
-  m_FlagUseReferenceIntensityRange = false;
-}
-
-IntensityCurveInterface*
-GreyImageWrapper
-::GetIntensityMapFunction()
-{
-  return m_IntensityCurveVTK;
-}
-
-void 
-GreyImageWrapper
-::CopyIntensityMap(const GreyImageWrapper &s)
-{
-  m_IntensityCurveVTK->Initialize(
-    s.m_IntensityCurveVTK->GetControlPointCount());
-  for(size_t i = 0; i < m_IntensityCurveVTK->GetControlPointCount(); i++)
-    {
-    float t, x;
-    s.m_IntensityCurveVTK->GetControlPoint(i, t, x);
-    m_IntensityCurveVTK->UpdateControlPoint(i, t, x);
-    }
-}
-
-void GreyImageWrapper
-::UpdateIntensityMapFunction()
-{
-  // Get the range of the image
-  GreyType iMin = GetImageMin();
-  GreyType iMax = GetImageMax();
-
-  // Set the input range of the functor
-  if(m_FlagUseReferenceIntensityRange)
-    {
-    m_IntensityFunctor.SetInputRange(
-      m_ReferenceIntensityMin,
-      m_ReferenceIntensityMax);
-    }
-  else
-    {
-    m_IntensityFunctor.SetInputRange(iMin, iMax);
-    }
-    
-  // Set the active range of the cache
-  m_IntensityMapCache->SetEvaluationRange(iMin,iMax);
-
-  // Dirty the intensity filters
-  for(unsigned int i=0;i<3;i++)
-    m_IntensityFilter[i]->Modified();
-}
-
-GreyImageWrapper::DisplaySlicePointer
-GreyImageWrapper
-::GetDisplaySlice(unsigned int dim) const
-{
-  return m_IntensityFilter[dim]->GetOutput();
-}
-
-ColorMap
-GreyImageWrapper
-::GetColorMap() const
-{
-  return m_IntensityFunctor.m_Colormap;
-}
-
-void
-GreyImageWrapper
-::SetColorMap(const ColorMap& colormap)
-{
-  m_IntensityFunctor.m_Colormap = colormap;
-}
-
-void
-GreyImageWrapper
-::Update()
-{
-  // Dirty the intensity filters
-  for(unsigned int i=0;i<3;i++)
-    m_IntensityFilter[i]->Modified();
-}
-
-void 
-GreyImageWrapper::IntensityFunctor
-::SetInputRange(GreyType intensityMin, GreyType intensityMax) 
-{
-  m_IntensityMin = intensityMin;
-  m_IntensityFactor = 1.0f / (intensityMax-intensityMin);
-}
-
-GreyImageWrapper::DisplayPixelType
-GreyImageWrapper::IntensityFunctor
-::operator()(const GreyType &in) const 
-{
-  // Map the input value to range of 0 to 1
-  double inZeroOne = (in - m_IntensityMin) * m_IntensityFactor;
-  
-  // Compute the intensity mapping
-  double outZeroOne = m_IntensityMap->Evaluate(inZeroOne);
-
-  // Map the output to a RGBA pixel
-  return m_Colormap.MapIndexToRGBA(outZeroOne);
-}
-
-
diff --git a/Logic/ImageWrapper/GreyImageWrapper.h b/Logic/ImageWrapper/GreyImageWrapper.h
deleted file mode 100644
index 4c22831..0000000
--- a/Logic/ImageWrapper/GreyImageWrapper.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: GreyImageWrapper.h,v $
-  Language:  C++
-  Date:      $Date: 2009/09/19 08:15:09 $
-  Version:   $Revision: 1.17 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __GreyImageWrapper_h_
-#define __GreyImageWrapper_h_
-
-#include "ScalarImageWrapper.h"
-#include "ColorMap.h"
-#include "IntensityCurveVTK.h"
-// #include "UnaryFunctorCache.h"
-
-// Forward references
-namespace itk {
-  template<class TInput,class TOutput> class FunctionBase;
-  template<class TInput,class TOutput,class TFunctor> 
-    class UnaryFunctorImageFilter;
-};
-template <class TInput, class TOutput, class TFunctor> 
-  class UnaryFunctorCache;
-template <class TInput, class TOutput, class TFunctor> 
-  class CachingUnaryFunctor;
-
-/**
- * \class GreyImageWrapper
- * \brief Image wrapper used for greyscale images in IRIS/SNAP.
- * 
- * Adds ability to remap intensity from short to byte using an
- * arbitrary function when outputing slices.
- */
-class GreyImageWrapper : public ScalarImageWrapper<GreyType>
-{
-public:
-
-  /**
-   * Get the intensity curve to be used for mapping image intensities 
-   * from GreyType to DisplayType. The curve is defined on the domain
-   * [0, 1]. By default, the entire intensity range of the image is
-   * mapped to the domain of the curve. However, in some situations 
-   * (e.g., when the image is a subregion of another image with respect
-   * to which the curve was created), the domain of the curve should 
-   * correspond to a different intensity range. That can be specified
-   * using the SetReferenceIntensityRange() function
-   */
-  IntensityCurveInterface* GetIntensityMapFunction();
-
-  /**
-   * Copy the intensity curve information from another grey image wrapper
-   */
-  void CopyIntensityMap(const GreyImageWrapper &source);
-
-  void UpdateIntensityMapFunction();
-
-  /**
-   * Set the reference intensity range - a range of intensity that 
-   * is mapped to the domain of the intensity curve
-   * @see GetIntensityMapFunction
-   */
-  void SetReferenceIntensityRange(GreyType refMin, GreyType refMax);
-  void ClearReferenceIntensityRange();
-
-  /**
-   * Set the transformation to native intensity space
-   */
-  irisSetMacro(NativeMapping, GreyTypeToNativeFunctor);
-  irisGetMacro(NativeMapping, GreyTypeToNativeFunctor);
-
-
-  /**
-   * Get voxel intensity in native space
-   */
-  double GetVoxelMappedToNative(const Vector3ui &vec)
-    { return m_NativeMapping(this->GetVoxel(vec)); }
-
-  /**
-   * Get min/max voxel intensity in native space
-   */
-  double GetImageMinNative()
-    { return m_NativeMapping(this->GetImageMin()); }
-  double GetImageMaxNative()
-    { return m_NativeMapping(this->GetImageMax()); }
-
-  /**
-   * Get the display slice in a given direction.  To change the
-   * display slice, call parent's MoveToSlice() method
-   */
-  DisplaySlicePointer GetDisplaySlice(unsigned int dim) const;
-
-  /**
-   * Get/Set the colormap
-   */
-  ColorMap GetColorMap () const;
-  void SetColorMap (const ColorMap& colormap);
-
-  void Update();
-
-  /** Constructor initializes mappers */
-  GreyImageWrapper();
-
-  /** Destructor */
-  ~GreyImageWrapper();
-
-private:
-
-  /**
-   * This object is passed on to the cache for intensity mapping
-   */
-  class IntensityFunctor {
-  public:
-
-    /** Map a grey value */
-    DisplayPixelType operator()(const GreyType &value) const;
-
-    // The storage for the float->float intensity map
-    IntensityCurveInterface *m_IntensityMap;
-
-    // Intensity mapping factors
-    GreyType m_IntensityMin;
-    float m_IntensityFactor;
- 
-    // Color map
-    ColorMap m_Colormap;
-
-    // Equality operators required, if variables defined!!!
-    bool operator == (const IntensityFunctor &z) const 
-      { 
-      return 
-        m_IntensityMap == z.m_IntensityMap &&
-        m_IntensityFactor == z.m_IntensityFactor &&
-        m_IntensityMin == z.m_IntensityMin &&
-        m_Colormap == z.m_Colormap;
-      }
-
-    bool operator != (const IntensityFunctor &z) const 
-      { return !(*this == z); }
-
-    /**
-     * Set the range over which the input data is mapped to output data
-     */
-    void SetInputRange(GreyType intensityMin,GreyType intensityMax);
-  };
-
-  // Type of intensity function used to map 3D volume intensity into
-  // 2D slice intensities
-  typedef UnaryFunctorCache<GreyType,DisplayPixelType,IntensityFunctor> CacheType;
-  typedef itk::SmartPointer<CacheType> CachePointer;  
-  typedef CachingUnaryFunctor<GreyType,DisplayPixelType,IntensityFunctor>
-     CacheFunctor;
-
-  // Filters applied to slices
-  typedef itk::Image<GreyType,2> GreySliceType;
-  typedef itk::UnaryFunctorImageFilter<
-    GreySliceType,DisplaySliceType,CacheFunctor> IntensityFilterType;
-  typedef itk::SmartPointer<IntensityFilterType> IntensityFilterPointer;
-
-  /**
-   * Reference intensity range. This is used for images that are subregions
-   * of larger images. When evaluating the intensity of these images, the 
-   * intensity curve needs to be applied to the intensity range of the larger 
-   * image, not that of the region.
-   */
-  GreyType m_ReferenceIntensityMin, m_ReferenceIntensityMax;
-  bool m_FlagUseReferenceIntensityRange;
-
-  /**
-   * An instance of the private intensity mapper (this mapper wraps the
-   * passed in float->float function to a new function that is 
-   * [min..max]->uchar)
-   */
-  IntensityFunctor m_IntensityFunctor;
-
-  /**
-   * A cache used for the intensity mapping function
-   */
-  CachePointer m_IntensityMapCache;
-
-  /**
-   *
-   */
-  IntensityCurveVTK::Pointer m_IntensityCurveVTK;
-
-  /**
-   * Filters used to remap the intensity of the slices in this image
-   * into unsigned char images
-   */
-  IntensityFilterPointer m_IntensityFilter[3];
-
-  /** 
-   * The grey image is an image of shorts. But the real image on disk may
-   * be an image of floats or doubles. So we store a transformation from
-   * internal intensity values to 'native' intensity values
-   */
-  GreyTypeToNativeFunctor m_NativeMapping;
-};
-
-#endif // __GreyImageWrapper_h_
diff --git a/Logic/ImageWrapper/GuidedNativeImageIO.cxx b/Logic/ImageWrapper/GuidedNativeImageIO.cxx
index f20e655..5ff5af7 100755
--- a/Logic/ImageWrapper/GuidedNativeImageIO.cxx
+++ b/Logic/ImageWrapper/GuidedNativeImageIO.cxx
@@ -37,10 +37,9 @@
 #include "SNAPCommon.h"
 #include "SNAPRegistryIO.h"
 #include "ImageCoordinateGeometry.h"
-#include "itkOrientedImage.h"
 
+#include "itkImage.h"
 #include "itkImageIOBase.h"
-#include "itkAnalyzeImageIO.h"
 #include "itkGiplImageIO.h"
 #include "itkMetaImageIO.h"
 #include "itkNrrdImageIO.h"
@@ -57,12 +56,15 @@
 #include "itkImageSeriesReader.h"
 #include "itkImageIOFactory.h"
 #include "itkGDCMSeriesFileNames.h"
-#include "itkImageToVectorImageFilter.h"
-
+#include "gdcmFile.h"
+#include "gdcmReader.h"
+#include "gdcmStringFilter.h"
 #include "itkMinimumMaximumImageCalculator.h"
 #include "itkShiftScaleImageFilter.h"
 #include "itkNumericTraits.h"
 
+#include <itk_zlib.h>
+
 
 using namespace std;
 
@@ -74,20 +76,191 @@ RegistryEnumMap<GuidedNativeImageIO::RawPixelType> GuidedNativeImageIO::m_EnumRa
 const GuidedNativeImageIO::FileFormatDescriptor 
 GuidedNativeImageIO
 ::m_FileFormatDescrictorArray[] = {
-  {"MetaImage", "mha,mhd",           true,  true,  true,  true},
-  {"GIPL", "gipl,gipl.gz",           true,  false, true,  true},
-  {"Raw Binary", "raw",              false, false, true,  true},
-  {"Analyze", "hdr,img,img.gz",      true,  false, true,  true},
-  {"DICOM", "dcm",                   false, true,  true,  true},
+  {"Analyze", "img.gz,hdr,img",      true,  false, true,  true},
+  {"DICOM Image Series", "",         false, true,  true,  true},
+  {"DICOM Single Image", "dcm",      false, true,  true,  true},
   {"GE Version 4", "ge4",            false, false, true,  true},
   {"GE Version 5", "ge5",            false, false, true,  true},
-  {"NIFTI", "nii,nia,nii.gz,nia.gz", true,  true,  true,  true},
+  {"GIPL", "gipl,gipl.gz",           true,  false, true,  true},
+  {"MetaImage", "mha,mhd",           true,  true,  true,  true},
+  {"NiFTI", "nii.gz,nii,nia,nia.gz", true,  true,  true,  true},
+  {"NRRD", "nrrd,nhdr",              true,  true,  true,  true},
+  {"Raw Binary", "raw",              false, false, true,  true},
   {"Siemens Vision", "ima",          false, false, true,  true},
-  {"VTK", "vtk",                     true,  false, true,  true},
   {"VoxBo CUB", "cub,cub.gz",        true,  false, true,  true},
-  {"NRRD", "nrrd,nhdr",              true,  true,  true,  true},
+  {"VTK Image", "vtk",               true,  false, true,  true},
   {"INVALID FORMAT", "",             false, false, false, false}};
 
+
+/*************************************************************************/
+/* THE FOLLOWING CODE IS TAKEN FROM FFTW */
+
+/* In-place transpose routine from TOMS, which follows the cycles of
+   the permutation so that it writes to each location only once.
+   Because of cache-line and other issues, however, this routine is
+   typically much slower than transpose-gcd or transpose-cut, even
+   though the latter do some extra writes.  On the other hand, if the
+   vector length is large then the TOMS routine is best.
+
+   The TOMS routine also has the advantage of requiring less buffer
+   space for the case of gcd(nx,ny) small.  However, in this case it
+   has been superseded by the combination of the generalized
+   transpose-cut method with the transpose-gcd method, which can
+   always transpose with buffers a small fraction of the array size
+   regardless of gcd(nx,ny). */
+
+/*
+ * TOMS Transpose.  Algorithm 513 (Revised version of algorithm 380).
+ *
+ * These routines do in-place transposes of arrays.
+ *
+ * [ Cate, E.G. and Twigg, D.W., ACM Transactions on Mathematical Software,
+ *   vol. 3, no. 1, 104-110 (1977) ]
+ *
+ * C version by Steven G. Johnson (February 1997).
+ */
+
+/*
+ * "a" is a 1D array of length ny*nx*N which constains the nx x ny
+ * matrix of N-tuples to be transposed.  "a" is stored in row-major
+ * order (last index varies fastest).  move is a 1D array of length
+ * move_size used to store information to speed up the process.  The
+ * value move_size=(ny+nx)/2 is recommended.  buf should be an array
+ * of length 2*N.
+ *
+ */
+
+template <typename INT>
+INT gcd(INT a, INT b)
+{
+  INT r;
+  do {
+    r = a % b;
+    a = b;
+    b = r;
+    } while (r != 0);
+
+  return a;
+}
+
+template <typename R, typename INT>
+void transpose_toms513(R *a, INT nx, INT ny, char *move, INT move_size, R *buf)
+{
+  INT i, im, mn;
+  R *b, *c, *d;
+  INT ncount;
+  INT k;
+
+  /* check arguments and initialize: */
+  assert(ny > 0 && nx > 0 && move_size > 0);
+
+  b = buf;
+
+  /* Cate & Twigg have a special case for nx == ny, but we don't
+  bother, since we already have special code for this case elsewhere. */
+
+  c = buf + 1;
+  ncount = 2;		/* always at least 2 fixed points */
+  k = (mn = ny * nx) - 1;
+
+  for (i = 0; i < move_size; ++i)
+    move[i] = 0;
+
+  if (ny >= 3 && nx >= 3)
+    ncount += gcd(ny - 1, nx - 1) - 1;	/* # fixed points */
+
+  i = 1;
+  im = ny;
+
+  while (1) {
+    INT i1, i2, i1c, i2c;
+    INT kmi;
+
+    /** Rearrange the elements of a loop
+        and its companion loop: **/
+
+    i1 = i;
+    kmi = k - i;
+    i1c = kmi;
+    b[0] = a[i1];
+    c[0] = a[i1c];
+
+    while (1) {
+      i2 = ny * i1 - k * (i1 / nx);
+      i2c = k - i2;
+      if (i1 < move_size)
+        move[i1] = 1;
+      if (i1c < move_size)
+        move[i1c] = 1;
+      ncount += 2;
+      if (i2 == i)
+        break;
+      if (i2 == kmi) {
+        d = b;
+        b = c;
+        c = d;
+        break;
+        }
+      a[i1] = a[i2];
+      a[i1c] = a[i2c];
+      i1 = i2;
+      i1c = i2c;
+      }
+
+    a[i1] = b[0];
+    a[i1c] = c[0];
+
+    if (ncount >= mn)
+      break;	/* we've moved all elements */
+
+    /** Search for loops to rearrange: **/
+
+    while (1) {
+      INT max = k - i;
+      ++i;
+//      assert(i <= max);
+      im += ny;
+      if (im > k)
+        im -= k;
+      i2 = im;
+      if (i == i2)
+        continue;
+      if (i >= move_size) {
+        while (i2 > i && i2 < max) {
+          i1 = i2;
+          i2 = ny * i1 - k * (i1 / nx);
+          }
+        if (i2 == i)
+          break;
+        } else if (!move[i])
+        break;
+      }
+    }
+}
+
+
+bool GuidedNativeImageIO::FileFormatDescriptor
+::TestFilename(std::string fname)
+{
+  if(fname.length() == 0)
+    return false;
+
+  // Check if the filename matches the pattern
+  for(size_t i = 0; i < pattern.length(); )
+    {
+    size_t j = pattern.find(',', i);
+    string ext = "." + pattern.substr(i, j-i);
+    i+=ext.length();
+    size_t pos = fname.rfind(ext);
+    if(pos == std::string::npos)
+      continue;
+
+    if(pos == fname.length() - ext.length())
+      return true;
+    }
+  return false;
+}
+
 GuidedNativeImageIO
 ::GuidedNativeImageIO()
 {
@@ -95,7 +268,7 @@ GuidedNativeImageIO
     {
     for(int i = 0; i < FORMAT_COUNT; i++)
       m_EnumFileFormat.AddPair(
-        (FileFormat)(FORMAT_MHA + i), 
+        (FileFormat)(i),
         m_FileFormatDescrictorArray[i].name.c_str());
 
     m_EnumRawPixelType.AddPair(PIXELTYPE_CHAR, "CHAR");
@@ -206,7 +379,7 @@ GuidedNativeImageIO
     {
     case FORMAT_MHA:        m_IOBase = itk::MetaImageIO::New();          break;
     case FORMAT_NRRD:       m_IOBase = itk::NrrdImageIO::New();          break;
-    case FORMAT_ANALYZE:    m_IOBase = itk::AnalyzeImageIO::New();       break;
+    case FORMAT_ANALYZE:    m_IOBase = itk::NiftiImageIO::New();       break;
     case FORMAT_GIPL:       m_IOBase = itk::GiplImageIO::New();          break;
     case FORMAT_GE4:        m_IOBase = itk::GE4ImageIO::New();           break;
     case FORMAT_GE5:        m_IOBase = itk::GE5ImageIO::New();           break;
@@ -214,7 +387,8 @@ GuidedNativeImageIO
     case FORMAT_SIEMENS:    m_IOBase = itk::SiemensVisionImageIO::New(); break;
     case FORMAT_VTK:        m_IOBase = itk::VTKImageIO::New();           break;
     case FORMAT_VOXBO_CUB:  m_IOBase = itk::VoxBoCUBImageIO::New();      break;
-    case FORMAT_DICOM:      m_IOBase = itk::GDCMImageIO::New();          break;
+    case FORMAT_DICOM_DIR:
+    case FORMAT_DICOM_FILE: m_IOBase = itk::GDCMImageIO::New();          break;
     case FORMAT_RAW:
       {
       // Get the Raw header sub-folder
@@ -236,7 +410,9 @@ GuidedNativeImageIO
         case PIXELTYPE_FLOAT:  CreateRawImageIO<float>(fldRaw);          break;
         case PIXELTYPE_DOUBLE: CreateRawImageIO<double>(fldRaw);         break;
         default:
-          throw itk::ExceptionObject("Unsupported Pixel Type when reading Raw File");
+          throw IRISException("Error: Unsupported voxel type."
+                              "Unsupported voxel type ('%s') when reading raw file.",
+                              folder["Raw.PixelType"][""]);
         }
       }
       break;
@@ -251,88 +427,147 @@ GuidedNativeImageIO
 }
 
 
-   
-
-
-
-
-
-
-
 void
 GuidedNativeImageIO
-::ReadNativeImage(const char *FileName, Registry &folder)
+::ReadNativeImageHeader(const char *FileName, Registry &folder)
 {
+  // Save the hints
+  m_Hints = folder;
+
   // Create the header corresponding to the current image type
-  CreateImageIO(FileName, folder, true);
+  CreateImageIO(FileName, m_Hints, true);
   if(!m_IOBase)
-    throw itk::ExceptionObject("Unsupported image file type");
+    throw IRISException("Error: Unsupported or missing image file format. "
+                        "ITK-SNAP failed to create an ImageIO object for the "
+                        "image '%s' using format '%s'.",
+                        FileName, m_Hints["Format"][""]);
 
   // Read the information about the image
-  if(m_FileFormat == FORMAT_DICOM)
+  if(m_FileFormat == FORMAT_DICOM_DIR)
     {
-    // Check if the array of filenames has been provided for us
-    m_DICOMFiles = 
-      folder.Folder("DICOM.SliceFiles").GetArray(std::string("NULL"));
-
-    // If no filenames were specified, read the first series in the directory
-    if(m_DICOMFiles.size() == 0)
+    // Get the directory where to search for the series
+    std::string SeriesDir = FileName;
+    if(!itksys::SystemTools::FileIsDirectory(FileName))
+      SeriesDir = itksys::SystemTools::GetParentDirectory(FileName);
+
+    // NOTE: for the time being, we are relying on GDCMSeriesFileNames for
+    // proper sorting of the DICOM data. This is marked as deprecated in GDCM 2
+    if(m_GDCMSeries.IsNull() || m_GDCMSeriesDirectory != SeriesDir)
       {
-      // Create a names generator. The input must be a directory 
-      typedef itk::GDCMSeriesFileNames NamesGeneratorType;
-      NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
-      nameGenerator->SetDirectory(FileName);
+      m_GDCMSeries = itk::GDCMSeriesFileNames::New();
+      m_GDCMSeries->SetUseSeriesDetails(true);
+      m_GDCMSeries->SetDirectory(SeriesDir);
+      m_GDCMSeriesDirectory = SeriesDir;
+      }
 
+    // Select which series
+    std::string SeriesID = m_Hints["DICOM.SeriesId"][""];
+    if(SeriesID.length() == 0)
+      {
       // Get the list of series in the directory
-      const itk::SerieUIDContainer &sids = nameGenerator->GetSeriesUIDs();
+      const itk::SerieUIDContainer &sids = m_GDCMSeries->GetSeriesUIDs();
 
       // There must be at least of series
       if(sids.size() == 0)
-        throw itk::ExceptionObject("No DICOM series found in the DICOM directory");
-    
+        throw IRISException("Error: DICOM series not found. "
+                            "Directory '%s' does not appear to contain a "
+                            "series of DICOM images.",FileName);
+
       // Read the first DICOM series in the directory
-      m_DICOMFiles = nameGenerator->GetFileNames(sids.front().c_str());
+      SeriesID = sids.front();
       }
 
+    // Use the series provided by the user
+    m_DICOMFiles = m_GDCMSeries->GetFileNames(SeriesID.c_str());
+
     // Read the information from the first filename
     if(m_DICOMFiles.size() == 0)
-      throw itk::ExceptionObject("No DICOM files found in the DICOM directory");
+      throw IRISException("Error: DICOM series not found. "
+                          "Directory '%s' does not appear to contain a "
+                          "series of DICOM images.",FileName);
+
     m_IOBase->SetFileName(m_DICOMFiles[0]);
     m_IOBase->ReadImageInformation();
     }
   else
     {
+    // Check that the reader actually supports this format. We skip this for
+    // the RAW format, because it stupidly refuses to read files named other
+    // than with the .raw extension
+    if(m_FileFormat != FORMAT_RAW && !m_IOBase->CanReadFile(FileName))
+      throw IRISException(
+          "Error: Wrong Format. "
+          "The IO library for the format '%s' can not read the image file.",
+          m_Hints["Format"][""]);
     m_IOBase->SetFileName(FileName);
     m_IOBase->ReadImageInformation();
     }
 
-  // Based on the component type, read image in native mode
-  switch(m_IOBase->GetComponentType()) 
+  // Get the data dimensions
+  int ncomp = m_IOBase->GetNumberOfComponents();
+
+  // Set the dimensions (if 2D image, we set last dim to 1)
+  m_NativeDimensions.fill(1);
+  for(size_t i = 0; i < m_IOBase->GetNumberOfDimensions(); i++)
     {
-    case itk::ImageIOBase::UCHAR:  DoReadNative<unsigned char>(FileName, folder);  break;
-    case itk::ImageIOBase::CHAR:   DoReadNative<signed char>(FileName, folder);    break;
-    case itk::ImageIOBase::USHORT: DoReadNative<unsigned short>(FileName, folder); break;
-    case itk::ImageIOBase::SHORT:  DoReadNative<signed short>(FileName, folder);   break;
-    case itk::ImageIOBase::UINT:   DoReadNative<unsigned int>(FileName, folder);   break;
-    case itk::ImageIOBase::INT:    DoReadNative<signed int>(FileName, folder);     break;
-    case itk::ImageIOBase::ULONG:  DoReadNative<unsigned long>(FileName, folder);  break;
-    case itk::ImageIOBase::LONG:   DoReadNative<signed long>(FileName, folder);    break;
-    case itk::ImageIOBase::FLOAT:  DoReadNative<float>(FileName, folder);          break;
-    case itk::ImageIOBase::DOUBLE: DoReadNative<double>(FileName, folder);         break;
-    default: 
-      throw itk::ExceptionObject("Unknown Pixel Type when reading image");
+    if(i < 3)
+      m_NativeDimensions[i] = m_IOBase->GetDimensions(i);
+    else
+      ncomp *= m_IOBase->GetDimensions(i);
     }
 
-  // Get rid of the IOBase, it may store useless data (in case of NIFTI)
+  // Extract properties from IO base
   m_NativeType = m_IOBase->GetComponentType();
-  m_NativeComponents = m_IOBase->GetNumberOfComponents();
+  m_NativeComponents = ncomp;
   m_NativeTypeString = m_IOBase->GetComponentTypeAsString(m_NativeType);
   m_NativeFileName = m_IOBase->GetFileName();
   m_NativeByteOrder = m_IOBase->GetByteOrder();
   m_NativeSizeInBytes = m_IOBase->GetImageSizeInBytes();
+
+  // Also pull out a nickname for this file, if it's in the folder
+  m_NativeNickname = m_Hints["Nickname"][""];
+}
+
+void
+GuidedNativeImageIO
+::ReadNativeImageData()
+{
+  const char *fname = m_NativeFileName.c_str();
+
+  // Based on the component type, read image in native mode
+  switch(m_IOBase->GetComponentType())
+    {
+    case itk::ImageIOBase::UCHAR:  DoReadNative<unsigned char>(fname, m_Hints);  break;
+    case itk::ImageIOBase::CHAR:   DoReadNative<signed char>(fname, m_Hints);    break;
+    case itk::ImageIOBase::USHORT: DoReadNative<unsigned short>(fname, m_Hints); break;
+    case itk::ImageIOBase::SHORT:  DoReadNative<signed short>(fname, m_Hints);   break;
+    case itk::ImageIOBase::UINT:   DoReadNative<unsigned int>(fname, m_Hints);   break;
+    case itk::ImageIOBase::INT:    DoReadNative<signed int>(fname, m_Hints);     break;
+    case itk::ImageIOBase::ULONG:  DoReadNative<unsigned long>(fname, m_Hints);  break;
+    case itk::ImageIOBase::LONG:   DoReadNative<signed long>(fname, m_Hints);    break;
+    case itk::ImageIOBase::FLOAT:  DoReadNative<float>(fname, m_Hints);          break;
+    case itk::ImageIOBase::DOUBLE: DoReadNative<double>(fname, m_Hints);         break;
+    default:
+      throw IRISException("Error: Unsupported voxel type."
+                          "Unsupported voxel type ('%s') when reading raw file.",
+                          m_IOBase->GetComponentTypeAsString(
+                            m_IOBase->GetComponentType()).c_str());
+    }
+
+  // Get rid of the IOBase, it may store useless data (in case of NIFTI)
   m_IOBase = NULL;
 }
 
+void
+GuidedNativeImageIO
+::ReadNativeImage(const char *FileName, Registry &folder)
+{
+  this->ReadNativeImageHeader(FileName, folder);
+  this->ReadNativeImageData();
+}
+
+#include <itkTimeProbe.h>
+
 template<class TScalar>
 void
 GuidedNativeImageIO
@@ -342,10 +577,10 @@ GuidedNativeImageIO
   typedef itk::VectorImage<TScalar, 3> NativeImageType;
 
   // There is a special handler for the DICOM case!
-  if(m_FileFormat == FORMAT_DICOM && m_DICOMFiles.size() > 1)
+  if(m_FileFormat == FORMAT_DICOM_DIR && m_DICOMFiles.size() > 1)
     {
     // It seems that ITK can't yet read DICOM into a VectorImage. 
-    typedef itk::OrientedImage<TScalar, 3> GreyImageType;
+    typedef itk::Image<TScalar, 3> GreyImageType;
 
     // Create an image series reader 
     typedef itk::ImageSeriesReader<GreyImageType> ReaderType;
@@ -362,14 +597,25 @@ GuidedNativeImageIO
     
     // Update
     reader->Update();
+    typename GreyImageType::Pointer scalar = reader->GetOutput();
+
+    // Convert the image into VectorImage format. Do this in-place to avoid
+    // allocating memory pointlessly
+    typename NativeImageType::Pointer vector = NativeImageType::New();
+    m_NativeImage = vector;
 
-    // Convert the image into VectorImage format
-    typedef itk::ImageToVectorImageFilter<GreyImageType> FilterType;
-    typename FilterType::Pointer flt = FilterType::New();
-    flt->SetInput(0, reader->GetOutput());
-    flt->Update();
-    m_NativeImage = flt->GetOutput();
-    m_NativeImage->SetDirection(flt->GetOutput()->GetDirection());
+    vector->CopyInformation(scalar);
+    vector->SetRegions(scalar->GetBufferedRegion());
+
+    typedef typename NativeImageType::PixelContainer PixConType;
+    typename PixConType::Pointer pc = PixConType::New();
+    pc->SetImportPointer(
+          reinterpret_cast<TScalar *>(scalar->GetBufferPointer()),
+          scalar->GetBufferedRegion().GetNumberOfPixels(), true);
+    vector->SetPixelContainer(pc);
+
+    // Prevent the container from being deleted
+    scalar->GetPixelContainer()->SetContainerManageMemory(false);
 
     // Copy the metadata from the first scan in the series
     const typename ReaderType::DictionaryArrayType *darr = 
@@ -394,8 +640,8 @@ GuidedNativeImageIO
     typename NativeImageType::SpacingType spc;   spc.Fill(1.0);
     typename NativeImageType::DirectionType dir; dir.SetIdentity();    
     
-    size_t nd = m_IOBase->GetNumberOfDimensions(); 
-    if(nd > 3) nd = 3;
+    size_t nd_actual = m_IOBase->GetNumberOfDimensions();
+    size_t nd = (nd_actual > 3) ? 3 : nd_actual;
     
     for(unsigned int i = 0; i < nd; i++)
       {
@@ -411,23 +657,74 @@ GuidedNativeImageIO
     image->SetDirection(dir);
     image->SetMetaDataDictionary(m_IOBase->GetMetaDataDictionary());
 
+    // Fold in any higher number of dimensions as additional components.
+    int ncomp = m_IOBase->GetNumberOfComponents();
+    if(nd_actual > nd)
+      {
+      for(int i = nd; i < nd_actual; i++)
+        ncomp *= m_IOBase->GetDimensions(i);
+      }
+
     // Set the regions and allocate
     typename NativeImageType::RegionType region;
     typename NativeImageType::IndexType index = {{0, 0, 0}};
     region.SetIndex(index);
     region.SetSize(dim);
     image->SetRegions(region);
-    image->SetVectorLength(m_IOBase->GetNumberOfComponents());
+    image->SetVectorLength(ncomp);
     image->Allocate();
 
     // Set the IO region
-    itk::ImageIORegion ioRegion(3);
-    itk::ImageIORegionAdaptor<3>::Convert(region, ioRegion, index);
-    m_IOBase->SetIORegion(ioRegion);
+    if(nd_actual <= 3)
+      {
+      // This is the old code, which we preserve
+      itk::ImageIORegion ioRegion(3);
+      itk::ImageIORegionAdaptor<3>::Convert(region, ioRegion, index);
+      m_IOBase->SetIORegion(ioRegion);
+      }
+    else
+      {
+      itk::ImageIORegion ioRegion(nd_actual);
+      itk::ImageIORegion::IndexType ioIndex;
+      itk::ImageIORegion::SizeType ioSize;
+      for(int i = 0; i < nd_actual; i++)
+        {
+        ioIndex.push_back(0);
+        ioSize.push_back(m_IOBase->GetDimensions(i));
+        }
+      ioRegion.SetIndex(ioIndex);
+      ioRegion.SetSize(ioSize);
+      m_IOBase->SetIORegion(ioRegion);
+      }
 
     // Read the image into the buffer
     m_IOBase->Read(image->GetBufferPointer());
     m_NativeImage = image;
+
+    // If the image is 4-dimensional or more, we must perform an in-place transpose
+    // of the image. The fourth dimension is the one that varies fastest, and in our
+    // representation, the image is represented as a VectorImage, where the components
+    // of each voxel are the thing that moves fastest. The problem can be represented as
+    // a transpose of a N x M array, where N = dimX*dimY*dimZ and M = dimW
+    if(nd_actual > 3)
+      {
+      long N = dim[0] * dim[1] * dim[2];
+      long M = ncomp;
+      long move_size = (2 * M) * sizeof(TScalar);
+      char *move = new char[move_size];
+      TScalar buffer[2];
+
+      // TODO: this is a pretty slow routine. It would be nice to find somehting a little
+      // faster than this. But at least we can read 4D data now
+      itk::TimeProbe probe;
+      probe.Start();
+      transpose_toms513(image->GetBufferPointer(), M, N, move, move_size, buffer);
+      probe.Stop();
+
+      std::cout << "Transpose of " << N << " by " << M << " matrix computed in " << probe.GetTotal() << " sec." << std::endl;
+      delete move;
+      }
+
     
     /*
     typedef ImageFileReader<NativeImageType> ReaderType;
@@ -484,16 +781,16 @@ GuidedImageIO<TPixel>
 }
 */
 
-template<typename TPixel>
+template<typename TImageType>
 void
 GuidedNativeImageIO
-::SaveImage(const char *FileName, Registry &folder, itk::Image<TPixel,3> *image)
+::SaveImage(const char *FileName, Registry &folder, TImageType *image)
 {
   // Create an Image IO based on the folder
   CreateImageIO(FileName, folder, false);
 
   // Save the image
-  typedef itk::ImageFileWriter< itk::Image<TPixel,3> > WriterType;
+  typedef itk::ImageFileWriter<TImageType> WriterType;
   typename WriterType::Pointer writer = WriterType::New();
   
   writer->SetFileName(FileName);
@@ -513,19 +810,14 @@ GuidedNativeImageIO
  * ADAPTER OBJECTS TO CAST NATIVE IMAGE TO GIVEN IMAGE
  ****************************************************************************/
 
-template<typename TPixel>
-typename RescaleNativeImageToScalar<TPixel>::OutputImageType *
-RescaleNativeImageToScalar<TPixel>::operator()(GuidedNativeImageIO *nativeIO)
+template<class TOutputImage>
+typename RescaleNativeImageToIntegralType<TOutputImage>::OutputImageType *
+RescaleNativeImageToIntegralType<TOutputImage>::operator()(
+    GuidedNativeImageIO *nativeIO)
 {
   // Get the native image pointer
   itk::ImageBase<3> *native = nativeIO->GetNativeImage();
 
-  // Allocate the output image
-  m_Output = OutputImageType::New();
-  m_Output->CopyInformation(native);
-  m_Output->SetMetaDataDictionary(native->GetMetaDataDictionary());
-  m_Output->SetRegions(native->GetBufferedRegion());
-
   // Cast image from native format to TPixel
   itk::ImageIOBase::IOComponentType itype = nativeIO->GetComponentTypeInNativeImage();
   switch(itype) 
@@ -541,161 +833,214 @@ RescaleNativeImageToScalar<TPixel>::operator()(GuidedNativeImageIO *nativeIO)
     case itk::ImageIOBase::FLOAT:  DoCast<float>(native);           break;
     case itk::ImageIOBase::DOUBLE: DoCast<double>(native);          break;
     default: 
-      throw itk::ExceptionObject("Unknown Pixel Type when reading image");
+      throw IRISException("Unknown pixel type when reading image");
     }
 
   // Return the output image
   return m_Output;
 }
 
-template<typename TPixel>
+template<typename TPixel, typename TNative>
+class RescaleScalarNativeImageToScalarFunctor
+{
+public:
+
+  RescaleScalarNativeImageToScalarFunctor(double shift, double scale)
+    : m_Shift(shift), m_Scale(scale) {}
+
+  RescaleScalarNativeImageToScalarFunctor()
+    : m_Shift(0), m_Scale(1) {}
+
+  void operator()(TNative *src, TPixel *trg)
+  {
+    *trg = (TPixel) ((*src + m_Shift) * m_Scale + 0.5);
+  }
+
+  size_t GetNumberOfDimensions() { return 1; }
+
+protected:
+
+  double m_Shift, m_Scale;
+
+};
+
+
+template<typename TPixel, typename TNative>
+class RescaleVectorNativeImageToScalarFunctor
+{
+public:
+
+  RescaleVectorNativeImageToScalarFunctor(double shift, double scale, size_t ncomp)
+    : m_Shift(shift), m_Scale(scale), m_Components(ncomp) {}
+
+  RescaleVectorNativeImageToScalarFunctor()
+    : m_Shift(0), m_Scale(1), m_Components(0) {}
+
+  void operator()(TNative *src, TPixel *trg)
+  {
+    double x = 0;
+    for(size_t i = 0; i < m_Components; i++)
+      x += src[i] * src[i];
+    *trg = (TPixel) ((sqrt(x) + m_Shift) * m_Scale + 0.5);
+  }
+
+  size_t GetNumberOfDimensions() { return m_Components; }
+
+protected:
+
+  double m_Shift, m_Scale;
+  size_t m_Components;
+
+};
+
+template<typename TPixel, typename TNative>
+class RescaleVectorNativeImageToVectorFunctor
+{
+public:
+
+  typedef TPixel PixelType;
+
+  RescaleVectorNativeImageToVectorFunctor(double shift, double scale)
+    : m_Shift(shift), m_Scale(scale) {}
+
+  RescaleVectorNativeImageToVectorFunctor()
+    : m_Shift(0), m_Scale(1) {}
+
+  void operator()(TNative *src, TPixel *trg)
+  {
+    *trg = (TPixel) ((*src + m_Shift) * m_Scale + 0.5);
+  }
+
+protected:
+
+  double m_Shift, m_Scale;
+
+};
+
+
+
+
+template<class TOutputImage>
 template<typename TNative>
 void
-RescaleNativeImageToScalar<TPixel>
+RescaleNativeImageToIntegralType<TOutputImage>
 ::DoCast(itk::ImageBase<3> *native)
 {
   // Get the native image
   typedef itk::VectorImage<TNative, 3> InputImageType;
   typedef itk::ImageRegionConstIterator<InputImageType> InputIterator;
-  typename InputImageType::Pointer input = 
-    dynamic_cast<InputImageType *>(native);
+  SmartPtr<InputImageType> input = dynamic_cast<InputImageType *>(native);
   assert(input);
 
-  // Special case: native image is the same as target image
-  if(typeid(TPixel) == typeid(TNative))
-    {
-    typename OutputImageType::PixelContainer *inbuff = 
-      dynamic_cast<typename OutputImageType::PixelContainer *>(input->GetPixelContainer());
-    assert(inbuff);
-    m_Output->SetPixelContainer(inbuff);
-    m_NativeScale = 1.0;
-    m_NativeShift = 0.0;
-    return;
-    }
-
-  // Otherwise, allocate the buffer in the output image
-  m_Output->Allocate();
-
-  // We must compute the range of the input data
-  size_t nvoxels = input->GetBufferedRegion().GetNumberOfPixels();
+  // Get the number of components in the native image
   size_t ncomp = input->GetNumberOfComponentsPerPixel();
-  double imin = itk::NumericTraits<double>::max();
-  double imax = -itk::NumericTraits<double>::max();
-  TPixel omax = itk::NumericTraits<TPixel>::max();
-  TPixel omin = itk::NumericTraits<TPixel>::min();
-
-  if(ncomp > 1)
-    {
-    for(InputIterator it(input, input->GetBufferedRegion()); !it.IsAtEnd(); ++it)
-      {
-      double mag = it.Get().GetSquaredNorm();
-      if(mag < imin) imin = mag;
-      if(mag > imax) imax = mag;
-      }
-    imin = sqrt(imin);
-    imax = sqrt(imax);
-    }
-  else
-    {
-    for(size_t i = 0; i < nvoxels; i++)
-      {
-      // Have to cast to double here
-      double val = input->GetBufferPointer()[i]; 
-      if(val < imin) imin = val;
-      if(val > imax) imax = val;
-      }
-    }
 
   // We must compute a scale and shift factor
   double scale = 1.0, shift = 0.0;
 
-  // Now we have to be careful, depending on the type of the input voxel
-  // For float and double, we map the input range into the output range
-  if(!itk::NumericTraits<TNative>::is_integer || ncomp > 1)
+  // The type of the component in the output image. Now, the output image here
+  // may be either a VectorImage or an Image.
+  typedef typename OutputImageType::InternalPixelType OutputComponentType;
+
+  // Only bother with computing the scale and shift if the types are different
+  if(typeid(OutputComponentType) != typeid(TNative))
     {
-    // Test whether the input image is actually an integer image cast to 
-    // floating point. In that case, there is no need for conversion
-    bool isint = false;
-    if(1.0 * omin <= imin && 1.0 * omax >= imax && ncomp == 1)
+    // We must compute the range of the input data
+    double imin = itk::NumericTraits<double>::max();
+    double imax = -itk::NumericTraits<double>::max();
+    OutputComponentType omax = itk::NumericTraits<OutputComponentType>::max();
+    OutputComponentType omin = itk::NumericTraits<OutputComponentType>::min();
+
+    // Iterate over all the components in the input image
+    for(InputIterator it(input, input->GetBufferedRegion()); !it.IsAtEnd(); ++it)
       {
-      isint = true;
-      for(size_t i = 0; i < nvoxels; i++)
+      typename InputImageType::PixelType pix = it.Get();
+      for(int i = 0; i < ncomp; i++)
         {
-        TNative vin = input->GetBufferPointer()[i];
-        TNative vcmp = static_cast<TNative>(static_cast<TPixel>(vin + 0.5));
-        if(vin != vcmp)
-          { isint = false; break; }
+        double val = static_cast<double>(pix[i]);
+        if(val < imin) imin = val;
+        if(val > imax) imax = val;
         }
       }
 
-    // If underlying data is really integer, no scale or shift is necessary
-    // except that to round (so floating values like 0.9999999 get mapped to 
-    // 1 not to 0
-    if(isint)
+    // Now we have to be careful, depending on the type of the input voxel
+    // For float and double, we map the input range into the output range
+    if(!itk::NumericTraits<TNative>::is_integer)
       {
-      scale = 1.0; shift = 0.0;
-      }
+      // Test whether the input image is actually an integer image cast to
+      // floating point. In that case, there is no need for conversion
+      bool isint = false;
+      if(1.0 * omin <= imin && 1.0 * omax >= imax && ncomp == 1)
+        {
+        isint = true;
+
+        for(InputIterator it(input, input->GetBufferedRegion()); !it.IsAtEnd(); ++it)
+          {
+          typename InputImageType::PixelType pix = it.Get();
+          for(int i = 0; i < ncomp; i++)
+            {
+            TNative vin = pix[i];
+            TNative vcmp = static_cast<TNative>(static_cast<OutputComponentType>(vin + 0.5));
+            if(vin != vcmp)
+              { isint = false; break; }
+            }
+          }
+        }
 
-    // If the min and max are the same, we map that value to zero
-    else if(imin == imax)
-      {
-      scale = 1.0; shift = -imax;
-      }
-    else
-      {  
-      // Compute the scaling factor to map image into output range
-      scale = (1.0 * omax - 1.0 * omin) / (imax - imin);
-      shift = omin / scale - imin;
-      }
-    }
+      // If underlying data is really integer, no scale or shift is necessary
+      // except that to round (so floating values like 0.9999999 get mapped to
+      // 1 not to 0
+      if(isint)
+        {
+        scale = 1.0; shift = 0.0;
+        }
 
-  // For integer types we only need to take action if the range is outside
-  // of the supported range. We cast to double to make sure the comparison 
-  // is valid
-  else if(1.0 * imin < 1.0 * omin || 1.0 * imax > omax)
-    {
-    // Can we solve the problem by a shift only?
-    if(1.0 * imax - 1.0 * imin <= 1.0 * omax - 1.0 * omin)
-      {
-      scale = 1.0;
-      shift = 1.0 * omin - 1.0 * imin;
+      // If the min and max are the same, we map that value to zero
+      else if(imin == imax)
+        {
+        scale = 1.0; shift = -imax;
+        }
+      else
+        {
+        // Compute the scaling factor to map image into output range
+        scale = (1.0 * omax - 1.0 * omin) / (imax - imin);
+        shift = omin / scale - imin;
+        }
       }
-    }
 
-  // Map the values from input vector image to output image. Not using
-  // iterators to increase speed and avoid unnecessary constructors
-  TNative *bn = input->GetBufferPointer();
-  TPixel *bo = m_Output->GetBufferPointer();
-  if(ncomp == 1)
-    {
-    for(size_t i = 0; i < nvoxels; i++, bn++)
+    // For integer types we only need to take action if the range is outside
+    // of the supported range. We cast to double to make sure the comparison
+    // is valid
+    else if(1.0 * imin < 1.0 * omin || 1.0 * imax > omax)
       {
-      bo[i] = (TPixel) ((*bn + shift)*scale + 0.5);
-      }
-    }
-  else
-    {
-    for(size_t i = 0; i < nvoxels; i++)
-      {
-      double val = 0.0;
-      for(size_t k = 0; k < ncomp; k++, bn++)
-        val += (*bn) * (*bn);
-      bo[1] = (TPixel) ((sqrt(val) + shift)*scale + 0.5);
+      // Can we solve the problem by a shift only?
+      if(1.0 * imax - 1.0 * imin <= 1.0 * omax - 1.0 * omin)
+        {
+        scale = 1.0;
+        shift = 1.0 * omin - 1.0 * imin;
+        }
       }
     }
 
-  // Store the shift and the scale needed to take the TPixel values 
+
+  // Store the shift and the scale needed to take the TPixel values
   // to the TNative values
   m_NativeScale = 1.0 / scale;
   m_NativeShift = - shift;
-}
-
-
 
+  // Create a cast functor. Note that if TPixel == TNative, the functor will
+  // not be used because the CastNativeImageBase::DoCast will just assign the
+  // input pixel container to the output image
+  typedef RescaleVectorNativeImageToVectorFunctor<OutputComponentType, TNative> Functor;
+  CastNativeImage<OutputImageType, Functor> caster;
+  caster.SetFunctor(Functor(shift, scale));
+  caster.template DoCast<TNative>(native);
+  m_Output = caster.m_Output;
+}
 
-template<class TPixel, class TCastFunctor>
-typename CastNativeImageBase<TPixel,TCastFunctor>::OutputImageType *
-CastNativeImageBase<TPixel,TCastFunctor>
+template<class TOutputImage, class TCastFunctor>
+typename CastNativeImage<TOutputImage,TCastFunctor>::OutputImageType *
+CastNativeImage<TOutputImage,TCastFunctor>
 ::operator()(GuidedNativeImageIO *nativeIO)
 {
   // Get the native image pointer
@@ -716,17 +1061,22 @@ CastNativeImageBase<TPixel,TCastFunctor>
     case itk::ImageIOBase::FLOAT:  DoCast<float>(native);           break;
     case itk::ImageIOBase::DOUBLE: DoCast<double>(native);          break;
     default: 
-      throw itk::ExceptionObject("Unknown Pixel Type when reading image");
+      throw IRISException("Error: Unknown pixel type when reading image."
+                          "The voxels in the image you are loading have format '%s', "
+                          "which is not supported.",
+                          nativeIO->GetComponentTypeAsStringInNativeImage().c_str());
     }
 
   // Return the output image
   return m_Output;
 }
 
-template<class TPixel, class TCastFunctor>
+#include "itkMeasurementVectorTraits.h"
+
+template<class TOutputImage, class TCastFunctor>
 template<typename TNative>
 void
-CastNativeImageBase<TPixel,TCastFunctor>
+CastNativeImage<TOutputImage,TCastFunctor>
 ::DoCast(itk::ImageBase<3> *native)
 {
   // Get the native image
@@ -735,44 +1085,252 @@ CastNativeImageBase<TPixel,TCastFunctor>
     reinterpret_cast<InputImageType *>(native);
   assert(input);
 
-  // Make sure the number of components matches
-  TCastFunctor functor;
-  
-  // If the native image does not have three components, we crash
-  if(input->GetNumberOfComponentsPerPixel() != functor.GetNumberOfDimensions())
-    throw IRISException(
-      "Can not convert image to target format (%s).\n"
-      "Image has %d components per pixel, but it should have %d components.",
-      typeid(TPixel).name(), 
-      input->GetNumberOfComponentsPerPixel(), 
-      functor.GetNumberOfDimensions() );
+  typedef typename InputImageType::PixelContainer InPixCon;
+  typedef typename OutputImageType::PixelContainer OutPixCon;
+
+  InPixCon *ipc = input->GetPixelContainer();
 
   // Allocate the output image
   m_Output = OutputImageType::New();
   m_Output->CopyInformation(native);
+  m_Output->SetMetaDataDictionary(native->GetMetaDataDictionary());
   m_Output->SetRegions(native->GetBufferedRegion());
 
+  // CAREFUL! At this point, it may be that the number of components in the
+  // output is still 1 (because the output is an itk::Image) and the number
+  // of components in the input is not 1. In that case, we can either throw
+  // an exception or use the first component of the input image to fill out
+  // the output image. For the time being, we will throw an exception.
+  int ncomp = input->GetNumberOfComponentsPerPixel();
+  int ncomp_out = m_Output->GetNumberOfComponentsPerPixel();
+  if(ncomp != ncomp_out)
+    {
+    throw IRISException("Unable to cast an input image with %d components to "
+                        "an output image with %d components", ncomp, ncomp_out);
+    }
+
   // Special case: native image is the same as target image
-  if(typeid(TPixel) == typeid(TNative))
+  if(typeid(OutputComponentType) == typeid(TNative))
     {
     typename OutputImageType::PixelContainer *inbuff = 
-      dynamic_cast<typename OutputImageType::PixelContainer *>(input->GetPixelContainer());
+      dynamic_cast<typename OutputImageType::PixelContainer *>(ipc);
     assert(inbuff);
     m_Output->SetPixelContainer(inbuff);
     return;
     }
 
+  // We are going to map data from native to target format in place in order
+  // to save memory. This way, SNAP will never use extra memory when loading
+  // an image. Some trickery is needed though.
+  size_t nvoxels = input->GetBufferedRegion().GetNumberOfPixels();
+  size_t szNative = sizeof(TNative);
+  size_t szTarget = sizeof(OutputComponentType);
+
+  // Bytes allocated in the current pixel container
+  size_t nbNative = input->GetPixelContainer()->Capacity() * szNative;
+
+  // Bytes needed to store the data in target format
+  size_t nbTarget = input->GetPixelContainer()->Size() * szTarget;
+
+  // This memory is no longer owned by the input
+  ipc->SetContainerManageMemory(false);
+
+  // Pointer to the input buffer
+  TNative *ib = ipc->GetImportPointer();
+
+  // If target is larger than native, expand the pixel container
+  if(nbNative < nbTarget)
+    {
+    // We should probably avoid this possibility by forcing at least a short
+    // type when loading char data. But if this does happen, all we need to
+    // do is increase the capacity of the native data
+    ib = reinterpret_cast<TNative *>(realloc(ib, nbTarget));
+    }
+
+  // Get a pointer to the output buffer (same as input buffer)
+  OutputComponentType *ob = reinterpret_cast<OutputComponentType *>(ib);
+
+  // Finally, we get to the code where we map from input format to the output
+  // format. Here again we have to be careful. If the native image is larger or
+  // same than the target image, we want to proceed in ascending order, since each
+  // input element will be replaced by one or more output elements. But if the
+  // native image is smaller, we want to proceed from the end of the memory
+  // block in a descending order, so that the native data is not overridden
+  unsigned long nval =  nvoxels * ncomp;
+  if(szTarget > szNative)
+    {
+    TNative *pn = ib + nval - 1;
+    OutputComponentType *pt = ob + nval - 1;
+    for(; pt >= ob; pt--, pn--)
+      m_Functor(pn, pt);
+    }
+  else
+    {
+    TNative *pn = ib;
+    OutputComponentType *pt = ob;
+    for(; pt < ob + nval; pt++, pn++)
+      m_Functor(pn, pt);
+    }
+
+  // If needed, squeeze the memory
+  if(nbTarget < nbNative)
+    ob = reinterpret_cast<OutputComponentType *>(realloc(ob, nbTarget));
+
+  // Create a new container wrapped around the same chunk of memory as the
+  // native image. The size we pass in here is the number of elements that
+  // have been already allocated. We will shrink that memory later
+  SmartPtr<OutPixCon> pc = OutPixCon::New();
+  pc->SetImportPointer(ob, nval, true);
+
   // Otherwise, allocate the buffer in the output image
-  m_Output->Allocate();
+  m_Output->SetPixelContainer(pc);
+}
 
-  // We simply cast every component of every pixel from input to output
-  size_t nvoxels = native->GetBufferedRegion().GetNumberOfPixels();
-  size_t ncomp = functor.GetNumberOfDimensions();
+GuidedNativeImageIO::FileFormat
+GuidedNativeImageIO::GuessFormatForFileName(
+    const std::string &fname, bool checkMagic)
+{
+  if(checkMagic)
+    {
+    // Read the first few bytes from the file. We use zlib to automatically
+    // handle gz-compressed data.
+    const int buf_size=1024;
+    char buffer[buf_size];
+
+    gzFile gz = gzopen(fname.c_str(), "rb");
+    bool havebuff = (gz!=NULL) && (buf_size==gzread(gz,buffer,buf_size));
+    gzclose(gz);
+
+    // Now we will check known magic numbers, especially for formats that
+    // are primary formats supported by SNAP
+
+    // Check for DICOM
+    if(havebuff && !strncmp(buffer+128,"DICM",4))
+      {
+      // PY: Now that I cleaned up the DICOM reader, we should never default
+      // to single DICOM file anymore. That's just too annoying
+      return FORMAT_DICOM_DIR;
+      }
+
+    // Check for NIFTI. This is important because .hdr files can be either
+    // NIFTI or Analyze, so we have to know what we are dealing with.
+    if(havebuff && buffer[344]==0x6E && buffer[347]==0x00 &&
+       (buffer[345]==0x69 || buffer[345]==0x2B) &&
+       buffer[346] > 0x30 && buffer[346] <= 0x39)
+      return FORMAT_NIFTI;
+
+    // Potentially, we could check for other formats here too, but this is
+    // not as high priority. For one thing, unlike DICOM and NIFTI, the other
+    // formats are well defined by their extension.
+    }
+
+  // The rest of this method checks by extension
+  for(unsigned int i = 0; i < FORMAT_COUNT; i++)
+    {
+    // Get the format descriptor
+    FileFormat fmt = static_cast<FileFormat>(i);
+    FileFormatDescriptor fd = GetFileFormatDescriptor(fmt);
 
-  TNative *bn = input->GetBufferPointer();
-  TPixel *bo = m_Output->GetBufferPointer();
-  for(size_t i = 0; i < nvoxels; i++, bn+=ncomp, bo++)
-    functor(bn, bo);
+    // Check if there is a filename match
+    if(fd.TestFilename(fname))
+      {
+      return fmt;
+      }
+    }
+
+  // Nothing matched
+  return FORMAT_COUNT;
+}
+
+
+const gdcm::Tag GuidedNativeImageIO::m_tagRows(0x0028, 0x0010);
+const gdcm::Tag GuidedNativeImageIO::m_tagCols(0x0028, 0x0011);
+const gdcm::Tag GuidedNativeImageIO::m_tagDesc(0x0008, 0x103e);
+const gdcm::Tag GuidedNativeImageIO::m_tagTextDesc(0x0028, 0x0010);
+const gdcm::Tag GuidedNativeImageIO::m_tagSeriesInstanceUID(0x0020,0x000E);
+const gdcm::Tag GuidedNativeImageIO::m_tagSeriesNumber(0x0020,0x0011);
+const gdcm::Tag GuidedNativeImageIO::m_tagAcquisitionNumber(0x0020,0x0012);
+const gdcm::Tag GuidedNativeImageIO::m_tagInstanceNumber(0x0020,0x0013);
+
+
+
+void GuidedNativeImageIO::ParseDicomDirectory(
+    const std::string &dir,
+    GuidedNativeImageIO::RegistryArray &reg,
+    const GuidedNativeImageIO::DicomRequest &req)
+{
+  // Must have a directory
+  if(!itksys::SystemTools::FileIsDirectory(dir.c_str()))
+    throw IRISException(
+        "Error: Not a directory. "
+        "Trying to look for DICOM series in '%s', which is not a directory",
+        dir.c_str());
+
+  // Use the ITK stuff for parsing
+  if(m_GDCMSeries.IsNull() || m_GDCMSeriesDirectory != dir)
+    {
+    m_GDCMSeries = itk::GDCMSeriesFileNames::New();
+    m_GDCMSeries->SetUseSeriesDetails(true);
+    m_GDCMSeries->SetDirectory(dir);
+    m_GDCMSeriesDirectory = dir;
+    }
+
+  // List all the unique series ids
+  const itk::SerieUIDContainer uids = m_GDCMSeries->GetSeriesUIDs();
+  for(int i = 0; i < uids.size(); i++)
+    {
+    // Get the filenames for this serie
+    const itk::FilenamesContainer &fc = m_GDCMSeries->GetFileNames(uids[i]);
+    if(!fc.size())
+      continue;
+
+    // Initialize the registry for this parsing
+    Registry r;
+    r["SeriesId"] << uids[i];
+
+    // Get tags for this file
+    std::set<gdcm::Tag> tagset;
+    tagset.insert(m_tagRows);
+    tagset.insert(m_tagCols);
+    tagset.insert(m_tagSeriesNumber);
+    tagset.insert(m_tagDesc);
+
+    // Read the tags
+    gdcm::Reader reader;
+    reader.SetFileName(fc.front().c_str());
+    bool read = false;
+
+    try { read = reader.ReadSelectedTags(tagset); }
+    catch(...) { read = false; }
+
+    if(read)
+      {
+      gdcm::StringFilter sf;
+      sf.SetFile(reader.GetFile());
+
+      // Read series description
+      r["SeriesDescription"] << sf.ToString(m_tagDesc);
+      r["SeriesNumber"] << sf.ToString(m_tagSeriesNumber);
+
+      // Read the dimensions
+      ostringstream oss;
+      oss << sf.ToString(m_tagRows) << " x "
+          << sf.ToString(m_tagCols) << " x "
+          << fc.size();
+
+      r["Dimensions"] << oss.str();
+      r["NumberOfImages"] << fc.size();
+
+      // Add the registry to the list
+      reg.push_back(r);
+      }
+    }
+  
+  // Complain if no series have been found
+  if(reg.size() == 0)
+    throw IRISException(
+        "Error: DICOM series not found. "
+        "Directory '%s' does not appear to contain a DICOM series.", dir.c_str());
 }
 
 /*
@@ -845,10 +1403,14 @@ CastNativeImageToScalar<TPixel>
 
 */
 
-template class RescaleNativeImageToScalar<GreyType>;
-template class CastNativeImageBase<RGBType, CastToArrayFunctor<RGBType, 3> >;
-template class CastNativeImageBase<LabelType, CastToScalarFunctor<LabelType> >;
-template class CastNativeImageBase<float, CastToScalarFunctor<float> >;
+template class RescaleNativeImageToIntegralType<itk::Image<GreyType, 3> >;
+template class RescaleNativeImageToIntegralType<itk::VectorImage<GreyType, 3> >;
+
+template class CastNativeImage<itk::Image<unsigned short, 3> >;
+
+// template class CastNativeImageBase<RGBType, CastToArrayFunctor<RGBType, 3> >;
+// template class CastNativeImageBase<LabelType, CastToScalarFunctor<LabelType> >;
+// template class CastNativeImageBase<float, CastToScalarFunctor<float> >;
 
 /*
 template class CastNativeImageToRGB<RGBType>; 
@@ -861,3 +1423,5 @@ template void GuidedNativeImageIO::SaveImage(const char *, Registry &, itk::Imag
 template void GuidedNativeImageIO::SaveImage(const char *, Registry &, itk::Image<float,3> *);
 template void GuidedNativeImageIO::SaveImage(const char *, Registry &, itk::Image<RGBType,3> *);
 
+
+
diff --git a/Logic/ImageWrapper/GuidedNativeImageIO.h b/Logic/ImageWrapper/GuidedNativeImageIO.h
index b6984d6..b077761 100755
--- a/Logic/ImageWrapper/GuidedNativeImageIO.h
+++ b/Logic/ImageWrapper/GuidedNativeImageIO.h
@@ -37,9 +37,13 @@
 
 #include "Registry.h"
 #include "itkSmartPointer.h"
-#include "itkOrientedImage.h"
+#include "itkImage.h"
 #include "itkImageIOBase.h"
+#include "itkVectorImage.h"
+#include "itkGDCMSeriesFileNames.h"
+#include "gdcmTag.h"
 
+  
 namespace itk
 {
   template<class TPixel, unsigned int VDim> class Image;
@@ -53,14 +57,19 @@ namespace itk
  * as explicit IO type, and for some types such as raw, the necessary additional
  * information.
  */
-class GuidedNativeImageIO
+class GuidedNativeImageIO : public itk::Object
 {
 public:
 
+  irisITKObjectMacro(GuidedNativeImageIO, itk::Object)
+
   enum FileFormat {
-    FORMAT_MHA=0, FORMAT_GIPL, FORMAT_RAW, FORMAT_ANALYZE,
-    FORMAT_DICOM, FORMAT_GE4, FORMAT_GE5, FORMAT_NIFTI, FORMAT_SIEMENS, 
-    FORMAT_VTK, FORMAT_VOXBO_CUB, FORMAT_NRRD, FORMAT_COUNT};
+    FORMAT_ANALYZE=0,
+    FORMAT_DICOM_DIR,       // A directory containing multiple DICOM files
+    FORMAT_DICOM_FILE,      // A single DICOM file
+    FORMAT_GE4, FORMAT_GE5, FORMAT_GIPL,
+    FORMAT_MHA, FORMAT_NIFTI, FORMAT_NRRD, FORMAT_RAW, FORMAT_SIEMENS,
+    FORMAT_VOXBO_CUB, FORMAT_VTK, FORMAT_COUNT};
 
   enum RawPixelType {
     PIXELTYPE_UCHAR=0, PIXELTYPE_CHAR, PIXELTYPE_USHORT, PIXELTYPE_SHORT, 
@@ -79,8 +88,11 @@ public:
     bool can_store_orientation;
     bool can_store_float;
     bool can_store_short;
+
+    bool TestFilename(std::string fname);
   };
 
+
   // Image type. This is only for 3D images.
   typedef itk::ImageIOBase IOBase;
   typedef itk::SmartPointer<IOBase> IOBasePointer;
@@ -88,10 +100,6 @@ public:
   typedef itk::ImageBase<3> ImageBase;
   typedef itk::SmartPointer<ImageBase> ImageBasePointer;
 
-  GuidedNativeImageIO();
-  virtual ~GuidedNativeImageIO()
-    { DeallocateNativeImage(); }
-
   /**
    * This method loads an image from the given filename. A registry can be 
    * supplied to assist the loading. The registry specifies the desired IO
@@ -103,12 +111,25 @@ public:
    */
   void ReadNativeImage(const char *FileName, Registry &folder);
 
+  void ReadNativeImageHeader(const char *FileName, Registry &folder);
+
+  void ReadNativeImageData();
+
   /**
    * Get the number of components in the native image read by ReadNativeImage.
    */
   size_t GetNumberOfComponentsInNativeImage() const;
 
   /**
+    Access the IO header stored in the IO object. This is only temporarily
+    available between calls to ReadNativeImageHeader() and ReadNativeImageData().
+    The purpose is to allow users to check the validity of the header before
+    actually loading the data completely.
+    */
+  itk::ImageIOBase *GetIOBase()
+    { return m_IOBase; }
+
+  /**
    * Get the component type in the native image
    */
   itk::ImageIOBase::IOComponentType GetComponentTypeInNativeImage() const
@@ -126,7 +147,11 @@ public:
   unsigned long GetFileSizeOfNativeImage() const
     { return m_NativeSizeInBytes; }
 
+  std::string GetNicknameOfNativeImage() const
+    { return m_NativeNickname; }
 
+  Vector3ui GetDimensionsOfNativeImage() const
+    { return m_NativeDimensions; }
 
   /**
    * This method returns the image internally stored in this object. This is
@@ -160,8 +185,8 @@ public:
    * Save an image using the Registry folder to specify parameters. This method
    * is templated over the image type.
    */
-  template<typename TPixel>
-    void SaveImage(const char *FileName, Registry &folder, itk::Image<TPixel,3> *image);
+  template<class TImageType>
+    void SaveImage(const char *FileName, Registry &folder, TImageType *image);
 
   /** Parse registry to get file format */
   static FileFormat GetFileFormat(Registry &folder, FileFormat dflt = FORMAT_COUNT);
@@ -173,23 +198,70 @@ public:
   static FileFormatDescriptor GetFileFormatDescriptor(FileFormat fmt)
     { return m_FileFormatDescrictorArray[fmt]; }
 
+  /**
+    Determine file format for a filename. This method can optionally try to
+    open the file and scan the magic number, for the formats that are known
+    */
+  static FileFormat GuessFormatForFileName(
+      const std::string &string, bool checkMagic);
+
   /** Parse registry to get pixel type of raw file */
   static RawPixelType GetPixelType(Registry &folder, RawPixelType dflt = PIXELTYPE_COUNT);
 
   /** Set the file format in a registry */
   static void SetPixelType(Registry &folder, RawPixelType type);
 
-  // Get the output of the last operation
-  // irisGetMacro(IOBase, itk::ImageIOBase *);    
+  /** A field used to request DICOM fields */
+  struct DicomRequestField
+  {
+    short group, elem;
+    std::string code;
+    DicomRequestField(short g, short e, std::string c)
+      : group(g), elem(e), code(c) {}
+    DicomRequestField()
+      : group(0), elem(0) {}
+  };
 
-private:
-  
-  /** 
+  /** A parameter for ParseDicomDirectory */
+  typedef std::vector<DicomRequestField> DicomRequest;
+
+  /** Output for ParseDicomDirectory */
+  typedef std::vector<Registry> RegistryArray;
+
+  /**
+   * Get series information from a DICOM directory. This will list all the
+   * files in the DICOM directory and generate a registry for each series in
+   * the directory. By default, the following registry entries are generated
+   * for each series:
+   *   - SeriesDescription
+   *   - Dimensions
+   *   - NumberOfImages
+   *   - SeriesId
+   *   - SeriesFiles (an array with filenames)
+   * You can also ask for additional DICOM entries to be extracted by giving
+   * a list of DICOM keys in the third optional parameter.
+   */
+  void ParseDicomDirectory(
+      const std::string &dir,
+      RegistryArray &reg,
+      const DicomRequest &req = DicomRequest());
+
+
+  /**
    * Create an ImageIO object using a registry folder. Second parameter is
    * true for reading the file, false for writing the file
    */
   void CreateImageIO(const char *fname, Registry &folder, bool read);
 
+  // Get the output of the last operation
+  // irisGetMacro(IOBase, itk::ImageIOBase *);    
+
+protected:
+
+  GuidedNativeImageIO();
+  virtual ~GuidedNativeImageIO()
+    { DeallocateNativeImage(); }
+
   /** Templated function to create RAW image IO */
   template <typename TRaw> void CreateRawImageIO(Registry &folder);
 
@@ -197,21 +269,33 @@ private:
   template <typename TScalar> void DoReadNative(const char *fname, Registry &folder);
 
   /** 
-   * This is a vector image in native format. It stores the data read from the
-   * image file. The user must cast it to a desired type to use it.
+   This is a vector image in native format. It stores the data read from the
+   image file. The user must cast it to a desired type to use it. Once it has
+   been cast, the native image becomes unusable because casting is done inplace
+   so the buffer initially allocated for the native image may be resized and
+   overridden.
    */
   ImageBasePointer m_NativeImage;
 
   // The IO base used to read the files
   IOBasePointer m_IOBase;
 
+  // GDCM series reader/parser (for DICOM)
+  SmartPtr<itk::GDCMSeriesFileNames> m_GDCMSeries;
+  std::string m_GDCMSeriesDirectory;
+
   // This information is copied from IOBase in order to delete IOBase at the 
   // earliest possible point, so as to conserve memory
   IOBase::IOComponentType m_NativeType;
   size_t m_NativeComponents;
   unsigned long m_NativeSizeInBytes;
   std::string m_NativeTypeString, m_NativeFileName;
+  std::string m_NativeNickname;
   IOBase::ByteOrder m_NativeByteOrder;
+  Vector3ui m_NativeDimensions;
+
+  // Copy of the registry passed in when reading header
+  Registry m_Hints;
 
   // The file format
   FileFormat m_FileFormat;
@@ -226,32 +310,43 @@ private:
 
   // File format descriptors
   static const FileFormatDescriptor m_FileFormatDescrictorArray[];
+
+  static const gdcm::Tag m_tagRows;
+  static const gdcm::Tag m_tagCols;
+  static const gdcm::Tag m_tagDesc;
+  static const gdcm::Tag m_tagTextDesc;
+  static const gdcm::Tag m_tagSeriesInstanceUID;
+  static const gdcm::Tag m_tagSeriesNumber;
+  static const gdcm::Tag m_tagAcquisitionNumber;
+  static const gdcm::Tag m_tagInstanceNumber;
+  
 };
 
 
 /**
- * \class RescaleNativeImageToScalar
+ * \class RescaleNativeImageToIntegralType
  * \brief An adapter class that rescales a native-format image from 
  * GuidedNativeImageIO to user-specified scalar type
  */
-template<typename TPixel>
-class RescaleNativeImageToScalar
+template<class TOutputImage>
+class RescaleNativeImageToIntegralType
 {
 public:
-  RescaleNativeImageToScalar() {}
-  virtual ~RescaleNativeImageToScalar() {}
+  RescaleNativeImageToIntegralType() {}
+  virtual ~RescaleNativeImageToIntegralType() {}
 
-  typedef itk::OrientedImage<TPixel,3> OutputImageType;
-  typedef itk::ImageBase<3> NativeImageType;
+  typedef TOutputImage                                         OutputImageType;
+  typedef typename TOutputImage::PixelType                     OutputPixelType;
+  typedef itk::ImageBase<3>                                    NativeImageType;
 
   // Constructor, takes pointer to native image
   OutputImageType *operator()(GuidedNativeImageIO *nativeIO);
 
   // Get the scale factor to map from scalar to native
-  irisGetMacro(NativeScale, double);
+  irisGetMacro(NativeScale, double)
 
   // Get the shift to map from scalar to native
-  irisGetMacro(NativeShift, double);
+  irisGetMacro(NativeShift, double)
 
 private:
   typename OutputImageType::Pointer m_Output;
@@ -261,27 +356,48 @@ private:
   template<typename TNative> void DoCast(itk::ImageBase<3> *native);
 };
 
+template<class TPixel> class TrivialCastFunctor
+{
+public:
+  typedef TPixel PixelType;
+  template<class TNative> void operator()(TNative *src, TPixel *trg)
+    { *trg = static_cast<TPixel>(*src); }
+};
+
+
 /**
  * \class CastNativeImageBase
  * \brief An adapter class that casts a native-format image from 
- * GuidedNativeImageIO to an image of type TPixel. The actual casting
+ * GuidedNativeImageIO to an output image type. The actual casting
  * is done using the functor TCastFunctor. Use derived classes.
  */
-template<class TPixel, class TCastFunctor>
-class CastNativeImageBase
+template<class TOutputImage,
+         class TCastFunctor =
+           TrivialCastFunctor<typename TOutputImage::InternalPixelType> >
+class CastNativeImage
 {
 public:
-  typedef itk::OrientedImage<TPixel,3> OutputImageType;
-  typedef itk::ImageBase<3> NativeImageType;
+  typedef TOutputImage                                         OutputImageType;
+  typedef RescaleNativeImageToIntegralType<OutputImageType>       RescalerType;
+  typedef typename RescalerType::NativeImageType               NativeImageType;
+  typedef typename OutputImageType::PixelType                  OutputPixelType;
+  typedef typename OutputImageType::InternalPixelType      OutputComponentType;
 
   // Constructor, takes pointer to native image
   OutputImageType *operator()(GuidedNativeImageIO *nativeIO);
 
+  // Set the functor
+  void SetFunctor(TCastFunctor functor) 
+    { m_Functor = functor; }
+
 private:
   typename OutputImageType::Pointer m_Output;
+  TCastFunctor m_Functor;
 
   // Method that does the casting
   template<typename TNative> void DoCast(itk::ImageBase<3> *native);
+
+  friend class RescaleNativeImageToIntegralType<OutputImageType>;
 };
 
 // Functor used for scalar to scalar casting
@@ -307,19 +423,21 @@ public:
  * \brief An adapter class that casts a native-format image from 
  * GuidedNativeImageIO to an RGB image
  */
+/*
 template<typename TRGBPixel>
 class CastNativeImageToRGB : 
   public CastNativeImageBase<TRGBPixel, CastToArrayFunctor<TRGBPixel, 3> > {};
-
+*/
 
 /**
  * \class CastNativeImageToScalar
  * \brief An adapter class that casts a native-format image from 
  * GuidedNativeImageIO to a scalar image of given type
  */
+/*
 template<typename TPixel>
 class CastNativeImageToScalar : 
   public CastNativeImageBase<TPixel, CastToScalarFunctor<TPixel> > {};
-
+*/
 
 #endif
diff --git a/Logic/ImageWrapper/ImageIORoutines.h b/Logic/ImageWrapper/ImageIORoutines.h
deleted file mode 100644
index e128a40..0000000
--- a/Logic/ImageWrapper/ImageIORoutines.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ImageIORoutines.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:14 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __ImageIORoutines_h_
-#define __ImageIORoutines_h_
-
-#include "itkImage.h"
-#include "itkImageIOBase.h"
-#include "itkImageFileReader.h"
-#include "itkImageFileWriter.h"
-
-// This file contains a collection of useful IO routines
-
-/** Load an image from a file, throw exception if something happens */
-template <class TImageType>
-void LoadImageFromFile(const char *fname,
-                       typename itk::SmartPointer<TImageType> &target,
-                       itk::ImageIOBase *io = 0) throw(itk::ExceptionObject)
-{
-  // Load the image using itk IO
-  typedef itk::ImageFileReader<TImageType> ReaderType;
-  typename ReaderType::Pointer reader = ReaderType::New();
-  
-  reader->SetFileName(fname);
-  if(io)
-    reader->SetImageIO(io);
-  reader->Update();
-  target = reader->GetOutput();    
-}
-
-/** Save an image to a file, throw exception if something happens */
-template <class TImageType>
-void SaveImageToFile(const char *fname,
-                     TImageType *source,
-                     itk::ImageIOBase *io = 0) throw(itk::ExceptionObject)
-{
-  // Load the image using itk IO
-  typedef itk::ImageFileWriter<TImageType> WriterType;
-  typename WriterType::Pointer writer = WriterType::New();
-  
-  writer->SetFileName(fname);
-  if(io)
-    writer->SetImageIO(io);
-  writer->SetInput(source);
-  writer->Update();
-}
-
-#endif // __ImageIORoutines_h_
-
-
-
diff --git a/Logic/ImageWrapper/ImageWrapper.cxx b/Logic/ImageWrapper/ImageWrapper.cxx
new file mode 100644
index 0000000..3e1f97d
--- /dev/null
+++ b/Logic/ImageWrapper/ImageWrapper.cxx
@@ -0,0 +1,1371 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: ImageWrapper.txx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/14 16:21:04 $
+  Version:   $Revision: 1.11 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+
+#include "ImageWrapper.h"
+#include "itkImageRegionIterator.h"
+#include "itkImageSliceConstIteratorWithIndex.h"
+#include "itkNumericTraits.h"
+#include "itkRegionOfInterestImageFilter.h"
+#include "itkIdentityTransform.h"
+#include "IRISSlicer.h"
+#include "SNAPSegmentationROISettings.h"
+#include "itkCommand.h"
+#include "ImageCoordinateGeometry.h"
+#include <itkImageFileWriter.h>
+#include <itkResampleImageFilter.h>
+#include <itkIdentityTransform.h>
+#include <itkFlipImageFilter.h>
+#include <itkUnaryFunctorImageFilter.h>
+#include "ImageWrapperTraits.h"
+#include "itkNearestNeighborInterpolateImageFunction.h"
+#include "itkBSplineInterpolateImageFunction.h"
+#include "itkWindowedSincInterpolateImageFunction.h"
+#include "itkLinearInterpolateImageFunction.h"
+#include "itkConstantBoundaryCondition.h"
+#include "IRISException.h"
+#include "itkImageAdaptor.h"
+#include "itkVectorImageToImageAdaptor.h"
+#include "UnaryValueToValueFilter.h"
+#include "ScalarImageHistogram.h"
+#include "GuidedNativeImageIO.h"
+
+
+#include <vnl/vnl_inverse.h>
+#include <iostream>
+
+#include <itksys/SystemTools.hxx>
+
+unsigned long GlobalImageWrapperIndex = 0;
+
+
+template <class TPixel>
+class SimpleCastToDoubleFunctor
+{
+public:
+  typedef TPixel InputType;
+  typedef double OutputType;
+  double operator()(TPixel input) { return static_cast<double>(input); }
+};
+
+
+/**
+ * Some functions in the image wrapper are only defined for 'concrete' image
+ * wrappers, i.e., those that store an image or a vectorimage. These functions
+ * involve copying subregions, filling the buffer, IO, etc. To handle this
+ * differential availability of functionality, we use partial template
+ * specialization below.
+ */
+template <class TImage>
+class ImageWrapperPartialSpecializationTraits
+{
+public:
+  typedef TImage ImageType;
+  typedef typename TImage::PixelType PixelType;
+
+  static void FillBuffer(ImageType *image, PixelType)
+  {
+    throw IRISException("FillBuffer unsupported for class %s",
+                        image->GetNameOfClass());
+  }
+
+  static void Write(ImageType *image, const char *fname, Registry &hints)
+  {
+    throw IRISException("FillBuffer unsupported for class %s",
+                        image->GetNameOfClass());
+  }
+
+  static SmartPtr<ImageType> CopyRegion(ImageType *image,
+                                        const SNAPSegmentationROISettings &roi,
+                                        itk::Command *progressCommand)
+  {
+    throw IRISException("CopyRegion unsupported for class %s",
+                        image->GetNameOfClass());
+    return NULL;
+  }
+};
+
+template <class TImage>
+class ImageWrapperPartialSpecializationTraitsCommon
+{
+public:
+  typedef TImage ImageType;
+  typedef typename TImage::PixelType PixelType;
+
+  static void FillBuffer(ImageType *image, PixelType p)
+  {
+    image->FillBuffer(p);
+  }
+
+  static void Write(ImageType *image, const char *fname, Registry &hints)
+  {
+    SmartPtr<GuidedNativeImageIO> io = GuidedNativeImageIO::New();
+    io->CreateImageIO(fname, hints, false);
+    itk::ImageIOBase *base = io->GetIOBase();
+
+    typedef itk::ImageFileWriter<TImage> WriterType;
+    typename WriterType::Pointer writer = WriterType::New();
+    writer->SetFileName(fname);
+    if(base)
+      writer->SetImageIO(base);
+    writer->SetInput(image);
+    writer->Update();
+  }
+
+  template <class TInterpolateFunction>
+  static SmartPtr<ImageType> DeepCopyImageRegion(
+      ImageType *image,
+      TInterpolateFunction *interp,
+      const SNAPSegmentationROISettings &roi,
+      itk::Command *progressCommand)
+  {
+    // Check if there is a difference in voxel size, i.e., user wants resampling
+    Vector3d vOldSpacing = image->GetSpacing();
+    Vector3d vOldOrigin = image->GetOrigin();
+    Vector3i vROIIndex(roi.GetROI().GetIndex());
+    Vector3ui vROISize(roi.GetROI().GetSize());
+
+    if(roi.IsResampling())
+      {
+      // Compute the number of voxels in the output
+      typedef typename itk::ImageRegion<3> RegionType;
+      typedef typename itk::Size<3> SizeType;
+
+      // We need to compute the new spacing and origin of the resampled
+      // ROI piece. To do this, we need the direction matrix
+      typedef typename ImageType::DirectionType DirectionType;
+      const DirectionType &dm = image->GetDirection();
+
+      // The spacing of the new ROI
+      Vector3d vNewSpacing =
+          element_quotient(element_product(vOldSpacing, to_double(vROISize)),
+                           to_double(roi.GetResampleDimensions()));
+
+      // The origin of the new ROI
+      Vector3d vNewOrigin =
+          vOldOrigin + dm.GetVnlMatrix() * (
+            element_product((to_double(vROIIndex) - 0.5), vOldSpacing) +
+            vNewSpacing * 0.5);
+
+      // Create a filter for resampling the image
+      typedef itk::ResampleImageFilter<ImageType,ImageType> ResampleFilterType;
+      typename ResampleFilterType::Pointer fltSample = ResampleFilterType::New();
+
+      // Initialize the resampling filter
+      fltSample->SetInput(image);
+      fltSample->SetTransform(itk::IdentityTransform<double,3>::New());
+      fltSample->SetInterpolator(interp);
+
+      // Set the image sizes and spacing
+      fltSample->SetSize(to_itkSize(roi.GetResampleDimensions()));
+      fltSample->SetOutputSpacing(vNewSpacing.data_block());
+      fltSample->SetOutputOrigin(vNewOrigin.data_block());
+      fltSample->SetOutputDirection(image->GetDirection());
+
+      // Set the progress bar
+      if(progressCommand)
+        fltSample->AddObserver(itk::AnyEvent(),progressCommand);
+
+      fltSample->Update();
+
+      return fltSample->GetOutput();
+      }
+    else
+      {
+      // The filter used to chop off the region of interest
+      typedef itk::RegionOfInterestImageFilter <ImageType,ImageType> ChopFilterType;
+      typename ChopFilterType::Pointer fltChop = ChopFilterType::New();
+
+      // Pipe image into the chopper
+      fltChop->SetInput(image);
+
+      // Set the region of interest
+      fltChop->SetRegionOfInterest(roi.GetROI());
+
+      // Update the pipeline
+      fltChop->Update();
+
+      // Return the resulting image
+      return fltChop->GetOutput();
+      }
+  }
+
+};
+
+
+template<class TPixel, unsigned int VDim>
+class ImageWrapperPartialSpecializationTraits< itk::Image<TPixel, VDim> >
+    : public ImageWrapperPartialSpecializationTraitsCommon< itk::Image<TPixel, VDim> >
+{
+public:
+  typedef itk::Image<TPixel, VDim> ImageType;
+  typedef typename ImageType::PixelType PixelType;
+  typedef ImageWrapperPartialSpecializationTraitsCommon<ImageType> Superclass;
+
+  static SmartPtr<ImageType> CopyRegion(ImageType *image,
+                                        const SNAPSegmentationROISettings &roi,
+                                        itk::Command *progressCommand)
+  {
+    typedef itk::InterpolateImageFunction<ImageType> Interpolator;
+    SmartPtr<Interpolator> interp = NULL;
+
+    // Choose the interpolator
+    switch(roi.GetInterpolationMethod())
+      {
+      case SNAPSegmentationROISettings::NEAREST_NEIGHBOR :
+        typedef itk::NearestNeighborInterpolateImageFunction<ImageType,double> NNInterpolatorType;
+        interp = NNInterpolatorType::New().GetPointer();
+        break;
+
+      case SNAPSegmentationROISettings::TRILINEAR :
+        typedef itk::LinearInterpolateImageFunction<ImageType,double> LinearInterpolatorType;
+        interp = LinearInterpolatorType::New().GetPointer();
+        break;
+
+      case SNAPSegmentationROISettings::TRICUBIC :
+        typedef itk::BSplineInterpolateImageFunction<ImageType,double> CubicInterpolatorType;
+        interp = CubicInterpolatorType::New().GetPointer();
+        break;
+
+      case SNAPSegmentationROISettings::SINC_WINDOW_05 :
+        // More typedefs are needed for the sinc interpolator
+        static const unsigned int VRadius = 5;
+        typedef itk::Function::HammingWindowFunction<VRadius> WindowFunction;
+        typedef itk::ConstantBoundaryCondition<ImageType> Condition;
+        typedef itk::WindowedSincInterpolateImageFunction<
+          ImageType, VRadius, WindowFunction, Condition, double> SincInterpolatorType;
+        interp = SincInterpolatorType::New().GetPointer();
+        break;
+      };
+
+    return Superclass::template DeepCopyImageRegion<Interpolator>(image,interp,roi,progressCommand);
+  }
+};
+
+
+template<class TPixel, unsigned int VDim>
+class ImageWrapperPartialSpecializationTraits< itk::VectorImage<TPixel, VDim> >
+   : public ImageWrapperPartialSpecializationTraitsCommon< itk::VectorImage<TPixel, VDim> >
+{
+public:
+  typedef itk::VectorImage<TPixel, VDim> ImageType;
+  typedef typename ImageType::PixelType PixelType;
+  typedef ImageWrapperPartialSpecializationTraitsCommon<ImageType> Superclass;
+
+  static void FillBuffer(ImageType *image, PixelType p)
+  {
+    image->FillBuffer(p);
+  }
+
+  static SmartPtr<ImageType> CopyRegion(ImageType *image,
+                                        const SNAPSegmentationROISettings &roi,
+                                        itk::Command *progressCommand)
+  {
+    typedef itk::InterpolateImageFunction<ImageType> Interpolator;
+    SmartPtr<Interpolator> interp = NULL;
+
+    // Choose the interpolator
+    switch(roi.GetInterpolationMethod())
+      {
+      case SNAPSegmentationROISettings::NEAREST_NEIGHBOR :
+        typedef itk::NearestNeighborInterpolateImageFunction<ImageType> NNInterpolatorType;
+        interp = NNInterpolatorType::New().GetPointer();
+        break;
+
+      case SNAPSegmentationROISettings::TRILINEAR :
+        typedef itk::LinearInterpolateImageFunction<ImageType> LinearInterpolatorType;
+        interp = LinearInterpolatorType::New().GetPointer();
+        break;
+
+      default:
+        throw IRISException("Higher-order interpolation for vector images is unsupported.");
+      };
+
+    return Superclass::template DeepCopyImageRegion<Interpolator>(image,interp,roi,progressCommand);
+  }
+
+};
+
+
+template<class TTraits, class TBase>
+ImageWrapper<TTraits,TBase>
+::ImageWrapper() 
+{
+  CommonInitialization();
+}
+
+template<class TTraits, class TBase>
+ImageWrapper<TTraits,TBase>
+::~ImageWrapper() 
+{
+  Reset();
+}
+
+template<class TTraits, class TBase>
+void 
+ImageWrapper<TTraits,TBase>
+::CommonInitialization()
+{
+  // This is the code that should be called by all constructors
+
+  // Set the unique wrapper id
+  m_UniqueId = ++GlobalImageWrapperIndex;
+
+  // Set initial state    
+  m_Initialized = false;
+  m_PipelineReady = false;
+
+  // Create slicer objects
+  m_Slicer[0] = SlicerType::New();
+  m_Slicer[1] = SlicerType::New();
+  m_Slicer[2] = SlicerType::New();
+
+  // Initialize the display mapping
+  m_DisplayMapping = DisplayMapping::New();
+  m_DisplayMapping->Initialize(
+        static_cast<typename TTraits::WrapperType *>(this));
+
+  // Set sticky flag
+  m_Sticky = TTraits::StickyByDefault;
+
+  // By default, the parent wrapper is NULL. This is overridden for wrappers
+  // that are derived from vector wrappers. See VectorImageWrapper::CreateDerivedWrapper
+  m_ParentWrapper = NULL;
+
+  // Update the image geometry to default value
+  this->UpdateImageGeometry();
+}
+
+template<class TTraits, class TBase>
+ImageWrapper<TTraits,TBase>
+::ImageWrapper(const Self &copy)
+{
+  CommonInitialization();
+
+  // If the source contains an image, make a copy of that image
+  if (copy.IsInitialized() && copy.GetImage())
+    {
+    // Create and allocate the image
+    ImagePointer newImage = ImageType::New();
+    newImage->SetRegions(copy.GetImage()->GetBufferedRegion());
+    newImage->Allocate();
+
+    // Copy the image contents
+    InternalPixelType *ptrTarget = newImage->GetBufferPointer();
+    InternalPixelType *ptrSource = copy.GetImage()->GetBufferPointer();
+    memcpy(ptrTarget,ptrSource,
+           sizeof(PixelType) * newImage->GetPixelContainer()->Size());
+
+    UpdateImagePointer(newImage);
+    }
+}
+
+template<class TTraits, class TBase>
+const ImageCoordinateTransform &
+ImageWrapper<TTraits,TBase>
+::GetImageToDisplayTransform(unsigned int iSlice) const
+{
+  return m_ImageGeometry.GetImageToDisplayTransform(iSlice);
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::SetDisplayGeometry(IRISDisplayGeometry &dispGeom)
+{
+  // Set the display geometry
+  m_DisplayGeometry = dispGeom;
+
+  // Update the image geometry object and the slicers
+  this->UpdateImageGeometry();
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::SetDirectionMatrix(const vnl_matrix<double> &direction)
+{
+  // Update the direction matrix in the image
+  typename ImageType::DirectionType matrix(direction);
+  m_Image->SetDirection(matrix);
+
+  // Update the NIFTI/RAS transform
+  this->UpdateNiftiTransforms();
+
+  // Update the image geometry
+  this->UpdateImageGeometry();
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::CopyImageCoordinateTransform(const ImageWrapperBase *source)
+{
+  // Better have the image!
+  assert(m_Image && source->GetImageBase());
+
+  // Set the new meta-data on the image
+  m_Image->SetSpacing(source->GetImageBase()->GetSpacing());
+  m_Image->SetOrigin(source->GetImageBase()->GetOrigin());
+  m_Image->SetDirection(source->GetImageBase()->GetDirection());
+
+  // Update NIFTI transforms
+  this->UpdateNiftiTransforms();
+
+  // Update the image geometry
+  this->UpdateImageGeometry();
+}
+
+template<class TTraits, class TBase>
+Vector3ui
+ImageWrapper<TTraits,TBase>
+::GetSize() const
+{
+  // Cast the size to our vector format
+  itk::Size<3> size = m_Image->GetLargestPossibleRegion().GetSize();
+  return Vector3ui(
+    (unsigned int) size[0],
+    (unsigned int) size[1],
+        (unsigned int) size[2]);
+}
+
+template<class TTraits, class TBase>
+bool
+ImageWrapper<TTraits,TBase>
+::IsDrawable() const
+{
+  // If not initialized, the layer is not drawable
+  if(!this->IsInitialized())
+    return false;
+
+  // If the image is a pipeline output, then it is displayable either if
+  // there is a preview pipeline in place, or if the image volume itself has
+  // been modified.
+  if(TTraits::PipelineOutput)
+    {
+    return (IsPreviewPipelineAttached() && IsPipelineReady())
+        || m_Image->GetMTime() > m_ImageAssignTime;
+    }
+
+  // Otherwise, it's drawable
+  return true;
+}
+
+
+template<class TTraits, class TBase>
+itk::ImageRegion<3>
+ImageWrapper<TTraits,TBase>
+::GetBufferedRegion() const
+{
+  return m_ImageBase->GetBufferedRegion();
+}
+
+template<class TTraits, class TBase>
+size_t
+ImageWrapper<TTraits,TBase>
+::GetNumberOfVoxels() const
+{
+  return m_ImageBase->GetBufferedRegion().GetNumberOfPixels();
+}
+
+template<class TTraits, class TBase>
+Vector3d
+ImageWrapper<TTraits,TBase>
+::TransformVoxelIndexToPosition(const Vector3ui &iVoxel) const
+{
+  // Use the ITK method to do this
+  typename ImageBaseType::IndexType xIndex;
+  for(size_t d = 0; d < 3; d++) xIndex[d] = iVoxel[d];
+
+  itk::Point<double, 3> xPoint;
+  m_ImageBase->TransformIndexToPhysicalPoint(xIndex, xPoint);
+
+  Vector3d xOut;
+  for(unsigned int q = 0; q < 3; q++) xOut[q] = xPoint[q];
+
+  return xOut;
+}
+
+template<class TTraits, class TBase>
+Vector3d
+ImageWrapper<TTraits,TBase>
+::TransformVoxelIndexToNIFTICoordinates(const Vector3d &iVoxel) const
+{
+  // Create homogeneous vector
+  vnl_vector_fixed<double, 4> x;
+  for(size_t d = 0; d < 3; d++)
+    x[d] = (double) iVoxel[d];
+  x[3] = 1.0;
+
+  // Transform to NIFTI coords
+  vnl_vector_fixed<double, 4> p = m_NiftiSform * x;
+
+  // Return the component
+  return Vector3d(p[0], p[1], p[2]);
+}
+
+template<class TTraits, class TBase>
+Vector3d
+ImageWrapper<TTraits,TBase>
+::TransformNIFTICoordinatesToVoxelIndex(const Vector3d &vNifti) const
+{
+  // Create homogeneous vector
+  vnl_vector_fixed<double, 4> x;
+  for(size_t d = 0; d < 3; d++)
+    x[d] = (double) vNifti[d];
+  x[3] = 1.0;
+
+  // Transform to NIFTI coords
+  vnl_vector_fixed<double, 4> p = m_NiftiInvSform * x;
+
+  // Return the component
+  return Vector3d(p[0], p[1], p[2]);
+}
+
+
+template<class TTraits, class TBase>
+void 
+ImageWrapper<TTraits,TBase>
+::PrintDebugInformation() 
+{
+  std::cout << "=== Image Properties ===" << std::endl;
+  std::cout << "   Dimensions         : " << m_Image->GetLargestPossibleRegion().GetSize() << std::endl;
+  std::cout << "   Origin             : " << m_Image->GetOrigin() << std::endl;
+  std::cout << "   Spacing            : " << m_Image->GetSpacing() << std::endl;
+  std::cout << "------------------------" << std::endl;
+}
+
+template<class TTraits, class TBase>
+void 
+ImageWrapper<TTraits,TBase>
+::UpdateImagePointer(ImageType *newImage)
+{
+  // Check if the image size or image direction matrix has changed
+  bool hasSizeChanged = true, hasDirectionChanged = true;
+  if(m_Image && m_Image != newImage)
+    {
+    hasSizeChanged = newImage->GetLargestPossibleRegion().GetSize()
+        != m_Image->GetLargestPossibleRegion().GetSize();
+
+    hasDirectionChanged = newImage->GetDirection()
+        != m_Image->GetDirection();
+    }
+
+  // Change the input of the slicers 
+  m_Slicer[0]->SetInput(newImage);
+  m_Slicer[1]->SetInput(newImage);
+  m_Slicer[2]->SetInput(newImage);
+
+  // Update the image
+  this->m_ImageBase = newImage;
+  m_Image = newImage;
+
+  // Mark the image as Modified to enforce correct sequence of
+  // operations with MinMaxCalc
+  m_Image->Modified();
+
+  // Update the image in the display mapping
+  m_DisplayMapping->UpdateImagePointer(m_Image);
+
+  // Update the image coordinate geometry
+  if(hasSizeChanged || hasDirectionChanged)
+    {
+    // Reset the transform to identity
+    this->UpdateImageGeometry();
+
+    // Reset the slice positions to zero
+    this->SetSliceIndex(Vector3ui(0,0,0));
+    }
+
+  // Update the NIFTI/RAS transform
+  this->UpdateNiftiTransforms();
+
+  // We have been initialized
+  m_Initialized = true;
+
+  // Store the time when the image was assigned
+  m_ImageAssignTime = m_Image->GetTimeStamp();
+}
+
+template<class TTraits, class TBase>
+void 
+ImageWrapper<TTraits,TBase>
+::InitializeToWrapper(const ImageWrapperBase *source, ImageType *image) 
+{
+  // Update the display geometry from the source wrapper
+  m_DisplayGeometry = source->GetDisplayGeometry();
+
+  // Call the common update method
+  UpdateImagePointer(image);
+
+  // Update the slice index
+  SetSliceIndex(source->GetSliceIndex());
+}
+
+
+
+template<class TTraits, class TBase>
+void 
+ImageWrapper<TTraits,TBase>
+::InitializeToWrapper(const ImageWrapperBase *source, const PixelType &value)
+{
+  typedef ImageWrapperPartialSpecializationTraits<ImageType> Specialization;
+
+  // Allocate the image
+  ImagePointer newImage = ImageType::New();
+  newImage->SetRegions(source->GetImageBase()->GetBufferedRegion().GetSize());
+  newImage->Allocate();
+  Specialization::FillBuffer(newImage.GetPointer(), value);
+  newImage->SetOrigin(source->GetImageBase()->GetOrigin());
+  newImage->SetSpacing(source->GetImageBase()->GetSpacing());
+  newImage->SetDirection(source->GetImageBase()->GetDirection());
+
+  // Update the display geometry from the source wrapper
+  m_DisplayGeometry = source->GetDisplayGeometry();
+
+  // Call the common update method
+  UpdateImagePointer(newImage);
+
+  // Update the slice index
+  SetSliceIndex(source->GetSliceIndex());
+}
+
+template<class TTraits, class TBase>
+void 
+ImageWrapper<TTraits,TBase>
+::SetImage(ImagePointer newImage) 
+{
+  UpdateImagePointer(newImage);
+}
+
+
+template<class TTraits, class TBase>
+void 
+ImageWrapper<TTraits,TBase>
+::Reset() 
+{
+  if (m_Initialized)
+    {
+    m_Image->ReleaseData();
+    m_Image = NULL;
+    }
+  m_Initialized = false;
+
+  m_Alpha = 0.5;
+}
+
+
+template<class TTraits, class TBase>
+inline typename ImageWrapper<TTraits,TBase>::PixelType
+ImageWrapper<TTraits,TBase>
+::GetVoxel(const Vector3ui &index) const 
+{
+  return GetVoxel(index[0],index[1],index[2]);
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits, TBase>
+::SetVoxel(const Vector3ui &index, const PixelType &value)
+{
+  this->SetVoxel(to_itkIndex(index), value);
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::SetVoxel(const itk::Index<3> &index, const PixelType &value)
+{
+  // Verify that the pixel is contained by the image at debug time
+  assert(m_Image && m_Image->GetLargestPossibleRegion().IsInside(index));
+
+  // Return the pixel
+  m_Image->SetPixel(index, value);
+}
+
+template<class TTraits, class TBase>
+inline typename ImageWrapper<TTraits,TBase>::PixelType
+ImageWrapper<TTraits,TBase>
+::GetVoxel(unsigned int x, unsigned int y, unsigned int z) const
+{
+  itk::Index<3> index;
+  index[0] = x;
+  index[1] = y;
+  index[2] = z;
+
+  return GetVoxel(index);
+}
+
+template<class TTraits, class TBase>
+inline typename ImageWrapper<TTraits,TBase>::PixelType
+ImageWrapper<TTraits,TBase>
+::GetVoxel(const itk::Index<3> &index) const
+{
+  // Verify that the pixel is contained by the image at debug time
+  assert(m_Image && m_Image->GetLargestPossibleRegion().IsInside(index));
+
+  // Return the pixel
+  return m_Image->GetPixel(index);
+}
+
+template<class TTraits, class TBase>
+typename ImageWrapper<TTraits,TBase>::ConstIterator
+ImageWrapper<TTraits,TBase>
+::GetImageConstIterator() const 
+{
+  ConstIterator it(m_Image,m_Image->GetLargestPossibleRegion());
+  it.GoToBegin();
+  return it;
+}
+
+template<class TTraits, class TBase>
+typename ImageWrapper<TTraits,TBase>::Iterator
+ImageWrapper<TTraits,TBase>
+::GetImageIterator() 
+{
+  Iterator it(m_Image,m_Image->GetLargestPossibleRegion());
+  it.GoToBegin();
+  return it;
+}
+
+template<class TTraits, class TBase>
+void 
+ImageWrapper<TTraits,TBase>
+::SetSliceIndex(const Vector3ui &cursor)
+{
+  // Save the cursor position
+  m_SliceIndex = cursor;
+
+  // Select the appropriate slice for each slicer
+  for(unsigned int i=0;i<3;i++)
+  {
+    // Which axis does this slicer slice?
+    unsigned int axis = m_Slicer[i]->GetSliceDirectionImageAxis();
+
+    // Set the slice using that axis
+    m_Slicer[i]->SetSliceIndex(cursor[axis]);
+  }
+}
+
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::UpdateImageGeometry()
+{
+  // This method updates the internally stored image geometry object and
+  // the image coordinate transforms in all the slicers based on three
+  // pieces of information that are stored in the wrapper:
+  //   1. Image size
+  //   2. Image direction matrix
+  //   3. Display to anatomy transforms (m_DisplayGeometry)
+  // This method must be called whenever one of these parameters changes.
+
+  // Create an image coordinate geometry based on the current state
+  if(m_Image)
+    {
+    // Set the geometry based on the current image characteristics
+    m_ImageGeometry.SetGeometry(
+          m_Image->GetDirection().GetVnlMatrix(),
+          m_DisplayGeometry,
+          m_Image->GetLargestPossibleRegion().GetSize());
+
+    // Update the geometry for each slice
+    for(unsigned int iSlice = 0;iSlice < 3;iSlice ++)
+      {
+      // Get the transform and its inverse
+      ImageCoordinateTransform tran = m_ImageGeometry.GetImageToDisplayTransform(iSlice);
+      ImageCoordinateTransform tinv = tran.Inverse();
+
+      // Tell slicer in which directions to slice
+      m_Slicer[iSlice]->SetSliceDirectionImageAxis(
+            tinv.GetCoordinateIndexZeroBased(2));
+
+      m_Slicer[iSlice]->SetLineDirectionImageAxis(
+            tinv.GetCoordinateIndexZeroBased(1));
+
+      m_Slicer[iSlice]->SetPixelDirectionImageAxis(
+            tinv.GetCoordinateIndexZeroBased(0));
+
+      m_Slicer[iSlice]->SetPixelTraverseForward(
+            tinv.GetCoordinateOrientation(0) > 0);
+
+      m_Slicer[iSlice]->SetLineTraverseForward(
+            tinv.GetCoordinateOrientation(1) > 0);
+
+      // Invalidate the requested region in the display slice. This will
+      // cause the RR to reset to largest possible region on next Update
+      typename DisplaySliceType::RegionType invalidRegion;
+      this->GetDisplaySlice(iSlice)->SetRequestedRegion(invalidRegion);
+      }
+
+    // Cause the axis indices in the slicers to be updated due to reorientation
+    this->SetSliceIndex(this->GetSliceIndex());
+    }
+  else
+    {
+    // Identity matrix
+    typename ImageType::DirectionType dirmat;
+    dirmat.SetIdentity();
+
+    // Zero size
+    typename ImageType::SizeType size;
+
+    // Set the geometry to default values
+    m_ImageGeometry.SetGeometry(dirmat.GetVnlMatrix(), m_DisplayGeometry, size);
+    }
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::UpdateNiftiTransforms()
+{
+  assert(m_Image);
+
+  // Update the NIFTI/RAS transform
+  m_NiftiSform = ImageWrapperBase::ConstructNiftiSform(
+    m_Image->GetDirection().GetVnlMatrix(),
+    m_Image->GetOrigin().GetVnlVector(),
+    m_Image->GetSpacing().GetVnlVector());
+
+  // Compute the inverse transform
+  m_NiftiInvSform = vnl_inverse(m_NiftiSform);
+}
+
+
+template<class TTraits, class TBase>
+inline double
+ImageWrapper<TTraits,TBase>
+::GetImageMinAsDouble()
+{
+  this->GetImageMinObject()->Update();
+  return static_cast<double>(this->GetImageMinObject()->Get());
+}
+
+template<class TTraits, class TBase>
+inline double
+ImageWrapper<TTraits,TBase>
+::GetImageMaxAsDouble()
+{
+  this->GetImageMaxObject()->Update();
+  return static_cast<double>(this->GetImageMaxObject()->Get());
+}
+
+template<class TTraits, class TBase>
+inline double
+ImageWrapper<TTraits,TBase>
+::GetImageMinNative()
+{
+  this->GetImageMinObject()->Update();
+  return m_NativeMapping(this->GetImageMinObject()->Get());
+}
+
+template<class TTraits, class TBase>
+inline double
+ImageWrapper<TTraits,TBase>
+::GetImageMaxNative()
+{
+  this->GetImageMaxObject()->Update();
+  return m_NativeMapping(this->GetImageMaxObject()->Get());
+}
+
+
+
+/** For each slicer, find out which image dimension does is slice along */
+template<class TTraits, class TBase>
+unsigned int 
+ImageWrapper<TTraits,TBase>
+::GetDisplaySliceImageAxis(unsigned int iSlice)
+{
+  return m_Slicer[iSlice]->GetSliceDirectionImageAxis();
+}
+
+template<class TTraits, class TBase>
+typename ImageWrapper<TTraits,TBase>::SliceType*
+ImageWrapper<TTraits,TBase>
+::GetSlice(unsigned int dimension)
+{
+  return m_Slicer[dimension]->GetOutput();
+}
+
+template<class TTraits, class TBase>
+typename ImageWrapper<TTraits,TBase>::InternalPixelType *
+ImageWrapper<TTraits,TBase>
+::GetVoxelPointer() const
+{
+  return m_Image->GetBufferPointer();
+}
+
+
+// TODO: this should take advantage of an in-place filter!
+template<class TTraits, class TBase>
+unsigned int 
+ImageWrapper<TTraits,TBase>
+::ReplaceIntensity(PixelType iOld, PixelType iNew)
+{
+  // Counter for the number of replaced voxels
+  unsigned int nReplaced = 0;
+
+  // Replace the voxels
+  for(Iterator it = GetImageIterator(); !it.IsAtEnd(); ++it)
+    if(it.Get() == iOld)
+      {
+      it.Set(iNew);
+      ++nReplaced;
+      }
+
+  // Flag that changes have been made
+  if(nReplaced > 0)
+    m_Image->Modified();
+
+  // Return the number of replacements
+  return nReplaced;
+}
+
+template<class TTraits, class TBase>
+unsigned int 
+ImageWrapper<TTraits,TBase>
+::SwapIntensities(PixelType iFirst, PixelType iSecond)
+{
+  // Counter for the number of replaced voxels
+  unsigned int nReplaced = 0;
+
+  // Replace the voxels
+  for(Iterator it = GetImageIterator(); !it.IsAtEnd(); ++it)
+    {
+    PixelType iCurrent = it.Get();
+    if(iCurrent == iFirst)
+      {
+      it.Set(iSecond);
+      ++nReplaced;
+      }
+    else if(iCurrent == iSecond)
+      {
+      it.Set(iFirst);
+      ++nReplaced;
+      }
+    }
+
+  // Flag that changes have been made
+  if(nReplaced > 0)
+    m_Image->Modified();
+
+  // Return the number of replacements
+  return nReplaced;
+}
+
+template<class TTraits, class TBase>
+typename ImageWrapper<TTraits,TBase>::DisplaySlicePointer
+ImageWrapper<TTraits,TBase>::GetDisplaySlice(unsigned int dim)
+{
+  return m_DisplayMapping->GetDisplaySlice(dim);
+}
+
+template<class TTraits, class TBase>
+void *
+ImageWrapper<TTraits,TBase>
+::GetVoxelVoidPointer() const
+{
+  return (void *) m_Image->GetBufferPointer();
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits, TBase>
+::SetFileName(const std::string &name)
+{
+  m_FileName = name;
+  m_FileNameShort = itksys::SystemTools::GetFilenameName(name);
+  this->InvokeEvent(WrapperMetadataChangeEvent());
+}
+
+template<class TTraits, class TBase>
+const std::string &
+ImageWrapper<TTraits, TBase>
+::GetNickname() const
+{
+  if(m_CustomNickname.length())
+    return m_CustomNickname;
+
+  else if(m_FileName.length())
+    return m_FileNameShort;
+
+  else return m_DefaultNickname;
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits, TBase>
+::SetCustomNickname(const std::string &nickname)
+{
+  // Make sure the nickname is real
+  if(nickname == m_FileNameShort)
+    m_CustomNickname.clear();
+  else
+    m_CustomNickname = nickname;
+
+  this->InvokeEvent(WrapperMetadataChangeEvent());
+}
+
+
+// The method that can be called for some wrappers, not others
+template <class TImage>
+static void DoWriteImage(TImage *image, const char *fname, Registry &hints)
+{
+  SmartPtr<GuidedNativeImageIO> io = GuidedNativeImageIO::New();
+  io->CreateImageIO(fname, hints, false);
+  itk::ImageIOBase *base = io->GetIOBase();
+
+  typedef itk::ImageFileWriter<TImage> WriterType;
+  typename WriterType::Pointer writer = WriterType::New();
+  writer->SetFileName(fname);
+  if(base)
+    writer->SetImageIO(base);
+  writer->SetInput(image);
+  writer->Update();
+}
+
+template<class TImage>
+class ImageWrapperWriteTraits
+{
+public:
+  static void Write(TImage *image, const char *fname, Registry &hints)
+  {
+    throw IRISException("FillBuffer unsupported for class %s",
+                        image->GetNameOfClass());
+  }
+};
+
+template<class TPixel, unsigned int VDim>
+class ImageWrapperWriteTraits< itk::Image<TPixel, VDim> >
+{
+public:
+  typedef itk::Image<TPixel, VDim> ImageType;
+  static void Write(ImageType *image, const char *fname, Registry &hints)
+  {
+    DoWriteImage(image, fname, hints);
+  }
+};
+
+template<class TPixel, unsigned int VDim>
+class ImageWrapperWriteTraits< itk::VectorImage<TPixel, VDim> >
+{
+public:
+  typedef itk::VectorImage<TPixel, VDim> ImageType;
+  static void Write(ImageType *image, const char *fname, Registry &hints)
+  {
+    DoWriteImage(image, fname, hints);
+  }
+};
+
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::WriteToFile(const char *filename, Registry &hints)
+{
+  // Do the actual writing
+  typedef ImageWrapperPartialSpecializationTraits<ImageType> Specialization;
+  Specialization::Write(m_Image, filename, hints);
+
+  // Store the filename
+  m_FileName = itksys::SystemTools::GetFilenamePath(filename);
+
+  // Store the timestamp when the filename was written
+  m_ImageSaveTime = m_Image->GetTimeStamp();
+
+}
+
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::AttachPreviewPipeline(
+    PreviewFilterType *f0, PreviewFilterType *f1, PreviewFilterType *f2)
+{
+  PreviewFilterType *filter[] = {f0, f1, f2};
+  for(int i = 0; i < 3; i++)
+    {
+    // Update the preview inputs to the slicers
+    m_Slicer[i]->SetPreviewInput(filter[i]->GetOutput());
+
+    // Mark the preview filters as modified to ensure that the slicer
+    // is going to use it. TODO: is this really needed?
+    filter[i]->Modified();
+    }
+
+  // This is so that IsDrawable() behaves correctly
+  m_ImageAssignTime = m_Image->GetTimeStamp();
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::DetachPreviewPipeline()
+{
+  for(int i = 0; i < 3; i++)
+    {
+    m_Slicer[i]->SetPreviewInput(NULL);
+    }
+}
+
+template<class TTraits, class TBase>
+bool
+ImageWrapper<TTraits,TBase>
+::IsPreviewPipelineAttached() const
+{
+  return m_Slicer[0]->GetPreviewInput() != NULL;
+}
+
+
+struct RemoveTransparencyFunctor
+{
+  typedef ImageWrapperBase::DisplayPixelType PixelType;
+  PixelType operator()(const PixelType &p)
+  {
+    PixelType pnew = p;
+    pnew[3] = 255;
+    return pnew;
+  }
+};
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::WriteThumbnail(const char *file, unsigned int maxdim)
+{
+  // Get the display slice
+  // For now, just use the z-axis for exporting the thumbnails
+  DisplaySliceType *slice = this->GetDisplaySlice(2);
+  slice->Update();
+
+  // The size of the slice
+  Vector2ui slice_dim = slice->GetBufferedRegion().GetSize();
+
+  // The physical extents of the slice
+  Vector2d slice_extent(slice->GetSpacing()[0] * slice_dim[0],
+                        slice->GetSpacing()[1] * slice_dim[1]);
+
+  // The output thumbnail will have the extents as the slice, but its size
+  // must be at max maxdim
+  double slice_extent_max = slice_extent.max_value();
+
+  // Create a simple square thumbnail
+  Vector2ui thumb_size(maxdim, maxdim);
+
+  // Spacing is such that the slice extent fits into the thumbnail
+  Vector2d thumb_spacing(slice_extent_max / maxdim,
+                         slice_extent_max / maxdim);
+
+  // The origin of the thumbnail is such that the centers coincide
+  Vector2d thumb_origin(0.5 * (slice_extent[0] - slice_extent_max),
+                        0.5 * (slice_extent[1] - slice_extent_max));
+
+  typedef typename itk::IdentityTransform<double, 2> TransformType;
+  TransformType::Pointer transform = TransformType::New();
+
+  typedef typename itk::ResampleImageFilter<
+      DisplaySliceType, DisplaySliceType> ResampleFilter;
+
+  // Background color for thumbnails
+  unsigned char defrgb[] = {0,0,0,255};
+
+  SmartPtr<ResampleFilter> filter = ResampleFilter::New();
+  filter->SetInput(slice);
+  filter->SetTransform(transform);
+  filter->SetSize(to_itkSize(thumb_size));
+  filter->SetOutputSpacing(thumb_spacing.data_block());
+  filter->SetOutputOrigin(thumb_origin.data_block());
+  filter->SetDefaultPixelValue(DisplayPixelType(defrgb));
+
+  // For thumbnails, the image needs to be flipped
+  typedef itk::FlipImageFilter<DisplaySliceType> FlipFilter;
+  SmartPtr<FlipFilter> flipper = FlipFilter::New();
+  flipper->SetInput(filter->GetOutput());
+  typename FlipFilter::FlipAxesArrayType flipaxes;
+  flipaxes[0] = false; flipaxes[1] = true;
+  flipper->SetFlipAxes(flipaxes);
+
+  // We also need to replace the transparency
+  typedef itk::UnaryFunctorImageFilter<
+      DisplaySliceType, DisplaySliceType, RemoveTransparencyFunctor> OpaqueFilter;
+  SmartPtr<OpaqueFilter> opaquer = OpaqueFilter::New();
+  opaquer->SetInput(flipper->GetOutput());
+
+  // Write a PNG file
+  typedef typename itk::ImageFileWriter<DisplaySliceType> WriterType;
+  SmartPtr<WriterType> writer = WriterType::New();
+  writer->SetInput(opaquer->GetOutput());
+  writer->SetFileName(file);
+  writer->Update();
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::WriteMetaData(Registry &reg)
+{
+  // Save the display mapping
+  m_DisplayMapping->Save(reg.Folder("DisplayMapping"));
+
+  // Save the alpha and the stickiness
+  reg["Alpha"] << m_Alpha;
+  reg["Sticky"] << m_Sticky;
+  reg["CustomNickName"] << m_CustomNickname;
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::ReadMetaData(Registry &reg)
+{
+  // Load the display mapping
+  m_DisplayMapping->Restore(reg.Folder("DisplayMapping"));
+
+  // Load the alpha and the stickiness
+  this->SetAlpha(reg["Alpha"][m_Alpha]);
+  this->SetSticky(reg["Sticky"][m_Sticky]);
+  this->SetCustomNickname(reg["CustomNickName"][m_CustomNickname]);
+}
+
+template<class TTraits, class TBase>
+bool
+ImageWrapper<TTraits,TBase>
+::HasUnsavedChanges() const
+{
+  itk::TimeStamp tsNow = m_Image->GetTimeStamp();
+  return (tsNow > m_ImageAssignTime && tsNow > m_ImageSaveTime);
+}
+
+template<class TTraits, class TBase>
+void
+ImageWrapper<TTraits,TBase>
+::SetUserData(const std::string &role, itk::Object *data)
+{
+  m_UserDataMap[role] = data;
+}
+
+template<class TTraits, class TBase>
+itk::Object *
+ImageWrapper<TTraits,TBase>
+::GetUserData(const std::string &role) const
+{
+  UserDataMapType::const_iterator it = m_UserDataMap.find(role);
+  if(it == m_UserDataMap.end())
+    return NULL;
+  else return it->second;
+}
+
+template<class TTraits, class TBase>
+SmartPtr<ImageWrapperBase>
+ImageWrapper<TTraits,TBase>
+::ExtractROI(const SNAPSegmentationROISettings &roi,
+             itk::Command *progressCommand) const
+{
+  // Get the ITK image for the ROI
+  ImagePointer newImage = this->DeepCopyRegion(roi, progressCommand);
+
+  // Initialize the new wrapper
+  typedef typename TTraits::WrapperType WrapperType;
+  SmartPtr<WrapperType> newWrapper = WrapperType::New();
+
+  // Copy the display to anatomy geometry to the new wrapper
+  newWrapper->m_DisplayGeometry = m_DisplayGeometry;
+
+  // Assign the new image to the new wrapper
+  newWrapper->SetImage(newImage);
+  newWrapper->SetNativeMapping(this->GetNativeMapping());
+
+  // Appropriate the default nickname?
+  newWrapper->SetDefaultNickname(this->GetDefaultNickname());
+  newWrapper->SetAlpha(this->GetAlpha());
+  newWrapper->SetSticky(this->IsSticky());
+
+  // We should not copy the user-assigned metadata. It's up to the
+  // user what should propagate to the ROI
+
+  // Cast to base class
+  SmartPtr<ImageWrapperBase> retptr = newWrapper.GetPointer();
+  return retptr;
+}
+
+
+template<class TTraits, class TBase>
+typename ImageWrapper<TTraits,TBase>::ImagePointer
+ImageWrapper<TTraits,TBase>
+::DeepCopyRegion(const SNAPSegmentationROISettings &roi,
+                 itk::Command *progressCommand) const
+{
+
+  // We use partial template specialization here because region copy is
+  // only supported for images that are concrete (Image, VectorImage)
+  typedef ImageWrapperPartialSpecializationTraits<ImageType> Specialization;
+  return Specialization::CopyRegion(m_Image, roi, progressCommand);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+// Allowed types of image wrappers
+template class ImageWrapper<SpeedImageWrapperTraits, ScalarImageWrapperBase>;
+template class ImageWrapper<LabelImageWrapperTraits, ScalarImageWrapperBase>;
+template class ImageWrapper<LevelSetImageWrapperTraits, ScalarImageWrapperBase>;
+
+template class ImageWrapper<AnatomicImageWrapperTraits<GreyType>, VectorImageWrapperBase>;
+template class ImageWrapper<AnatomicScalarImageWrapperTraits<GreyType>, ScalarImageWrapperBase>;
+template class ImageWrapper<ComponentImageWrapperTraits<GreyType>, ScalarImageWrapperBase>;
+
+typedef VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMagnitudeFunctor> MagTraits;
+typedef VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMaxFunctor> MaxTraits;
+typedef VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMeanFunctor> MeanTraits;
+template class ImageWrapper<MagTraits, ScalarImageWrapperBase>;
+template class ImageWrapper<MaxTraits, ScalarImageWrapperBase>;
+template class ImageWrapper<MeanTraits, ScalarImageWrapperBase>;
diff --git a/Logic/ImageWrapper/ImageWrapper.h b/Logic/ImageWrapper/ImageWrapper.h
index 564d150..2437c2c 100644
--- a/Logic/ImageWrapper/ImageWrapper.h
+++ b/Logic/ImageWrapper/ImageWrapper.h
@@ -36,101 +36,107 @@
 #define __ImageWrapper_h_
 
 // Smart pointers have to be included from ITK, can't forward reference them
-#include "SNAPCommon.h"
-#include "ImageCoordinateTransform.h"
+#include "ImageWrapperBase.h"
+#include "ImageCoordinateGeometry.h"
 #include <itkImageRegionIterator.h>
-#include <itkOrientedImage.h>
+#include <itkVectorImage.h>
 #include <itkRGBAPixel.h>
+#include <DisplayMappingPolicy.h>
+#include <itkSimpleDataObjectDecorator.h>
 
 // Forward declarations to IRIS classes
-template <class TPixel> class IRISSlicer;
+template <class TInputImage, class TOutputImage> class IRISSlicer;
+template <class TFunctor> class UnaryValueToValueFilter;
+
 class SNAPSegmentationROISettings;
 namespace itk {
   template <unsigned int VDimension> class ImageBase;
+  template <class TImage> class ImageSource;
 }
 
+#include <itkImageSource.h>
 
 
 
 /**
  * \class ImageWrapper
- * \brief Abstract parent class for all image wrappers
- * \see ImageWrapper
- */
-class ImageWrapperBase
-{
-public:
-
-  // Definition for the display slice type
-  typedef itk::RGBAPixel<unsigned char> DisplayPixelType;
-  typedef itk::Image<DisplayPixelType,2> DisplaySliceType;
-  typedef itk::SmartPointer<DisplaySliceType> DisplaySlicePointer;
-
-  virtual ~ImageWrapperBase() { /*To avoid compiler warning.*/ }
-  virtual const ImageCoordinateTransform &GetImageToDisplayTransform(
-    unsigned int) const = 0;
-  virtual void SetImageToDisplayTransform(
-    unsigned int, const ImageCoordinateTransform &) = 0;
-  virtual Vector3ui GetSliceIndex() const = 0;
-  virtual void SetSliceIndex(const Vector3ui &) = 0;
-  virtual itk::ImageBase<3> *GetImageBase() const = 0;
-  virtual bool IsInitialized() const = 0;
-  virtual Vector3ui GetSize() const = 0;
-  virtual unsigned char GetAlpha() const = 0;
-  virtual void SetAlpha(unsigned char) = 0;
-  virtual void ToggleVisibility() = 0;
-  virtual itk::ImageRegion<3> GetBufferedRegion() const = 0;
-  virtual Vector3d TransformVoxelIndexToPosition(const Vector3ui &iVoxel) const = 0;
-  virtual Vector3d TransformVoxelIndexToNIFTICoordinates(const Vector3d &iVoxel) const = 0;
-  virtual Vector3d TransformNIFTICoordinatesToVoxelIndex(const Vector3d &vNifti) const = 0;
-  virtual vnl_matrix_fixed<double, 4, 4> GetNiftiSform() const = 0;
-  virtual DisplaySlicePointer GetDisplaySlice(unsigned int dim) const = 0;
-
-  // Delete internal data structures
-  virtual void Reset() = 0;
-};
-
-/**
- * \class ImageWrapper
  * \brief A wrapper around an itk::OrientedImage and related pipelines.
  * 
  * Image Wrapper serves as a wrapper around an image pointer, and 
  * is used to unify the treatment of different kinds of images in
- * SNaP.  
+ * SNaP. The image wrapper is parameterized by a base class TBase.
+ * This is done to avoid multiple inheritance. TBase must be a
+ * subclass of ImageWrapperBase.
  */
-template<class TPixel> class ImageWrapper : public ImageWrapperBase
+template<class TTraits, class TBase = ImageWrapperBase>
+class ImageWrapper : public TBase
 {
 public:
 
+  // Standard ITK business
+  typedef ImageWrapper<TTraits, TBase>                                    Self;
+  typedef TBase                                                     Superclass;
+  typedef SmartPtr<Self>                                               Pointer;
+  typedef SmartPtr<const Self>                                    ConstPointer;
+  itkTypeMacro(ImageWrapper, TBase)
+
   // Basic type definitions
-  typedef itk::OrientedImage<TPixel,3> ImageType;
-  typedef typename itk::SmartPointer<ImageType> ImagePointer;
+  typedef typename Superclass::ImageBaseType                     ImageBaseType;
+  typedef typename TTraits::ImageType                                ImageType;
+  typedef SmartPtr<ImageType>                                     ImagePointer;
+  typedef typename ImageType::PixelType                              PixelType;
+
+  // This is the pixel type of the buffer pointer, i.e., internal representation
+  typedef typename ImageType::InternalPixelType              InternalPixelType;
+
+  // This is the type of the outwardly visible components in the image. For
+  // wrappers that encapsulate 'real' images and vector images, this is the same
+  // as the internal pixel type, but for wrappers that encapsulate an image
+  // adaptor, the component type is the output type of the adaptor
+  typedef typename TTraits::ComponentType                        ComponentType;
 
   // Slice image type
-  typedef itk::Image<TPixel,2> SliceType;
-  typedef typename itk::SmartPointer<SliceType> SlicePointer;
+  typedef itk::Image<PixelType,2>                                    SliceType;
+  typedef SmartPtr<SliceType>                                     SlicePointer;
+
+  // Display slice type - inherited
+  typedef typename Superclass::DisplayPixelType               DisplayPixelType;
+  typedef typename Superclass::DisplaySliceType               DisplaySliceType;
+  typedef typename Superclass::DisplaySlicePointer         DisplaySlicePointer;
 
   // Slicer type
-  typedef IRISSlicer<TPixel> SlicerType;
-  typedef typename itk::SmartPointer<SlicerType> SlicerPointer;
+  typedef IRISSlicer<ImageType, SliceType>                          SlicerType;
+  typedef SmartPtr<SlicerType>                                   SlicerPointer;
+
+  // Preview source for preview pipelines
+  typedef itk::ImageSource<ImageType>                        PreviewFilterType;
 
   // Iterator types
-  typedef typename itk::ImageRegionIterator<ImageType> Iterator;
-  typedef typename itk::ImageRegionConstIterator<ImageType> ConstIterator;
+  typedef typename itk::ImageRegionIterator<ImageType>                Iterator;
+  typedef typename itk::ImageRegionConstIterator<ImageType>      ConstIterator;
 
-  /** 
-   * Default constructor.  Creates an image wrapper with a blank internal 
-   * image 
-   */
-  ImageWrapper();
+  // Other types from parent
+  typedef typename Superclass::TransformType                     TransformType;
 
-  /** 
-   * Copy constructor.  Copies the contents of the passed-in image wrapper. 
+  // Internal intensity to display intensity mapping
+  typedef typename TTraits::DisplayMapping                      DisplayMapping;
+
+  // Native intensity mapping
+  typedef typename TTraits::NativeIntensityMapping      NativeIntensityMapping;
+
+  // Objects used to represent min/max intensity in the image
+  typedef itk::SimpleDataObjectDecorator<ComponentType>    ComponentTypeObject;
+  typedef itk::SimpleDataObjectDecorator<double>                  DoubleObject;
+
+  /**
+   * Get the parent wrapper for this wrapper. For 'normal' wrappers, this method
+   * returns NULL, indicating that the wrapper is a top-level wrapper. For derived
+   * wrappers (i.e., components and scalar representations of vector wrappers),
+   * this method returns the vector wrapper from which the wrapper is derived.
+   *
+   * You should not have to call the SetParentWrapper method. It's used internally
    */
-  ImageWrapper(const ImageWrapper<TPixel> &copy);
-  
-  /** Destructor */
-  virtual ~ImageWrapper();
+  irisGetSetMacro(ParentWrapper, ImageWrapperBase *)
 
   /**
    * Initialize the image wrapper to match another image wrapper, setting the
@@ -138,7 +144,7 @@ public:
    * all be updated to match the source
    */
   virtual void InitializeToWrapper(
-    const ImageWrapperBase *source, const TPixel &value);
+    const ImageWrapperBase *source, const PixelType &value);
 
   /** 
    * Initialize the image wrapper with a combination of another image wrapper and
@@ -149,41 +155,130 @@ public:
     const ImageWrapperBase *source, ImageType *image);
 
   /**
-   * Initialize the internal image to a blank image of size x,y,z.
-   */
-  // virtual void InitializeToSize(unsigned int x, unsigned int y,unsigned int z);
+    Get a unique id for this wrapper. All wrappers ever created have
+    different ids.
+    */
+  irisGetMacro(UniqueId, unsigned long)
 
   /**
    * Clear the data associated with storing an image
    */
   virtual void Reset();
 
+  /** Get the coordinate transform for each display slice */
+  virtual const ImageCoordinateTransform &GetImageToDisplayTransform(
+    unsigned int) const;
+
+  /**
+   * Set the coordinate transformation between the display coordinates and
+   * the anatomical coordinates. This affects the behavior of the slicers
+   */
+  virtual void SetDisplayGeometry(IRISDisplayGeometry &dispGeom);
+
+  /** Get the display to anatomy coordinate mapping */
+  irisGetMacro(DisplayGeometry, const IRISDisplayGeometry &)
+
+  /** Set the direction matrix of the image */
+  virtual void SetDirectionMatrix(const vnl_matrix<double> &direction);
+
+  /**
+   * Set the image coordinate transform (origin, spacing, direction) to
+   * match those of a reference wrapper
+   */
+  virtual void CopyImageCoordinateTransform(const ImageWrapperBase *source);
+
+  /**
+   * Get the image geometry from the wrapper
+   */
+  irisGetMacro(ImageGeometry, const ImageCoordinateGeometry &)
+
+
+  /** Get the current slice index */
+  irisGetMacro(SliceIndex, Vector3ui)
+
+  /** Return some image info independently of pixel type */
+  ImageBaseType* GetImageBase() const { return m_Image; }
+
   /**
    * Is the image initialized?
    */
-  virtual bool IsInitialized() const;
+  irisIsMacro(Initialized)
 
   /**
-   * Get reference to a voxel at a given position.
+   * Get the size of the image
    */
-  virtual TPixel &GetVoxelForUpdate(unsigned int x, 
-                                    unsigned int y, 
-                                    unsigned int z);
-  
-  virtual TPixel &GetVoxelForUpdate(const Vector3ui &index);
-  
+  Vector3ui GetSize() const;
+
+  /** Get layer transparency */
+  irisSetWithEventMacro(Alpha, double, WrapperDisplayMappingChangeEvent)
+
+  /** Set layer transparency */
+  irisGetMacro(Alpha, double)
+
+  /**
+   * Get layer stickiness. A sticky layer always is shown 'on top' of other
+   * layers, e.g., the segmentation layer, or the level set image. A layer that
+   * is not sticky is shown in its own tile when the display is in tiled mode
+   */
+  irisSetWithEventMacro(Sticky, bool, WrapperVisibilityChangeEvent)
+
+  /** Set layer stickiness */
+  irisIsMacro(Sticky)
+
+  /**
+   * Whether the layer is drawable. Some layers may be initialized, but not
+   * yet computed, in which case they should not yet be drawn.
+   */
+  virtual bool IsDrawable() const;
+
+  /** Get the buffered region of the image */
+  virtual itk::ImageRegion<3> GetBufferedRegion() const;
+
+  /** Transform a voxel index into a spatial position */
+  virtual Vector3d TransformVoxelIndexToPosition(const Vector3ui &iVoxel) const;
+
+  /** Transform a voxel index into NIFTI coordinates (RAS) */
+  virtual Vector3d TransformVoxelIndexToNIFTICoordinates(const Vector3d &iVoxel) const;
+
+  /** Transform NIFTI coordinates to a continuous voxel index */
+  virtual Vector3d TransformNIFTICoordinatesToVoxelIndex(const Vector3d &vNifti) const;
+
+  /** Get the NIFTI s-form matrix for this image */
+  irisGetMacro(NiftiSform, TransformType)
+
+  /** Get the inverse NIFTI s-form matrix for this image */
+  irisGetMacro(NiftiInvSform, TransformType)
+
+  /** Set the voxel at a given position.*/
+  void SetVoxel(const Vector3ui &index, const PixelType &value);
+  void SetVoxel(const itk::Index<3> &index, const PixelType &value);
+
   /**
    * Get a constant reference to a voxel at a given position.
    */
-  virtual const TPixel &GetVoxel(unsigned int x, 
-                                 unsigned int y, 
-                                 unsigned int z) const;
+  PixelType GetVoxel(unsigned int x,
+                     unsigned int y,
+                     unsigned int z) const;
 
-  virtual const TPixel &GetVoxel(const Vector3ui &index) const;
+  PixelType GetVoxel(const Vector3ui &index) const;
 
-  /** Return some image info independently of pixel type */
-  virtual itk::ImageBase<3> *GetImageBase() const
-    { return m_Image.GetPointer(); }
+  PixelType GetVoxel(const itk::Index<3> &index) const;
+
+  /**
+   * Get the mapping between the internal data type and the 'native' range,
+   * i.e., the range of values shown to the user. This may be a linear mapping
+   * or an identity mapping. This method returns an abstract type;
+   */
+  virtual const AbstractNativeIntensityMapping *GetNativeIntensityMapping() const
+    { return &m_NativeMapping; }
+
+  /** These methods access the native mapping in its actual type */
+  irisGetMacro(NativeMapping, NativeIntensityMapping)
+  irisSetMacro(NativeMapping, NativeIntensityMapping)
+
+  /** Get the intensity to display mapping */
+  DisplayMapping *GetDisplayMapping()
+    { return m_DisplayMapping; }
 
   /** 
    * Return the pointed to the ITK image encapsulated by this wrapper.
@@ -198,20 +293,6 @@ public:
     { return m_Slicer[iDirection]; }
 
   /**
-   * Get the size of the image
-   */
-  virtual Vector3ui GetSize() const;
-
-  /**
-   * Get the buffered region of the image
-   */
-  virtual itk::ImageRegion<3> GetBufferedRegion() const
-    { return m_Image->GetBufferedRegion(); }
-
-  /** Get the current slice index */
-  virtual Vector3ui GetSliceIndex() const;
-
-  /**
    * Set the current slice index in all three dimensions.  The index should
    * be specified in the image coordinates, the slices will be generated
    * in accordance with the transforms that are specified
@@ -219,22 +300,23 @@ public:
   virtual void SetSliceIndex(const Vector3ui &cursor);
 
   /**
-   * Set the trasforms from image space to one of the three display slices (be
-   * sure to set all three, or you'll get weird looking slices!
+   * Get an ITK pipeline object holding the minimum value in the image. For
+   * multi-component images, this is the minimum value over all components.
    */
-  virtual void SetImageToDisplayTransform(
-    unsigned int iSlice,const ImageCoordinateTransform &transform);
+  virtual ComponentTypeObject *GetImageMinObject() const = 0;
+  virtual ComponentTypeObject *GetImageMaxObject() const = 0;
 
-  /** Get the coordinate transform for each display slice */
-  virtual const ImageCoordinateTransform &GetImageToDisplayTransform(
-    unsigned int iSlice) const;
+  /** Return componentwise minimum cast to double, without mapping to native range */
+  virtual double GetImageMinAsDouble();
 
-  /**
-   * Use a default image-slice transformation, the first slice is along z,
-   * the second along y, the third, along x, all directions of traversal are 
-   * positive.
-   */
-  virtual void SetImageToDisplayTransformsToDefault();
+  /** Return componentwise maximum cast to double, without mapping to native range */
+  virtual double GetImageMaxAsDouble();
+
+  /** Return componentwise minimum cast to double, after mapping to native range */
+  virtual double GetImageMinNative();
+
+  /** Return componentwise maximum cast to double, after mapping to native range */
+  virtual double GetImageMaxNative();
 
   /**
    * Get a slice of the image in a given direction
@@ -244,13 +326,11 @@ public:
   /**
    * This method exposes the scalar pointer in the image
    */
-  virtual TPixel *GetVoxelPointer() const;
+  virtual InternalPixelType *GetVoxelPointer() const;
+
+  /** Number of voxels */
+  virtual size_t GetNumberOfVoxels() const;
 
-  /**
-   * Get the number of voxels
-   */
-  size_t GetNumberOfVoxels() const;
-    
   /**
    * Pring debugging info
    * TODO: Delete this or make is worthwhile
@@ -263,12 +343,21 @@ public:
   virtual void SetImage(ImagePointer newImage);
 
   /**
+   * Extract a region of interest from the image wrapper, as a new wrapper of
+   * the same type
+   */
+  virtual SmartPtr<ImageWrapperBase> ExtractROI(
+      const SNAPSegmentationROISettings &roi, itk::Command *progressCommand) const;
+
+
+  /**
    * This method is used to perform a deep copy of a region of this image 
    * into another image, potentially resampling the region to use a different
    * voxel size
    */
   virtual ImagePointer DeepCopyRegion(const SNAPSegmentationROISettings &roi,
-                              itk::Command *progressCommand = NULL) const = 0;
+                              itk::Command *progressCommand = NULL) const;
+
 
   /**
    * Get an iterator for traversing the image.  The iterator is initialized
@@ -280,120 +369,221 @@ public:
   /** For each slicer, find out which image dimension does is slice along */
   unsigned int GetDisplaySliceImageAxis(unsigned int slice);
 
-  /** Transform a voxel index into a spatial position */
-  Vector3d TransformVoxelIndexToPosition(const Vector3ui &iVoxel) const;
-
-  /** Transform a voxel index into NIFTI coordinates (RAS) */
-  Vector3d TransformVoxelIndexToNIFTICoordinates(const Vector3d &iVoxel) const;
-
-  /** Transform NIFTI coordinates to a continuous voxel index */
-  Vector3d TransformNIFTICoordinatesToVoxelIndex(const Vector3d &vNifti) const;
-
   /** 
    * Replace all voxels with intensity values iOld with values iNew. 
    * \return number of voxels that had been modified
    */
-  virtual unsigned int ReplaceIntensity(TPixel iOld, TPixel iNew);
+  virtual unsigned int ReplaceIntensity(PixelType iOld, PixelType iNew);
 
   /** 
    * Swap intensity values iFirst and iSecond
    * \return number of voxels that had been modified
    */
-  virtual unsigned int SwapIntensities(TPixel iFirst, TPixel iSecond);
+  virtual unsigned int SwapIntensities(PixelType iFirst, PixelType iSecond);
 
-  /** Get the NIFTI s-form matrix for this image */
-  virtual vnl_matrix_fixed<double, 4, 4> GetNiftiSform() const
-    { return m_NiftiSform; }
+  /**
+   * Get the display slice
+   */
+  DisplaySlicePointer GetDisplaySlice(unsigned int dim);
 
-  /** 
-   * This static function constructs a NIFTI matrix from the ITK direction
-   * cosines matrix and Spacing and Origin vectors
-   */
-  static vnl_matrix_fixed<double,4,4> ConstructNiftiSform(
-    vnl_matrix<double> m_dir, 
-    vnl_vector<double> v_origin,
-    vnl_vector<double> v_spacing)
-  {
-    // Set the NIFTI/RAS transform
-    vnl_matrix<double> m_ras_matrix;
-    vnl_diag_matrix<double> m_scale, m_lps_to_ras;
-    vnl_vector<double> v_ras_offset;
-
-    // Compute the matrix
-    m_scale.set(v_spacing);
-    m_lps_to_ras.set(vnl_vector<double>(3, 1.0));
-    m_lps_to_ras[0] = -1;
-    m_lps_to_ras[1] = -1;
-    m_ras_matrix = m_lps_to_ras * m_dir * m_scale;
-
-    // Compute the vector
-    v_ras_offset = m_lps_to_ras * v_origin;
-
-    // Create the larger matrix
-    vnl_vector<double> vcol(4, 1.0);
-    vcol.update(v_ras_offset);
-    
-    vnl_matrix_fixed<double,4,4> m_sform;
-    m_sform.set_identity();
-    m_sform.update(m_ras_matrix);
-    m_sform.set_column(3, vcol);
-    return m_sform;
-  }
-
-  static vnl_matrix_fixed<double,4,4> ConstructVTKtoNiftiTransform(
-    vnl_matrix<double> m_dir, 
-    vnl_vector<double> v_origin,
-    vnl_vector<double> v_spacing)
-    {
-    vnl_matrix_fixed<double,4,4> vox2nii = ConstructNiftiSform(m_dir, v_origin, v_spacing);
-    vnl_matrix_fixed<double,4,4> vtk2vox; 
-    vtk2vox.set_identity();
-    for(size_t i = 0; i < 3; i++)
-      {
-      vtk2vox(i,i) = 1.0 / v_spacing[i];
-      vtk2vox(i,3) = - v_origin[i] / v_spacing[i];
-      }
-    return vox2nii * vtk2vox;
-    }
-
-  /**
-   * Get/Set the alpha
-   */
-  irisSetMacro(Alpha, unsigned char);
-  irisGetMacro(Alpha, unsigned char);
-  virtual void ToggleVisibility();
+  /**
+    Attach a preview pipeline to the wrapper. This is used with wrappers that
+    represent results of image processing operations, such as speed images.
+    A preview pipeline consists of a filter for each of the three slice
+    directions. When the upstream information in these filters is newer than
+    the image volume stored in the wrapper, the slices returned with
+    GetDisplaySlice() will be those from the preview filters rather than from
+    the image volume.
+    */
+  virtual void AttachPreviewPipeline(
+      PreviewFilterType *f0, PreviewFilterType *f1, PreviewFilterType *f2);
+
+  /**
+    Detach the preview pipeline from the wrapper. The wrapper will always
+    return slices from the internally stored image volume.
+    */
+  virtual void DetachPreviewPipeline();
+
+  /**
+    Report whether the preview pipeline is attached.
+    */
+  virtual bool IsPreviewPipelineAttached() const;
+
+  /**
+   * A flag governing whether the preview pipeline is ready or not. This is
+   * used to determine whether the layer is drawable (only relevant if the
+   * pipeline is attached)
+   */
+  irisIsMacro(PipelineReady)
+  irisSetMacro(PipelineReady, bool)
+
+
+  virtual void* GetVoxelVoidPointer() const;
+
+  /**
+   * Set the filename of the image wrapper. If the wrapper does not have a
+   * nickname, the nickname will be changed to the file part of the filename.
+   */
+  void SetFileName(const std::string &name);
+
+
+  // Access the filename
+  irisGetStringMacro(FileName)
+
+  /**
+   * Fallback nickname - shown if no filename and no custom nickname set.
+   */
+  irisGetSetMacro(DefaultNickname, const std::string &)
+
+  /**
+   * Get the nickname of the image. A nickname is a shorter description of the
+   * image that is displayed to the user. If a custom nickname is not set, it
+   * defaults to the filename (without path). If there is no filename (i.e.,
+   * the layer is internal), the default nickname is used.
+   */
+  const std::string &GetNickname() const;
+
+  /**
+   * Set the custom nickname for the wrapper.
+   */
+  virtual void SetCustomNickname(const std::string &nickname);
+  irisGetMacro(CustomNickname, const std::string &);
+
+
+  /**
+   * Write the image to disk with the help of the GuidedNativeImageIO object
+   */
+  virtual void WriteToFile(const char *filename, Registry &hints);
+
+  /**
+   * Create a thumbnail from the image and write it to a .png file
+   */
+  void WriteThumbnail(const char *filename, unsigned int maxdim);
+
+  /**
+   * Save metadata to a Registry file. The metadata are data that are not
+   * contained in the image header are need to be restored when the image
+   * is reloaded. Currently, this mainly includes the display mapping, but
+   * also the transparency, etc.
+   */
+  virtual void WriteMetaData(Registry &reg);
+
+  /**
+   * Restore metadata from a registry
+   */
+  virtual void ReadMetaData(Registry &reg);
+
+  /**
+   * Check if the image has unsaved changes
+   */
+  virtual bool HasUnsavedChanges() const;
+
+  /**
+   * The image wrapper has a generic mechanism for associating data with it.
+   * For example, we can associate some parameter values for a specific
+   * image processing algorithm with each layer. Do do that, we simply
+   * assign a pointer to the data to a specific string role. Internally,
+   * a smart pointer is used to point to the associated data.
+   *
+   * Users of this method might also want to rebroadcast events from the
+   * associated object as events of type WrapperUserChangeEvent(). These
+   * events will then propagate all the way up to the IRISApplication.
+   */
+  void SetUserData(const std::string &role, itk::Object *data);
+
+  /**
+   * Get the user data associated with this wrapper for a specific role. If
+   * no association exists, NULL is returned. The method is templated over the
+   * return type to avoid casting in user code.
+   */
+  itk::Object* GetUserData(const std::string &role) const;
 
 protected:
 
+  /**
+   * Default constructor.  Creates an image wrapper with a blank internal
+   * image
+   */
+  ImageWrapper();
+
+  /**
+   * Copy constructor.  Copies the contents of the passed-in image wrapper.
+   */
+  ImageWrapper(const Self &copy);
+
+  /** Destructor */
+  virtual ~ImageWrapper();
+
+  /** A unique Id of this wrapper. Used for the LayerAssociation code */
+  unsigned long m_UniqueId;
+
   /** The image that we are wrapping */
   ImagePointer m_Image;
 
   /** The associated slicer filters */
   SlicerPointer m_Slicer[3];
 
+  /** The wrapped image */
+  SmartPtr<ImageBaseType> m_ImageBase;
+
   /** The current cursor position (slice index) in image dimensions */
   Vector3ui m_SliceIndex;
 
   /**
-   * Is the image wrapper initialized? That is a prerequisite for all 
+   * Is the image wrapper initialized? That is a prerequisite for all
    * operations.
    */
   bool m_Initialized;
 
+  /** Pipeline readiness */
+  bool m_PipelineReady;
+
   /** Transparency */
-  unsigned char m_Alpha;
-  
-  /** A 'saved' value of alpha for when visibility is toggled */
-  unsigned char m_ToggleAlpha;
+  double m_Alpha;
+
+  /** Stickiness (whether the layer can be tiled or not) */
+  bool m_Sticky;
+
+  /** Time when the internal image was allocated, and when it was last saved */
+  itk::TimeStamp m_ImageAssignTime, m_ImageSaveTime;
+
+  /** The pipeline that handles mapping intensities to the display slices */
+  SmartPtr<DisplayMapping> m_DisplayMapping;
+
+  // Mapping from native to internal format
+  NativeIntensityMapping m_NativeMapping;
 
-  /** Transform from image space to display space */
-  ImageCoordinateTransform m_ImageToDisplayTransform[3];
+  // Mapping between the display coordinates and anatomical coordinates
+  IRISDisplayGeometry m_DisplayGeometry;
 
-  /** Transform from image space to display space */
-  ImageCoordinateTransform m_DisplayToImageTransform[3];
+  // This object encapsulates information about the coordinate mapping between
+  // the image coordinate space, the anatomical coordinate space, and the
+  // display coordinate space. It depends on three parameters: the size of the
+  // image, the Direction cosine matrix of the image, and the DisplayGeometry
+  // (transformation between the display and the anatomy spaces).
+  //
+  // The code should not directly modify this variable. It should only be
+  // modified by the UpdateImageGeometry() method.
+  ImageCoordinateGeometry m_ImageGeometry;
 
-  // Transform from image index to NIFTI world coordinates
-  vnl_matrix_fixed<double, 4, 4> m_NiftiSform, m_NiftiInvSform;
+  // Transform from image index to NIFTI world coordinates. This is derived
+  // from the origin, spacing, and direction cosine matrix in the image header.
+  TransformType m_NiftiSform, m_NiftiInvSform;
+
+  // Each layer has a filename, from which it is belived to have come
+  std::string m_FileName, m_FileNameShort;
+
+  // Each layer has a nickname. But this gets complicated, because the nickname
+  // can be set by the user, or it can be default for the wrapper, or it can be
+  // derived from the filename. The nicknames are used in the following order.
+  // - if there is a custom nickname, it is shown
+  // - if there is a filename, nickname is set to the shortened filename
+  // - if there is no filename, nickname is set to the default nickname
+  std::string m_DefaultNickname, m_CustomNickname;
+
+  // A map to store user-associated data
+  typedef std::map<std::string, SmartPtr<itk::Object> > UserDataMapType;
+  UserDataMapType m_UserDataMap;
 
   /**
    * Handle a change in the image pointer (i.e., a load operation on the image or 
@@ -401,8 +591,24 @@ protected:
    */
   virtual void UpdateImagePointer(ImageType *);
 
+  /**
+   * Update the image geometry (combining the information in the image and the
+   * information in the m_DisplayGeometry variable)
+   */
+  virtual void UpdateImageGeometry();
+
+  /**
+   * Update the NIFTI header. This should be called whenever the spacing,
+   * origin, or direction cosine matrix of the image are changed
+   */
+  virtual void UpdateNiftiTransforms();
+
   /** Common code for the different constructors */
   void CommonInitialization();
+
+  /** Parent wrapper */
+  ImageWrapperBase *m_ParentWrapper;
+
 };
 
 #endif // __ImageWrapper_h_
diff --git a/Logic/ImageWrapper/ImageWrapper.txx b/Logic/ImageWrapper/ImageWrapper.txx
deleted file mode 100644
index be7899f..0000000
--- a/Logic/ImageWrapper/ImageWrapper.txx
+++ /dev/null
@@ -1,565 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ImageWrapper.txx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/14 16:21:04 $
-  Version:   $Revision: 1.11 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __ImageWrapper_txx_
-#define __ImageWrapper_txx_
-
-#include "ImageWrapper.h"
-#include "itkImageRegionIterator.h"
-#include "itkImageSliceConstIteratorWithIndex.h"
-#include "itkNumericTraits.h"
-#include "itkRegionOfInterestImageFilter.h"
-#include "itkIdentityTransform.h"
-#include "IRISSlicer.h"
-#include "SNAPSegmentationROISettings.h"
-#include "itkCommand.h"
-
-#include <vnl/vnl_inverse.h>
-#include <iostream>
-
-template <class TPixel> 
-ImageWrapper<TPixel>
-::ImageWrapper() 
-{
-  CommonInitialization();
-}
-
-template <class TPixel>
-ImageWrapper<TPixel>
-::~ImageWrapper() 
-{
-  Reset();
-}
-
-template <class TPixel>
-void 
-ImageWrapper<TPixel>
-::CommonInitialization()
-{
-  // Set initial state    
-  m_Initialized = false;
-
-  // Create slicer objects
-  m_Slicer[0] = SlicerType::New();
-  m_Slicer[1] = SlicerType::New();
-  m_Slicer[2] = SlicerType::New();
-
-  // Set the transform to identity, which will initialize the directions of the
-  // slicers
-  this->SetImageToDisplayTransformsToDefault();
-}
-
-template <class TPixel>
-ImageWrapper<TPixel>
-::ImageWrapper(const ImageWrapper<TPixel> &copy) 
-{
-  CommonInitialization();
-
-  // If the source contains an image, make a copy of that image
-  if (copy.IsInitialized() && copy.GetImage())
-    {
-    // Create and allocate the image
-    ImagePointer newImage = ImageType::New();
-    newImage->SetRegions(copy.GetImage()->GetBufferedRegion());
-    newImage->Allocate();
-
-    // Copy the image contents
-    TPixel *ptrTarget = newImage->GetBufferPointer();
-    TPixel *ptrSource = copy.GetImage()->GetBufferPointer();
-    memcpy(ptrTarget,ptrSource,
-           sizeof(TPixel) * newImage->GetBufferedRegion().GetNumberOfPixels());
-    
-    UpdateImagePointer(newImage);
-    }
-}
-
-template <class TPixel> 
-void 
-ImageWrapper<TPixel>
-::PrintDebugInformation() 
-{
-  std::cout << "=== Image Properties ===" << std::endl;
-  std::cout << "   Dimensions         : " << m_Image->GetLargestPossibleRegion().GetSize() << std::endl;
-  std::cout << "   Origin             : " << m_Image->GetOrigin() << std::endl;
-  std::cout << "   Spacing            : " << m_Image->GetSpacing() << std::endl;
-  std::cout << "------------------------" << std::endl;
-}
-
-template <class TPixel>
-void 
-ImageWrapper<TPixel>
-::UpdateImagePointer(ImageType *newImage) 
-{
-  // Check if the image size has changed
-  bool hasSizeChanged = 
-    (!m_Image) || 
-    (newImage->GetLargestPossibleRegion().GetSize() !=
-     m_Image->GetLargestPossibleRegion().GetSize());
-  
-  // Change the input of the slicers 
-  m_Slicer[0]->SetInput(newImage);
-  m_Slicer[1]->SetInput(newImage);
-  m_Slicer[2]->SetInput(newImage);
-    
-  // If so, the coordinate transform needs to be reinitialized to identity
-  if(hasSizeChanged)
-    {
-    // Reset the transform to identity
-    this->SetImageToDisplayTransformsToDefault();
-
-    // Reset the slice positions to zero
-    this->SetSliceIndex(Vector3ui(0,0,0));
-    }
-  
-  // Update the image
-  m_Image = newImage;
-
-  // Mark the image as Modified to enforce correct sequence of 
-  // operations with MinMaxCalc
-  m_Image->Modified();
-
-  // Set the NIFTI/RAS transform
-  m_NiftiSform = ConstructNiftiSform(
-    m_Image->GetDirection().GetVnlMatrix(),
-    m_Image->GetOrigin().GetVnlVector(),
-    m_Image->GetSpacing().GetVnlVector());
-  m_NiftiInvSform = vnl_inverse(m_NiftiSform);
-
-  // We have been initialized
-  m_Initialized = true;
-}
-
-template <class TPixel>
-void 
-ImageWrapper<TPixel>
-::InitializeToWrapper(const ImageWrapperBase *source, ImageType *image) 
-{
-  // Call the common update method
-  UpdateImagePointer(image);
-
-  // Update the image-display transforms
-  for(unsigned int d=0;d<3;d++)
-    SetImageToDisplayTransform(d,source->GetImageToDisplayTransform(d));
-
-  // Update the slice index
-  SetSliceIndex(source->GetSliceIndex());
-}
-
-template <class TPixel>
-void 
-ImageWrapper<TPixel>
-::InitializeToWrapper(const ImageWrapperBase *source, const TPixel &value) 
-{
-  // Allocate the image
-  ImagePointer newImage = ImageType::New();
-  newImage->SetRegions(source->GetImageBase()->GetBufferedRegion().GetSize());
-  newImage->Allocate();
-  newImage->FillBuffer(value);
-  newImage->SetOrigin(source->GetImageBase()->GetOrigin());
-  newImage->SetSpacing(source->GetImageBase()->GetSpacing());
-  newImage->SetDirection(source->GetImageBase()->GetDirection());
-
-  // Call the common update method
-  UpdateImagePointer(newImage);
-
-  // Update the image-display transforms
-  for(unsigned int d=0;d<3;d++)
-    SetImageToDisplayTransform(d,source->GetImageToDisplayTransform(d));
-
-  // Update the slice index
-  SetSliceIndex(source->GetSliceIndex());
-}
-
-template <class TPixel>
-void 
-ImageWrapper<TPixel>
-::SetImage(ImagePointer newImage) 
-{
-  UpdateImagePointer(newImage);
-}
-
-
-template <class TPixel>
-void 
-ImageWrapper<TPixel>
-::Reset() 
-{
-  if (m_Initialized)
-    {
-    m_Image->ReleaseData();
-    m_Image = NULL;
-    }
-  m_Initialized = false;
-
-  m_Alpha = 128;
-  m_ToggleAlpha = 128;
-}
-
-template <class TPixel>
-bool 
-ImageWrapper<TPixel>
-::IsInitialized() const 
-{
-  return m_Initialized;
-}
-
-template <class TPixel>
-inline const TPixel& 
-ImageWrapper<TPixel>
-::GetVoxel(const Vector3ui &index) const 
-{
-  return GetVoxel(index[0],index[1],index[2]);
-}
-
-template <class TPixel>
-inline TPixel& 
-ImageWrapper<TPixel>
-::GetVoxelForUpdate(const Vector3ui &index) 
-{
-  return GetVoxelForUpdate(index[0],index[1],index[2]);
-}
-
-template <class TPixel>
-inline TPixel& 
-ImageWrapper<TPixel>
-::GetVoxelForUpdate(unsigned int x, unsigned int y, unsigned int z) 
-{
-  itk::Index<3> index;
-  index[0] = x;
-  index[1] = y;
-  index[2] = z;
-
-  // Verify that the pixel is contained by the image at debug time
-  assert(m_Image && m_Image->GetLargestPossibleRegion().IsInside(index));
-
-  // Return the pixel
-  return m_Image->GetPixel(index);
-}
-
-template <class TPixel>
-inline const TPixel& 
-ImageWrapper<TPixel>
-::GetVoxel(unsigned int x, unsigned int y, unsigned int z) const
-{
-  itk::Index<3> index;
-  index[0] = x;
-  index[1] = y;
-  index[2] = z;
-
-  // Verify that the pixel is contained by the image at debug time
-  assert(m_Image && m_Image->GetLargestPossibleRegion().IsInside(index));
-
-  // Return the pixel
-  return m_Image->GetPixel(index);
-}
-
-template <class TPixel> 
-typename ImageWrapper<TPixel>::ConstIterator 
-ImageWrapper<TPixel>
-::GetImageConstIterator() const 
-{
-  ConstIterator it(m_Image,m_Image->GetLargestPossibleRegion());
-  it.GoToBegin();
-  return it;
-}
-
-template <class TPixel> 
-typename ImageWrapper<TPixel>::Iterator 
-ImageWrapper<TPixel>
-::GetImageIterator() 
-{
-  Iterator it(m_Image,m_Image->GetLargestPossibleRegion());
-  it.GoToBegin();
-  return it;
-}
-
-template <class TPixel>    
-Vector3ui
-ImageWrapper<TPixel>
-::GetSliceIndex() const
-{
-  return m_SliceIndex;
-}
-
-template <class TPixel>    
-void 
-ImageWrapper<TPixel>
-::SetSliceIndex(const Vector3ui &cursor)
-{
-  // Save the cursor position
-  m_SliceIndex = cursor;
-
-  // Select the appropriate slice for each slicer
-  for(unsigned int i=0;i<3;i++)
-  {
-    // Which axis does this slicer slice?
-    unsigned int axis = m_Slicer[i]->GetSliceDirectionImageAxis();
-
-    // Set the slice using that axis
-    m_Slicer[i]->SetSliceIndex(cursor[axis]);
-  }
-}
-
-template <class TPixel>    
-void 
-ImageWrapper<TPixel>
-::SetImageToDisplayTransformsToDefault()
-{
-  ImageCoordinateTransform id[3];
-  id[0].SetTransform(Vector3i(1,2,3),Vector3ui(0,0,0));
-  id[1].SetTransform(Vector3i(1,3,2),Vector3ui(0,0,0));
-  id[2].SetTransform(Vector3i(2,3,1),Vector3ui(0,0,0));
-  SetImageToDisplayTransform(0,id[0]);
-  SetImageToDisplayTransform(1,id[1]);
-  SetImageToDisplayTransform(2,id[2]);
-}
-
-template <class TPixel>    
-const ImageCoordinateTransform&
-ImageWrapper<TPixel>
-::GetImageToDisplayTransform(unsigned int iSlice) const 
-{
-  return m_ImageToDisplayTransform[iSlice];
-}
-
-template <class TPixel>    
-void 
-ImageWrapper<TPixel>
-::SetImageToDisplayTransform(unsigned int iSlice,
-                             const ImageCoordinateTransform &transform)
-{
-  // Get the transform and its inverse
-  m_ImageToDisplayTransform[iSlice] = transform;
-  m_DisplayToImageTransform[iSlice] = transform.Inverse();
-
-  // Tell slicer in which directions to slice
-  m_Slicer[iSlice]->SetSliceDirectionImageAxis(
-    m_DisplayToImageTransform[iSlice].GetCoordinateIndexZeroBased(2));
-  
-  m_Slicer[iSlice]->SetLineDirectionImageAxis(
-    m_DisplayToImageTransform[iSlice].GetCoordinateIndexZeroBased(1));
-
-  m_Slicer[iSlice]->SetPixelDirectionImageAxis(
-    m_DisplayToImageTransform[iSlice].GetCoordinateIndexZeroBased(0));
-
-  m_Slicer[iSlice]->SetPixelTraverseForward(
-    m_DisplayToImageTransform[iSlice].GetCoordinateOrientation(0) > 0);
-
-  m_Slicer[iSlice]->SetLineTraverseForward(
-    m_DisplayToImageTransform[iSlice].GetCoordinateOrientation(1) > 0);
-}
-
-
-  /** For each slicer, find out which image dimension does is slice along */
-
-template <class TPixel>    
-unsigned int 
-ImageWrapper<TPixel>
-::GetDisplaySliceImageAxis(unsigned int iSlice)
-{
-  return m_Slicer[iSlice]->GetSliceDirectionImageAxis();
-}
-
-template <class TPixel>
-typename ImageWrapper<TPixel>::SliceType*
-ImageWrapper<TPixel>
-::GetSlice(unsigned int dimension)
-{
-  return m_Slicer[dimension]->GetOutput();
-}
-
-template <class TPixel>
-TPixel *
-ImageWrapper<TPixel>
-::GetVoxelPointer() const
-{
-  return m_Image->GetBufferPointer();
-}
-
-template <class TPixel>
-size_t
-ImageWrapper<TPixel>
-::GetNumberOfVoxels() const
-{
-  return m_Image->GetBufferedRegion().GetNumberOfPixels();
-}
-
-template <class TPixel>
-Vector3ui
-ImageWrapper<TPixel>
-::GetSize() const
-{
-  // Cast the size to our vector format
-  itk::Size<3> size = m_Image->GetLargestPossibleRegion().GetSize();      
-  return Vector3ui(
-    (unsigned int) size[0],
-    (unsigned int) size[1],
-    (unsigned int) size[2]);
-}
-
-template<class TPixel>
-Vector3d
-ImageWrapper<TPixel>
-::TransformVoxelIndexToPosition(const Vector3ui &iVoxel) const
-{
-  // Use the ITK method to do this
-  typename ImageType::IndexType xIndex;
-  for(size_t d = 0; d < 3; d++) xIndex[d] = iVoxel[d];
-  
-  itk::Point<double, 3> xPoint;
-  m_Image->TransformIndexToPhysicalPoint(xIndex, xPoint);
-
-  Vector3d xOut;
-  for(unsigned int q = 0; q < 3; q++) xOut[q] = xPoint[q];
-
-  return xOut;
-}
-
-template<class TPixel>
-Vector3d
-ImageWrapper<TPixel>
-::TransformVoxelIndexToNIFTICoordinates(const Vector3d &iVoxel) const
-{
-  // Create homogeneous vector
-  vnl_vector_fixed<double, 4> x;
-  for(size_t d = 0; d < 3; d++)
-    x[d] = (double) iVoxel[d];
-  x[3] = 1.0;
-
-  // Transform to NIFTI coords
-  vnl_vector_fixed<double, 4> p = m_NiftiSform * x;  
-
-  // Return the component
-  return Vector3d(p.data_block());
-}
-
-template<class TPixel>
-Vector3d
-ImageWrapper<TPixel>
-::TransformNIFTICoordinatesToVoxelIndex(const Vector3d &vNifti) const
-{
-  // Create homogeneous vector
-  vnl_vector_fixed<double, 4> x;
-  for(size_t d = 0; d < 3; d++)
-    x[d] = (double) vNifti[d];
-  x[3] = 1.0;
-
-  // Transform to NIFTI coords
-  vnl_vector_fixed<double, 4> p = m_NiftiInvSform * x;  
-
-  // Return the component
-  return Vector3d(p.data_block());  
-}
-
-template <class TPixel>
-unsigned int 
-ImageWrapper<TPixel>
-::ReplaceIntensity(TPixel iOld, TPixel iNew)
-{
-  // Counter for the number of replaced voxels
-  unsigned int nReplaced = 0;
-
-  // Replace the voxels
-  for(Iterator it = GetImageIterator(); !it.IsAtEnd(); ++it)
-    if(it.Value() == iOld)
-      {
-      it.Set(iNew);
-      ++nReplaced;
-      }
-
-  // Flag that changes have been made
-  if(nReplaced > 0)
-    m_Image->Modified();
-
-  // Return the number of replacements
-  return nReplaced;
-}
-
-template <class TPixel>
-unsigned int 
-ImageWrapper<TPixel>
-::SwapIntensities(TPixel iFirst, TPixel iSecond)
-{
-  // Counter for the number of replaced voxels
-  unsigned int nReplaced = 0;
-
-  // Replace the voxels
-  for(Iterator it = GetImageIterator(); !it.IsAtEnd(); ++it)
-    if(it.Value() == iFirst)
-      {
-      it.Set(iSecond);
-      ++nReplaced;
-      }
-    else if(it.Value() == iSecond)
-      {
-      it.Set(iFirst);
-      ++nReplaced;
-      }
-
-  // Flag that changes have been made
-  if(nReplaced > 0)
-    m_Image->Modified();
-
-  // Return the number of replacements
-  return nReplaced;
-}
-
-template <class TPixel>
-void
-ImageWrapper<TPixel>
-::ToggleVisibility()
-{
-  // If visible (alpha > 0), make invisible
-  if(m_Alpha > 0)
-    {
-    m_ToggleAlpha = m_Alpha;
-    m_Alpha = 0;
-    }
-  // If invisible, return to saved alpha value
-  else
-    {
-    m_Alpha = m_ToggleAlpha;
-    }
-}
-
-
-#endif // __ImageWrapper_txx_
diff --git a/Logic/ImageWrapper/ImageWrapperBase.cxx b/Logic/ImageWrapper/ImageWrapperBase.cxx
new file mode 100644
index 0000000..8126d6f
--- /dev/null
+++ b/Logic/ImageWrapper/ImageWrapperBase.cxx
@@ -0,0 +1,97 @@
+#include "ImageWrapperBase.h"
+#include "itkImageBase.h"
+#include "IRISException.h"
+
+
+
+
+vnl_matrix_fixed<double, 4, 4>
+ImageWrapperBase
+::ConstructNiftiSform(vnl_matrix<double> m_dir,
+                      vnl_vector<double> v_origin,
+                      vnl_vector<double> v_spacing)
+{
+  // Set the NIFTI/RAS transform
+  vnl_matrix<double> m_ras_matrix;
+  vnl_diag_matrix<double> m_scale, m_lps_to_ras;
+  vnl_vector<double> v_ras_offset;
+
+  // Compute the matrix
+  m_scale.set(v_spacing);
+  m_lps_to_ras.set(vnl_vector<double>(3, 1.0));
+  m_lps_to_ras[0] = -1;
+  m_lps_to_ras[1] = -1;
+  m_ras_matrix = m_lps_to_ras * m_dir * m_scale;
+
+  // Compute the vector
+  v_ras_offset = m_lps_to_ras * v_origin;
+
+  // Create the larger matrix
+  vnl_vector<double> vcol(4, 1.0);
+  vcol.update(v_ras_offset);
+
+  vnl_matrix_fixed<double,4,4> m_sform;
+  m_sform.set_identity();
+  m_sform.update(m_ras_matrix);
+  m_sform.set_column(3, vcol);
+  return m_sform;
+}
+
+vnl_matrix_fixed<double, 4, 4>
+ImageWrapperBase
+::ConstructVTKtoNiftiTransform(vnl_matrix<double> m_dir,
+                               vnl_vector<double> v_origin,
+                               vnl_vector<double> v_spacing)
+{
+  vnl_matrix_fixed<double,4,4> vox2nii = ConstructNiftiSform(m_dir, v_origin, v_spacing);
+  vnl_matrix_fixed<double,4,4> vtk2vox;
+  vtk2vox.set_identity();
+  for(size_t i = 0; i < 3; i++)
+    {
+    vtk2vox(i,i) = 1.0 / v_spacing[i];
+    vtk2vox(i,3) = - v_origin[i] / v_spacing[i];
+    }
+  return vox2nii * vtk2vox;
+}
+
+
+ScalarRepresentationIterator
+::ScalarRepresentationIterator(const VectorImageWrapperBase *wrapper)
+  : m_Depth(NUMBER_OF_SCALAR_REPS, 1)
+{
+  assert(wrapper->GetNumberOfComponents() > 0);
+
+  m_Depth[SCALAR_REP_COMPONENT] = wrapper->GetNumberOfComponents();
+  m_Current = SCALAR_REP_COMPONENT;
+  m_Index = 0;
+}
+
+ScalarRepresentationIterator &ScalarRepresentationIterator::operator ++()
+{
+  // Once at the end stay at the end
+  if(m_Current == NUMBER_OF_SCALAR_REPS)
+    return *this;
+
+  // If there is room to grow in current rep, do it
+  if(m_Index + 1 < m_Depth[(int) m_Current])
+    {
+    m_Index++;
+    }
+  else
+    {
+    m_Current++;
+    m_Index = 0;
+    }
+
+  return *this;
+}
+
+bool ScalarRepresentationIterator::IsAtEnd() const
+{
+  return m_Current == NUMBER_OF_SCALAR_REPS;
+}
+
+
+
+
+
diff --git a/Logic/ImageWrapper/ImageWrapperBase.h b/Logic/ImageWrapper/ImageWrapperBase.h
new file mode 100644
index 0000000..e5284fe
--- /dev/null
+++ b/Logic/ImageWrapper/ImageWrapperBase.h
@@ -0,0 +1,545 @@
+#ifndef IMAGEWRAPPERBASE_H
+#define IMAGEWRAPPERBASE_H
+
+#include "SNAPCommon.h"
+#include "ImageCoordinateTransform.h"
+#include "itkImageRegion.h"
+#include "itkObject.h"
+#include "SNAPEvents.h"
+
+namespace itk {
+  template <unsigned int VDim> class ImageBase;
+  template <class TPixel, unsigned int VDim> class Image;
+  template <class TPixel> class RGBAPixel;
+
+  namespace Statistics {
+    class DenseFrequencyContainer;
+    template <class TReal, unsigned int VDim, class TContainer> class Histogram;
+  }
+}
+
+class ScalarImageWrapperBase;
+class VectorImageWrapperBase;
+class IntensityCurveInterface;
+class ScalarImageHistogram;
+class ColorMap;
+class ImageCoordinateGeometry;
+class AbstractNativeIntensityMapping;
+class AbstractDisplayMappingPolicy;
+class SNAPSegmentationROISettings;
+class GuidedNativeImageIO;
+class Registry;
+class vtkImageImport;
+struct IRISDisplayGeometry;
+
+/**
+ * Supported ways of extracting a scalar value from vector-valued data.
+ * These modes allow the image to be cast to a scalar image and used in
+ * single-modality pipelines
+ */
+enum ScalarRepresentation
+{
+  SCALAR_REP_COMPONENT = 0,
+  SCALAR_REP_MAGNITUDE,
+  SCALAR_REP_MAX,
+  SCALAR_REP_AVERAGE,
+  NUMBER_OF_SCALAR_REPS
+};
+
+
+/**
+ \class ImageWrapper
+ \brief Abstract parent class for all image wrappers
+
+ This class is at the head of the ImageWrapper hierarchy. In fact, there are
+ two parallel hierarchies: the untyped hierarchy (xxxWrapperBase) and the
+ hierarchy templated over a type (xxxWrapper).
+
+ The idea is that most SNAP code will work with the untyped hierarches. Thus,
+ the code will not know what the underlying format of the image is. The typed
+ hierarchy is invisible to most of the SNAP classes, and accessed on special
+ occasions, where the raw data of the image is needed.
+ */
+class ImageWrapperBase : public itk::Object
+{
+public:
+
+  // Definition for the display slice type
+  typedef itk::RGBAPixel<unsigned char> DisplayPixelType;
+  typedef itk::Image<DisplayPixelType,2> DisplaySliceType;
+  typedef SmartPtr<DisplaySliceType> DisplaySlicePointer;
+
+  // Image base
+  typedef itk::ImageBase<3> ImageBaseType;
+
+  // Transform matrices
+  typedef vnl_matrix_fixed<double, 4, 4> TransformType;
+
+  /**
+   * The image wrapper fires a WrapperMetadataChangeEvent when properties
+   * such as nickname are modified. It fires a WrapperDisplayMappingChangeEvent
+   * when the factors affecting the mapping from internal data to the slice
+   * display (e.g., color map) are modified.
+   */
+  FIRES(WrapperMetadataChangeEvent)
+  FIRES(WrapperDisplayMappingChangeEvent)
+
+  virtual ~ImageWrapperBase() { }
+
+  /**
+    Get a unique id for this wrapper. All wrappers ever created have
+    different ids.
+    */
+  virtual unsigned long GetUniqueId() const = 0;
+
+  /**
+   * Every wrapper, whether it is a scalar wrapper or a vector wrapper, has a
+   * scalar representation. For scalar wrappers, this function just returns a
+   * pointer to itself. For vector wrappers, the behavior of this function
+   * depends on which scalar representation has been selected as the default
+   * scalar representation (e.g., one of the components, magnitude, max, mean).
+   */
+  virtual ScalarImageWrapperBase *GetDefaultScalarRepresentation() = 0;
+
+  /**
+   * Get the parent wrapper for this wrapper. For 'normal' wrappers, this method
+   * returns NULL, indicating that the wrapper is a top-level wrapper. For derived
+   * wrappers (i.e., components and scalar representations of vector wrappers),
+   * this method returns the vector wrapper from which the wrapper is derived
+   */
+  virtual ImageWrapperBase *GetParentWrapper() const = 0;
+
+  /** Set the parent wrapper */
+  virtual void SetParentWrapper(ImageWrapperBase *parent) = 0;
+
+  /** Get the coordinate transform for each display slice */
+  virtual const ImageCoordinateTransform &GetImageToDisplayTransform(
+    unsigned int) const = 0;
+
+  /**
+   * Set the coordinate transformation between the display coordinates and
+   * the anatomical coordinates. This affects the behavior of the slicers
+   */
+  virtual void SetDisplayGeometry(IRISDisplayGeometry &dispGeom) = 0;
+
+  /** Get the display to anatomy coordinate mapping */
+  virtual const IRISDisplayGeometry &GetDisplayGeometry() const = 0;
+
+  /** Set the direction matrix of the image */
+  virtual void SetDirectionMatrix(const vnl_matrix<double> &direction) = 0;
+
+  /**
+   * Set the image coordinate transform (origin, spacing, direction) to
+   * match those of a reference wrapper
+   */
+  virtual void CopyImageCoordinateTransform(const ImageWrapperBase *source) = 0;
+
+  /**
+   * Get the image geometry from the wrapper. The image geometry captures
+   * the transforms between each of the display slices and the 3D image.
+   */
+  virtual const ImageCoordinateGeometry &GetImageGeometry() const = 0;
+
+  /** Get the current slice index */
+  irisVirtualGetMacro(SliceIndex, Vector3ui)
+
+  /**
+   * Set the current slice index in all three dimensions.  The index should
+   * be specified in the image coordinates, the slices will be generated
+   * in accordance with the transforms that are specified
+   */
+  virtual void SetSliceIndex(const Vector3ui &) = 0;
+
+  /** Return some image info independently of pixel type */
+  irisVirtualGetMacro(ImageBase, ImageBaseType *)
+
+  /**
+   * Is the image initialized?
+   */
+  irisVirtualIsMacro(Initialized)
+
+  /**
+   * If the image wrapper is an output of a preview pipeline, is the pipeline ready?
+   */
+  irisVirtualIsMacro(PipelineReady)
+  irisVirtualSetMacro(PipelineReady, bool)
+
+  /** Is this image of scalar type? */
+  virtual bool IsScalar() const = 0;
+
+  /**
+   * Get the size of the image
+   */
+  virtual Vector3ui GetSize() const = 0;
+
+  /** Get layer transparency */
+  irisVirtualSetMacro(Alpha, double)
+
+  /** Set layer transparency */
+  irisVirtualGetMacro(Alpha, double)
+
+  /**
+   * Get layer stickiness. A sticky layer always is shown 'on top' of other
+   * layers, e.g., the segmentation layer, or the level set image. A layer that
+   * is not sticky is shown in its own tile when the display is in tiled mode
+   */
+  irisVirtualSetMacro(Sticky, bool)
+
+  /** Set layer stickiness */
+  irisVirtualIsMacro(Sticky)
+
+  /**
+   * Whether the layer is drawable. Some layers may be initialized, but not
+   * yet computed, in which case they should not yet be drawn.
+   */
+  irisVirtualIsMacro(Drawable)
+
+  /**
+   * Get the buffered region of the image
+   */
+  virtual itk::ImageRegion<3> GetBufferedRegion() const = 0;
+
+  /**
+   * Extract a region of interest from the image wrapper, as a new wrapper of
+   * the same type
+   */
+  virtual SmartPtr<ImageWrapperBase> ExtractROI(
+      const SNAPSegmentationROISettings &roi, itk::Command *progressCommand) const = 0;
+
+  /** Transform a voxel index into a spatial position */
+  virtual Vector3d TransformVoxelIndexToPosition(const Vector3ui &iVoxel) const = 0;
+
+  /** Transform a voxel index into NIFTI coordinates (RAS) */
+  virtual Vector3d TransformVoxelIndexToNIFTICoordinates(const Vector3d &iVoxel) const = 0;
+
+  /** Transform NIFTI coordinates to a continuous voxel index */
+  virtual Vector3d TransformNIFTICoordinatesToVoxelIndex(const Vector3d &vNifti) const = 0;
+
+  /** Get the NIFTI s-form matrix for this image */
+  irisVirtualGetMacro(NiftiSform, TransformType)
+
+  /** Get the inverse NIFTI s-form matrix for this image */
+  irisVirtualGetMacro(NiftiInvSform, TransformType)
+
+  /** Get a display slice correpsponding to the current index */
+  virtual DisplaySlicePointer GetDisplaySlice(unsigned int dim) = 0;
+
+  /** For each slicer, find out which image dimension does is slice along */
+  virtual unsigned int GetDisplaySliceImageAxis(unsigned int slice) = 0;
+
+  /** Get the number of voxels */
+  virtual size_t GetNumberOfVoxels() const = 0;
+
+  /** Get the number of components per voxel */
+  virtual size_t GetNumberOfComponents() const = 0;
+
+  /** Get voxel at index as an array of double components */
+  virtual void GetVoxelAsDouble(const Vector3ui &x, double *out) const = 0;
+
+  /** Get voxel at index as an array of double components */
+  virtual void GetVoxelAsDouble(const itk::Index<3> &idx, double *out) const = 0;
+
+  /** Get voxel intensity in native space. These methods are not recommended
+      for iterating over the entire image, since there is a virutal method
+      being resolved at each iteration. */
+  virtual void GetVoxelMappedToNative(const Vector3ui &vec, double *out) const = 0;
+  virtual void GetVoxelMappedToNative(const itk::Index<3> &idx, double *out) const = 0;
+
+  /** Return componentwise minimum cast to double, without mapping to native range */
+  virtual double GetImageMinAsDouble() = 0;
+
+  /** Return componentwise maximum cast to double, without mapping to native range */
+  virtual double GetImageMaxAsDouble() = 0;
+
+  /** Return componentwise minimum cast to double, after mapping to native range */
+  virtual double GetImageMinNative() = 0;
+
+  /** Return componentwise maximum cast to double, after mapping to native range */
+  virtual double GetImageMaxNative() = 0;
+
+  /**
+    Compute the image histogram. The histogram is cached inside of the
+    object, so repeated calls to this function with the same nBins parameter
+    will not require additional computation.
+
+    Calling with default parameter (0) will use the same number of bins that
+    is currently in the histogram (i.e., return/recompute current histogram).
+    If there is no current histogram, a default histogram with 128 entries
+    will be generated.
+
+    For multi-component data, the histogram is pooled over all components.
+    */
+  virtual const ScalarImageHistogram *GetHistogram(size_t nBins) = 0;
+
+  /** Compute statistics over a run of voxels in the image starting at the index
+   * startIdx. Appends the statistics to a running sum and sum of squared. The
+   * statistics are returned in internal (not native mapped) format */
+  virtual void GetRunLengthIntensityStatistics(
+      const itk::ImageRegion<3> &region,
+      const itk::Index<3> &startIdx, long runlength,
+      double *out_sum, double *out_sumsq) const = 0;
+
+  /**
+   * This method returns a vector of values for the voxel under the cursor.
+   * This is the natural value or set of values that should be displayed to
+   * the user. The value depends on the current display mode. For scalar
+   * images, it's just the value of the voxel, but for multi-component images,
+   * it's the value of the selected component (if there is one) or the value
+   * of the multiple components when the mode is RGB. In the second parameter,
+   * the method returns the RGB appearance of the voxel under the cursor
+   */
+  virtual void GetVoxelUnderCursorDisplayedValueAndAppearance(
+      vnl_vector<double> &out_value, DisplayPixelType &out_appearance) = 0;
+
+  /** Get the voxel array, as void pointer */
+  virtual void *GetVoxelVoidPointer() const = 0;
+
+  /** Clear the data associated with storing an image */
+  virtual void Reset() = 0;
+
+  /**
+   * Get the mapping between the internal data type and the 'native' range,
+   * i.e., the range of values shown to the user. This may be a linear mapping
+   * or an identity mapping.
+   */
+  virtual const AbstractNativeIntensityMapping *GetNativeIntensityMapping() const = 0;
+
+  /**
+   * Get the display mapping policy. This policy differs from wrapper to wrapper
+   * and may involve using color labels or color maps.
+   */
+  virtual AbstractDisplayMappingPolicy *GetDisplayMapping() = 0;
+
+  // Access the filename
+  irisVirtualGetStringMacro(FileName)
+  irisVirtualSetStringMacro(FileName)
+
+  // Access the nickname - which may be a custom nickname or derived from the
+  // filename if there is no custom nickname
+  irisVirtualGetMacro(Nickname, const std::string &)
+
+  // Set the custom nickname - precedence over the filename
+  irisVirtualGetMacro(CustomNickname, const std::string &)
+  irisVirtualSetMacro(CustomNickname, const std::string &)
+
+  // Fallback nickname - shown if no filename and no custom nickname set.
+  irisVirtualGetMacro(DefaultNickname, const std::string &)
+  irisVirtualSetMacro(DefaultNickname, const std::string &)
+
+  /**
+    Export one of the slices as a thumbnail (e.g., PNG file)
+    */
+  virtual void WriteThumbnail(const char *filename, unsigned int maxdim) = 0;
+
+  /**
+   * Write the image to disk with the help of the GuidedNativeImageIO object
+   */
+  virtual void WriteToFile(const char *filename, Registry &hints) = 0;
+
+  /**
+   * Check if the image has unsaved changes
+   */
+  virtual bool HasUnsavedChanges() const = 0;
+
+  /**
+   * Save metadata to a Registry file. The metadata are data that are not
+   * contained in the image header are need to be restored when the image
+   * is reloaded. Currently, this mainly includes the display mapping, but
+   * also the transparency, etc.
+   */
+  virtual void WriteMetaData(Registry &reg) = 0;
+
+  /**
+   * Restore metadata from a registry
+   */
+  virtual void ReadMetaData(Registry &reg) = 0;
+
+  /**
+   * This static function constructs a NIFTI matrix from the ITK direction
+   * cosines matrix and Spacing and Origin vectors
+   */
+  static TransformType ConstructNiftiSform(
+    vnl_matrix<double> m_dir,
+    vnl_vector<double> v_origin,
+    vnl_vector<double> v_spacing);
+
+  static TransformType ConstructVTKtoNiftiTransform(
+    vnl_matrix<double> m_dir,
+    vnl_vector<double> v_origin,
+    vnl_vector<double> v_spacing);
+
+  typedef itk::Image<short, 3> ShortImageType;
+
+  /**
+   * The image wrapper has a generic mechanism for associating data with it.
+   * For example, we can associate some parameter values for a specific
+   * image processing algorithm with each layer. Do do that, we simply
+   * assign a pointer to the data to a specific string role. Internally,
+   * a smart pointer is used to point to the associated data.
+   *
+   * Users of this method might also want to rebroadcast events from the
+   * associated object as events of type WrapperUserChangeEvent(). These
+   * events will then propagate all the way up to the IRISApplication.
+   */
+  virtual void SetUserData(const std::string &role, itk::Object *data) = 0;
+
+  /**
+   * Get the user data associated with this wrapper for a specific role. If
+   * no association exists, NULL is returned.
+   */
+  virtual itk::Object* GetUserData(const std::string &role) const = 0;
+
+protected:
+
+};
+
+class ScalarImageWrapperBase : public virtual ImageWrapperBase
+{
+public:
+
+  // A common image format to which the contents of the scalar image wrapper
+  // may be cast for downstream processing
+  typedef itk::Image<GreyType, 3>                      CommonFormatImageType;
+
+  /**
+   * An enum of export channel types. Export channels are used to present the
+   * internal image as an itk::Image of a fixed type. For efficient memory
+   * management, there are separate channels for downstream filters that
+   * operate on the whole image and filters that generate single-slice previews
+   * in the orthogonal slicing directions
+   */
+  enum ExportChannel {
+    WHOLE_IMAGE=0, PREVIEW_X, PREVIEW_Y, PREVIEW_Z, CHANNEL_COUNT
+  };
+
+  /**
+   * Get the scaling factor used to convert between intensities stored
+   * in this image and the 'true' image intensities
+   */
+  virtual double GetImageScaleFactor() = 0;
+
+  /** Get voxel at index as a single double value */
+  virtual double GetVoxelAsDouble(const Vector3ui &x) const = 0;
+
+  /** Get voxel at index as a single double value */
+  virtual double GetVoxelAsDouble(const itk::Index<3> &idx) const = 0;
+
+  /** Get voxel intensity in native space. These methods are not recommended
+      for iterating over the entire image, since there is a virutal method
+      being resolved at each iteration. */
+  virtual double GetVoxelMappedToNative(const Vector3ui &vec) const = 0;
+  virtual double GetVoxelMappedToNative(const itk::Index<3> &idx) const = 0;
+
+  /**
+    Get the maximum possible value of the gradient magnitude. This will
+    compute the gradient magnitude of the image (without Gaussian smoothing)
+    and return the maximum. The value will be cached so repeated calls to
+    this are not expensive.
+    */
+  virtual double GetImageGradientMagnitudeUpperLimit() = 0;
+
+  /**
+    Get the maximum possible value of the gradient magnitude in native units
+    */
+  virtual double GetImageGradientMagnitudeUpperLimitNative() = 0;
+
+  /**
+   * Extract a GreyType representation from the image wrapper. Note that
+   * internally, the scalar image wrapper can be of many itk types, e.g.,
+   * it could be a component of a vector image computed dynamically. In
+   * order to use the scalar image in downstream filters, we must have a
+   * way to map it to some common datatype. If not, we would have to template
+   * the downstream filter on the type of the image in the wrapper, which would
+   * lead to an exponential explosion of types.
+   *
+   * There are actually four representations for each image wrapper, one of
+   * which is intended for pipelines that act on entire image volumes and the
+   * other three intended for use in preview-capable pipelines, which generate
+   * output for just one slice. Since ITK only allocates the requested image
+   * region, these four representations should not really use much extra memory.
+   *
+   * However, it is very important that downstream filters use the itk streaming
+   * image filter to break up operations into pieces. Without that, there would
+   * be unnecessary large memory allocation.
+   */
+  virtual CommonFormatImageType* GetCommonFormatImage(
+      ExportChannel channel = WHOLE_IMAGE) = 0;
+
+  /**
+   * Get the intensity curve used to map raw intensities to color map inputs.
+   * The intensity curve is only used by some wrappers (anatomic, speed) and
+   * so this method may return NULL for some layers.
+   */
+  virtual IntensityCurveInterface *GetIntensityCurve() const = 0;
+
+  /**
+   * Get the color map used to present image intensities as RGBA.
+   */
+  virtual ColorMap *GetColorMap() const = 0;
+
+  /** Get a version of this image that is usable in VTK pipelines */
+  virtual vtkImageImport *GetVTKImporter() = 0;
+};
+
+
+
+
+/**
+ * A class that can be used to iterate over scalar representations.
+ * Within some of the scalar representations (for now just SCALAR_REP_COMPONENT)
+ * there are multiple indexed scalar components. The iterator iterates over the
+ * components before proceeding to the next component.
+ */
+class ScalarRepresentationIterator
+{
+public:
+  ScalarRepresentationIterator(const VectorImageWrapperBase *wrapper);
+
+  ScalarRepresentationIterator& operator ++();
+  bool IsAtEnd() const;
+
+  irisGetMacro(Index, int)
+
+  ScalarRepresentation GetCurrent() const
+    { return static_cast<ScalarRepresentation>(m_Current); }
+
+protected:
+  int m_Current;
+  int m_Index;
+
+  // Depth of each scalar representation
+  std::vector<int> m_Depth;
+
+  friend class VectorImageWrapperBase;
+};
+
+/**
+ * A base class for wrappers around vector-valued images
+ */
+class VectorImageWrapperBase : public virtual ImageWrapperBase
+{
+public:
+
+  /**
+   * Get a pointer to the given scalar representation of this vector image.
+   */
+  virtual ScalarImageWrapperBase *GetScalarRepresentation(
+      ScalarRepresentation type, int index = 0) = 0;
+
+
+  /**
+   * Access a scalar representation using an iterator
+   */
+  virtual ScalarImageWrapperBase *GetScalarRepresentation(
+      const ScalarRepresentationIterator &it) = 0;
+
+  /**
+   * If scalar_rep is a scalar representation of the vector image wrapper, find
+   * the type of the representation and the index. Otherwise return false;
+   */
+  virtual bool FindScalarRepresentation(
+      ImageWrapperBase *scalar_rep, ScalarRepresentation &type, int &index) const = 0;
+};
+
+
+#endif // IMAGEWRAPPERBASE_H
diff --git a/Logic/ImageWrapper/ImageWrapperTraits.cxx b/Logic/ImageWrapper/ImageWrapperTraits.cxx
new file mode 100644
index 0000000..60ee8ad
--- /dev/null
+++ b/Logic/ImageWrapper/ImageWrapperTraits.cxx
@@ -0,0 +1,2 @@
+#include "ImageWrapperTraits.h"
+
diff --git a/Logic/ImageWrapper/ImageWrapperTraits.h b/Logic/ImageWrapper/ImageWrapperTraits.h
new file mode 100644
index 0000000..55302ec
--- /dev/null
+++ b/Logic/ImageWrapper/ImageWrapperTraits.h
@@ -0,0 +1,247 @@
+#ifndef IMAGEWRAPPERTRAITS_H
+#define IMAGEWRAPPERTRAITS_H
+
+#include "SNAPCommon.h"
+#include "ImageWrapperBase.h"
+
+#include "CommonRepresentationPolicy.h"
+#include "DisplayMappingPolicy.h"
+#include "NativeIntensityMappingPolicy.h"
+
+#include "ScalarImageWrapper.h"
+#include "VectorImageWrapper.h"
+#include "ColorMap.h"
+
+namespace itk
+{
+  template <class TPixel, unsigned int VDim> class Image;
+  template <class TPixel, unsigned int VDim> class VectorImage;
+  template <class TPixel, unsigned int VDim> class VectorImageToImageAdaptor;
+}
+
+/*
+class ScalarImageWrapperBase;
+class VectorImageWrapperBase;
+template <class TImage, class TBase> class VectorImageWrapper;
+template <class TImage, class TBase> class ScalarImageWrapper;
+*/
+
+/**
+ * Each of the traits classes below defines types and policies for a specific
+ * type of image wrapper.
+ */
+class LabelImageWrapperTraits
+{
+public:
+  typedef LabelImageWrapperTraits Self;
+
+  typedef ScalarImageWrapper<LabelImageWrapperTraits> WrapperType;
+
+  typedef LabelType ComponentType;
+  typedef itk::Image<ComponentType, 3> ImageType;
+
+  typedef IdentityInternalToNativeIntensityMapping NativeIntensityMapping;
+  typedef ColorLabelTableDisplayMappingPolicy<Self> DisplayMapping;
+  typedef NullScalarImageWrapperCommonRepresentation<GreyType, Self> CommonRepresentationPolicy;
+
+  // Whether this image is shown on top of all other layers by default
+  itkStaticConstMacro(StickyByDefault, bool, true);
+
+  // Whether this image is produced from another by a pipeline (e.g., speed image)
+  itkStaticConstMacro(PipelineOutput, bool, false);
+};
+
+class SpeedImageWrapperTraits
+{
+public:
+  typedef SpeedImageWrapperTraits Self;
+
+  typedef ScalarImageWrapper<SpeedImageWrapperTraits> WrapperType;
+
+  typedef GreyType ComponentType;
+  typedef itk::Image<ComponentType, 3> ImageType;
+
+  typedef SpeedImageInternalToNativeIntensityMapping NativeIntensityMapping;
+  typedef LinearColorMapDisplayMappingPolicy<Self> DisplayMapping;
+  typedef NullScalarImageWrapperCommonRepresentation<GreyType, Self> CommonRepresentationPolicy;
+
+  static void GetFixedIntensityRange(float &min, float &max)
+    { min = -0x7fff; max = 0x7fff; }
+
+  itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_SPEED);
+
+  // Whether this image is shown on top of all other layers by default
+  itkStaticConstMacro(StickyByDefault, bool, false);
+
+  // Whether this image is produced from another by a pipeline (e.g., speed image)
+  itkStaticConstMacro(PipelineOutput, bool, true);
+};
+
+class LevelSetImageWrapperTraits
+{
+public:
+  typedef LevelSetImageWrapperTraits Self;
+
+  typedef ScalarImageWrapper<LevelSetImageWrapperTraits> WrapperType;
+
+  typedef float ComponentType;
+  typedef itk::Image<ComponentType, 3> ImageType;
+
+  typedef IdentityInternalToNativeIntensityMapping NativeIntensityMapping;
+  typedef LinearColorMapDisplayMappingPolicy<Self> DisplayMapping;
+  typedef NullScalarImageWrapperCommonRepresentation<GreyType, Self> CommonRepresentationPolicy;
+
+  static void GetFixedIntensityRange(float &min, float &max)
+    { min = -4.0; max = 4.0; }
+
+  itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_LEVELSET);
+
+  // Whether this image is shown on top of all other layers by default
+  itkStaticConstMacro(StickyByDefault, bool, true);
+
+  // Whether this image is produced from another by a pipeline (e.g., speed image)
+  itkStaticConstMacro(PipelineOutput, bool, true);
+};
+
+/**
+ * This helper traits class is used to select the appropriate common representation
+ * policy depending on the internal pixel type
+ */
+template <class TPixel, class TWrapperTraits>
+class DefaultCommonRepresentationPolicy
+{
+public:
+  typedef CastingScalarImageWrapperCommonRepresentation<GreyType, TWrapperTraits> Policy;
+};
+
+template <class TWrapperTraits>
+class DefaultCommonRepresentationPolicy<GreyType, TWrapperTraits>
+{
+public:
+  typedef InPlaceScalarImageWrapperCommonRepresentation<GreyType, TWrapperTraits> Policy;
+};
+
+template <class TPixel>
+class ComponentImageWrapperTraits
+{
+public:
+  typedef ComponentImageWrapperTraits<TPixel> Self;
+
+  typedef ScalarImageWrapper<Self> WrapperType;
+
+  typedef TPixel ComponentType;
+  typedef itk::VectorImageToImageAdaptor<ComponentType, 3> ImageType;
+
+  typedef LinearInternalToNativeIntensityMapping NativeIntensityMapping;
+  typedef CachingCurveAndColorMapDisplayMappingPolicy<Self> DisplayMapping;
+  typedef CastingScalarImageWrapperCommonRepresentation<GreyType, Self> CommonRepresentationPolicy;
+
+  itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_GREY);
+
+  // Whether this image is shown on top of all other layers by default
+  itkStaticConstMacro(StickyByDefault, bool, false);
+
+  // Whether this image is produced from another by a pipeline (e.g., speed image)
+  itkStaticConstMacro(PipelineOutput, bool, false);
+};
+
+template <class TFunctor>
+class VectorDerivedQuantityImageWrapperTraits
+{
+public:
+  typedef VectorDerivedQuantityImageWrapperTraits<TFunctor> Self;
+  typedef ScalarImageWrapper<Self> WrapperType;
+
+  typedef typename TFunctor::OutputPixelType ComponentType;
+
+  typedef typename TFunctor::InputPixelType InternalComponentType;
+  typedef itk::VectorImage<InternalComponentType, 3> InternalImageType;
+  typedef VectorToScalarImageAccessor<TFunctor> AccessorType;
+  typedef itk::ImageAdaptor<InternalImageType, AccessorType> ImageType;
+
+  typedef IdentityInternalToNativeIntensityMapping NativeIntensityMapping;
+  typedef CachingCurveAndColorMapDisplayMappingPolicy<Self> DisplayMapping;
+  typedef CastingScalarImageWrapperCommonRepresentation<GreyType, Self> CommonRepresentationPolicy;
+
+  itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_GREY);
+
+  // Whether this image is shown on top of all other layers by default
+  itkStaticConstMacro(StickyByDefault, bool, false);
+
+  // Whether this image is produced from another by a pipeline (e.g., speed image)
+  itkStaticConstMacro(PipelineOutput, bool, false);
+};
+
+
+template <class TPixel>
+class AnatomicImageWrapperTraits
+{
+public:
+  typedef AnatomicImageWrapperTraits<TPixel> Self;
+
+  typedef VectorImageWrapper<Self> WrapperType;
+
+  // Component stuff
+  typedef TPixel ComponentType;
+
+  typedef ComponentImageWrapperTraits<ComponentType> ComponentWrapperTraits;
+  typedef ScalarImageWrapper<ComponentWrapperTraits> ComponentWrapperType;
+
+  typedef itk::VectorImage<ComponentType, 3> ImageType;
+
+  typedef LinearInternalToNativeIntensityMapping NativeIntensityMapping;
+  typedef MultiChannelDisplayMappingPolicy<Self> DisplayMapping;
+
+  // Whether this image is shown on top of all other layers by default
+  itkStaticConstMacro(StickyByDefault, bool, false);
+
+  // Whether this image is produced from another by a pipeline (e.g., speed image)
+  itkStaticConstMacro(PipelineOutput, bool, false);
+};
+
+
+template <class TPixel>
+class AnatomicScalarImageWrapperTraits
+{
+public:
+  typedef AnatomicScalarImageWrapperTraits<TPixel> Self;
+
+  typedef ScalarImageWrapper<Self> WrapperType;
+
+  typedef TPixel ComponentType;
+  typedef itk::Image<ComponentType, 3> ImageType;
+
+  typedef LinearInternalToNativeIntensityMapping NativeIntensityMapping;
+  typedef CachingCurveAndColorMapDisplayMappingPolicy<Self> DisplayMapping;
+  typedef typename DefaultCommonRepresentationPolicy<TPixel, Self>::Policy CommonRepresentationPolicy;
+
+  // Default color map
+  itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_GREY);
+
+  // Whether this image is shown on top of all other layers by default
+  itkStaticConstMacro(StickyByDefault, bool, false);
+
+  // Whether this image is produced from another by a pipeline (e.g., speed image)
+  itkStaticConstMacro(PipelineOutput, bool, false);
+};
+
+
+// Global typedefs for traits with GreyType
+typedef AnatomicScalarImageWrapperTraits<GreyType> GreyAnatomicScalarImageWrapperTraits;
+typedef ComponentImageWrapperTraits<GreyType> GreyComponentImageWrapperTraits;
+typedef VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMagnitudeFunctor>
+  GreyVectorMagnitudeImageWrapperTraits;
+typedef VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMaxFunctor>
+  GreyVectorMaxImageWrapperTraits;
+typedef VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMeanFunctor>
+  GreyVectorMeanImageWrapperTraits;
+
+// Some global typedefs
+typedef AnatomicImageWrapperTraits<GreyType>::WrapperType AnatomicImageWrapper;
+typedef AnatomicScalarImageWrapperTraits<GreyType>::WrapperType AnatomicScalarImageWrapper;
+typedef LabelImageWrapperTraits::WrapperType LabelImageWrapper;
+typedef SpeedImageWrapperTraits::WrapperType SpeedImageWrapper;
+typedef LevelSetImageWrapperTraits::WrapperType LevelSetImageWrapper;
+
+
+#endif // IMAGEWRAPPERTRAITS_H
diff --git a/Logic/ImageWrapper/InputSelectionImageFilter.cxx b/Logic/ImageWrapper/InputSelectionImageFilter.cxx
new file mode 100644
index 0000000..375d163
--- /dev/null
+++ b/Logic/ImageWrapper/InputSelectionImageFilter.cxx
@@ -0,0 +1,61 @@
+#include "InputSelectionImageFilter.h"
+#include "itkUnaryFunctorImageFilter.hxx"
+#include "IRISException.h"
+
+#include "itkAddImageFilter.h"
+
+template<class TInputImage, typename TTag>
+InputSelectionImageFilter<TInputImage,TTag>
+::InputSelectionImageFilter()
+{
+}
+
+template<class TInputImage, typename TTag>
+void
+InputSelectionImageFilter<TInputImage,TTag>
+::AddSelectableInput(TagType tag, InputImageType *input)
+{
+  m_TagMap[tag] = input;
+  if(m_TagMap.size() == 0)
+    SetSelectedInput(tag);
+}
+
+template<class TInputImage, typename TTag>
+void
+InputSelectionImageFilter<TInputImage,TTag>
+::RemoveAllSelectableInputs()
+{
+  m_TagMap.clear();
+  this->SetInput(NULL);
+}
+
+template<class TInputImage, typename TTag>
+void
+InputSelectionImageFilter<TInputImage,TTag>
+::SetSelectedInput(TagType &tag)
+{
+  this->SetInput(m_TagMap[tag]);
+  m_SelectedInput = tag;
+  this->Modified();
+}
+
+/**
+ * Adopted from itk::InPlaceImageFilter::InternalAllocateOutputs()
+ */
+template<class TInputImage, typename TTag>
+void
+InputSelectionImageFilter<TInputImage,TTag>
+::GenerateData()
+{
+  // Just pass the container to the output image
+  InputImageType *inputPtr = const_cast<InputImageType *>(this->GetInput());
+  OutputImageType *outputPtr = this->GetOutput();
+
+  outputPtr->CopyInformation(inputPtr);
+  outputPtr->SetBufferedRegion(inputPtr->GetBufferedRegion());
+  outputPtr->SetPixelContainer(inputPtr->GetPixelContainer());
+}
+
+#include "DisplayMappingPolicy.h"
+#include "itkRGBAPixel.h"
+template class InputSelectionImageFilter<ImageWrapperBase::DisplaySliceType, MultiChannelDisplayMode>;
diff --git a/Logic/ImageWrapper/InputSelectionImageFilter.h b/Logic/ImageWrapper/InputSelectionImageFilter.h
new file mode 100644
index 0000000..2bc3ac0
--- /dev/null
+++ b/Logic/ImageWrapper/InputSelectionImageFilter.h
@@ -0,0 +1,71 @@
+#ifndef INPUTSELECTIONIMAGEFILTER_H
+#define INPUTSELECTIONIMAGEFILTER_H
+
+#include "itkImageToImageFilter.h"
+#include "SNAPCommon.h"
+#include <map>
+
+/**
+ * This filter selects one of its inputs and presents it as an output. It is
+ * used when there are several alternative pipelines that can be used to
+ * produce an output. Updating the output will Update() the correct pipeline.
+ *
+ * The class is templated over the type TTag, which is an arbitrary type
+ * that is used to identify input pipelines. This allows pipelines to be associated
+ * with non-integer values (structs, enums, etc.)
+ */
+template <class TInputImage, typename TTag = int>
+class InputSelectionImageFilter
+    : public itk::ImageToImageFilter<TInputImage,TInputImage>
+{
+public:
+
+  typedef InputSelectionImageFilter<TInputImage, TTag> Self;
+  typedef itk::ImageToImageFilter<TInputImage,TInputImage> Superclass;
+  typedef SmartPtr<Self> Pointer;
+  typedef SmartPtr<const Self> ConstPointer;
+
+  typedef TInputImage InputImageType;
+  typedef TInputImage OutputImageType;
+
+  itkNewMacro(Self)
+  itkStaticConstMacro(ImageDimension, unsigned int, InputImageType::ImageDimension);
+
+  typedef TTag TagType;
+
+  /**
+   * Add a selectable input identified with a tag
+   */
+  void AddSelectableInput(TagType tag, InputImageType *input);
+
+  /**
+   * Remove all selectable inputs
+   */
+  void RemoveAllSelectableInputs();
+
+  /**
+   * Set the selected input - must be one of the inputs added with AddInput!
+   * Defaults to the first input added.
+   */
+  void SetSelectedInput(TagType &tag);
+
+  itkGetMacro(SelectedInput, TagType)
+
+  /**
+   * Generate the data - by selecting an input and presenting it as output
+   */
+  void GenerateData();
+
+protected:
+
+  InputSelectionImageFilter();
+  virtual ~InputSelectionImageFilter() {};
+
+  TagType m_SelectedInput;
+
+  // A mapping from tag types to inputs
+  typedef std::map<TagType, SmartPtr<InputImageType> > TagMap;
+  TagMap m_TagMap;
+};
+
+#endif // INPUTSELECTIONIMAGEFILTER_H
diff --git a/Logic/ImageWrapper/LabelImageWrapper.cxx b/Logic/ImageWrapper/LabelImageWrapper.cxx
deleted file mode 100644
index a709dc0..0000000
--- a/Logic/ImageWrapper/LabelImageWrapper.cxx
+++ /dev/null
@@ -1,154 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: LabelImageWrapper.cxx,v $
-  Language:  C++
-  Date:      $Date: 2009/08/29 23:18:42 $
-  Version:   $Revision: 1.7 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "ImageWrapper.txx"
-#include "ScalarImageWrapper.txx"
-#include "LabelImageWrapper.h"
-#include "ColorLabel.h"
-#include "ColorLabelTable.h"
-
-// Create an instance of ImageWrapper of appropriate type
-template class ImageWrapper<LabelType>;
-template class ScalarImageWrapper<LabelType>;
-
-LabelImageWrapper
-::LabelImageWrapper()
-{
-  // Instantiate the filters
-  for(unsigned int i=0;i<3;i++) 
-  {
-    m_RGBAFilter[i] = RGBAFilterType::New();
-    m_RGBAFilter[i]->SetInput(m_Slicer[i]->GetOutput());
-  }
-
-  SetLabelColorTable(NULL);
-}
-
-LabelImageWrapper
-::LabelImageWrapper(const LabelImageWrapper &source)
-: ScalarImageWrapper<LabelType>(source)
-{
-  // Instantiate the filters
-  for(unsigned int i=0;i<3;i++) 
-  {
-    m_RGBAFilter[i] = RGBAFilterType::New();
-    m_RGBAFilter[i]->SetInput(m_Slicer[i]->GetOutput());
-  }
-
-  // Initialize the color table as well
-  SetLabelColorTable(source.GetLabelColorTable());
-}
-
-LabelImageWrapper
-::~LabelImageWrapper()
-{
-  for (size_t i = 0; i < 3; ++i)
-    {
-    m_RGBAFilter[i] = NULL;
-    }
-}
-
-ColorLabelTable *
-LabelImageWrapper
-::GetLabelColorTable() const
-{
-  return m_RGBAFilter[0]->GetColorTable();
-}
-
-void 
-LabelImageWrapper
-::SetLabelColorTable(ColorLabelTable *table) 
-{
-  // Set the new table
-  for(unsigned int i=0;i<3;i++) 
-    m_RGBAFilter[i]->SetColorTable(table);
-}
-
-void 
-LabelImageWrapper
-::UpdateColorMappingCache() 
-{
-  // Better have a color table
-  assert(GetLabelColorTable());
-
-  // Dirty the intensity filters
-  for(unsigned int i=0;i<3;i++)
-    m_RGBAFilter[i]->Modified();  
-}
-
-LabelImageWrapper::DisplaySlicePointer
-LabelImageWrapper
-::GetDisplaySlice(unsigned int dim) const
-{
-  return m_RGBAFilter[dim]->GetOutput();
-}
-
-/**
- * This definition is needed to use RGBA pixels for compilation
- */
-typedef itk::RGBAPixel<unsigned char> ColorPixel;
-
-namespace itk {
-
-template<>
-class NumericTraits<ColorPixel>
-{
-public:
-  typedef ColorPixel ValueType;
-  typedef ColorPixel PrintType;
-  typedef ColorPixel AbsType;
-  typedef ColorPixel AccumulateType;
-  static const ColorPixel Zero;
-  static const ColorPixel One;
-
-  static ColorPixel NonpositiveMin() { return Zero; }
-  static bool IsPositive(ColorPixel val) { return true; }
-  static bool IsNonpositive(ColorPixel val) { return false; }
-  static bool IsNegative(ColorPixel val) { return false; }
-  static bool IsNonnegative(ColorPixel val) {return true; }
-private:
-
-  static const unsigned char ZeroArray[4];
-  static const unsigned char OneArray[4];
-};
-
-} // End of namespace
-
-const unsigned char itk::NumericTraits<ColorPixel>::ZeroArray[4] = {0,0,0,0};
-const ColorPixel itk::NumericTraits<ColorPixel>::Zero = 
-  ColorPixel(itk::NumericTraits<ColorPixel>::ZeroArray);
-
-const unsigned char itk::NumericTraits<ColorPixel>::OneArray[4] = {1,1,1,1};
-const ColorPixel itk::NumericTraits<ColorPixel>::One = 
-  ColorPixel(itk::NumericTraits<ColorPixel>::OneArray);
diff --git a/Logic/ImageWrapper/LabelImageWrapper.h b/Logic/ImageWrapper/LabelImageWrapper.h
deleted file mode 100644
index a3037a5..0000000
--- a/Logic/ImageWrapper/LabelImageWrapper.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: LabelImageWrapper.h,v $
-  Language:  C++
-  Date:      $Date: 2009/08/25 21:38:16 $
-  Version:   $Revision: 1.5 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __LabelImageWrapper_h_
-#define __LabelImageWrapper_h_
-
-#include "ScalarImageWrapper.h"
-#include "UnaryFunctorCache.h"
-#include "LabelToRGBAFilter.h"
-
-
-
-// Forward references
-namespace itk {
-  template<class TInput, class TOutput, class TFunctor> 
-    class UnaryFunctorImageFilter;
-}
-
-class ColorLabel;
-class ColorLabelTable;
-
-/**
- * \class LabelImageWrapper
- * \brief ImageWrapper for segmentation images in SNAP/IRIS.
- * 
- * An extension of the ImageWrapper class for dealing with segmentation
- * images.  Using a table of color labels, it is possible to get RGBA 
- * slices from these images.
- *
- * \sa ImageWrapper
- */
-class LabelImageWrapper : public ScalarImageWrapper<LabelType>
-{
-public:
-
-  /**
-   * Set the table of color labels used to produce color slice images
-   */  
-  void SetLabelColorTable(ColorLabelTable *labels);
-
-  /**
-   * Get the color label table
-   */
-  ColorLabelTable *GetLabelColorTable() const;
-
-  /**
-   * Tell the object to update it's color mapping cache
-   * TODO: Implement this with ModifiedTime stuff
-   */
-  void UpdateColorMappingCache();
-
-  /**
-   * Get a color slice for display purposes
-   */
-  DisplaySlicePointer GetDisplaySlice(unsigned int dim) const;
-
-  /** Constructor initializes mapper */
-  LabelImageWrapper();
-
-  /** Constructor that copies another wrapper */
-  LabelImageWrapper(const LabelImageWrapper &source);
-
-  /** Destructor */
-  ~LabelImageWrapper();  
-
-private:
-  /**
-   * Functor used for display caching.  This class keeps a pointer to 
-   * the table of colors and maps colors to RGBA Pixels
-   */
-  class IntensityFunctor {
-  public:    
-      /** The pointer to the label table */
-      ColorLabelTable *m_ColorLabelTable;
-
-      /** The operator that maps label to color */
-      DisplayPixelType operator()(const LabelType &x) const;
-
-      // Dummy equality operators, since there is no data here
-      bool operator == (const IntensityFunctor &) const { return true; }
-      bool operator != (const IntensityFunctor &) const { return false; }
-  };
-
-  // Type of intensity function used to map 3D volume intensity into
-  // 2D slice intensities
-  // typedef 
-  //  UnaryFunctorCache<LabelType,DisplayPixelType,IntensityFunctor> CacheType;  
-  // typedef itk::SmartPointer<CacheType> CachePointer;
-  // typedef CacheType::CachingFunctor CacheFunctor;
-
-  // Filter applied to slices
-  typedef itk::Image<LabelType,2> LabelSliceType;
-
-
-  typedef LabelToRGBAFilter RGBAFilterType;
-  typedef RGBAFilterType::Pointer RGBAFilterPointer;
-
-  RGBAFilterPointer m_RGBAFilter[3];
-
-  // typedef 
-  //  itk::UnaryFunctorImageFilter<LabelSliceType,DisplaySliceType,CacheFunctor>
-  //  IntensityFilterType;
-  // typedef itk::SmartPointer<IntensityFilterType> IntensityFilterPointer;
-
-  /**
-   * An instance of the private intensity mapper (this mapper wraps the passed
-   * in list of labels
-   */
-  // IntensityFunctor m_IntensityFunctor;
-
-  /**
-   * A cache used for the intensity mapping function
-   */
-  // CachePointer m_IntensityMapCache;
-
-  /**
-   * Filters used to remap the intensity of the slices in this image
-   * into unsigned char images
-   */
-  // IntensityFilterPointer m_IntensityFilter[3];
-};
-
-#endif // __LabelImageWrapper_h_
diff --git a/Logic/ImageWrapper/LabelToRGBAFilter.h b/Logic/ImageWrapper/LabelToRGBAFilter.h
index 4ac87d0..f2dd8bd 100644
--- a/Logic/ImageWrapper/LabelToRGBAFilter.h
+++ b/Logic/ImageWrapper/LabelToRGBAFilter.h
@@ -21,6 +21,9 @@
 #include "itkImageToImageFilter.h"
 #include "ColorLabelTable.h"
 
+#include <itkRGBAPixel.h>
+#include <itkNumericTraitsRGBAPixel.h>
+
 /**
  * \class LabelToRGBAFilter
  * \brief Simple filter that maps label image to RGB color image
@@ -55,10 +58,17 @@ public:
                       InputImageType::ImageDimension);
 
   /** Set color table macro */
-  irisSetMacro(ColorTable, ColorLabelTable *);
+  void SetColorTable(ColorLabelTable *table)
+  {
+    m_ColorTable = table;
+    this->SetNthInput(1, table);
+  }
   
   /** Get color table */
-  irisGetMacro(ColorTable, ColorLabelTable *);
+  ColorLabelTable *GetColorTable()
+  {
+    return m_ColorTable;
+  }
 
 protected:
 
@@ -84,17 +94,28 @@ protected:
 
     // Get the clear label
     const ColorLabel &clear = m_ColorTable->GetColorLabel(0);
+    const ColorLabel *cllast = &clear;
+
+    // Keep track of the last pixel - this reduces the amount of color label
+    // lookups, taking advantage of the fact that segmentations are homogeneous
+    InputPixelType last_pixel = 0;
 
     // Simple loop
-    const LabelType *xin = inputPtr->GetBufferPointer();
+    const LabelType *xin = inputPtr->GetBufferPointer(), *xinend = xin + n;
     OutputPixelType *xout = outputPtr->GetBufferPointer();
-    for(size_t i = 0; i < n; i++)
+    for(; xin < xinend; ++xin, ++xout)
       {
-      const ColorLabel &cl = m_ColorTable->GetColorLabel(xin[i]);
-      if(cl.IsVisible())
-        cl.GetRGBAVector(xout[i].GetDataPointer());
-      else
-        clear.GetRGBAVector(xout[i].GetDataPointer());
+      if(*xin != last_pixel)
+        {
+        last_pixel = *xin;
+        const ColorLabel &cl = m_ColorTable->GetColorLabel(last_pixel);
+        if(cl.IsVisible())
+          cllast = &cl;
+        else
+          cllast = &clear;
+        }
+
+      cllast->GetRGBAVector(xout->GetDataPointer());
       }
     }
 
diff --git a/Logic/ImageWrapper/LevelSetImageWrapper.cxx b/Logic/ImageWrapper/LevelSetImageWrapper.cxx
deleted file mode 100644
index 9c102ed..0000000
--- a/Logic/ImageWrapper/LevelSetImageWrapper.cxx
+++ /dev/null
@@ -1,141 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: LevelSetImageWrapper.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/06/28 18:45:08 $
-  Version:   $Revision: 1.6 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "LevelSetImageWrapper.h"
-#include "ImageWrapper.txx"
-#include "ScalarImageWrapper.txx"
-#include "ColorLabel.h"
-
-// Create an instance of ImageWrapper of appropriate type
-template class ImageWrapper<float>;
-template class ScalarImageWrapper<float>;
-
-
-LevelSetImageWrapper::DisplayPixelType
-LevelSetImageWrapper::MappingFunctor
-::operator()(float in)
-{
-  // Negative values are 'inside'
-  return in <= 0.0f ? m_InsidePixel : m_OutsidePixel;
-
-  // Use this code to display the level set directly
-  // TODO: Add an option to use this form of display
-  /* 
-  LevelSetImageWrapper::DisplayPixelType pixel(m_OutsidePixel);
-
-  if(in > -4.0 && in < 4.0) 
-  {
-    if(in <= 0)
-    {
-      pixel[0] = (unsigned char) (255 + in * 64);
-      pixel[1] = (unsigned char) (255 + in * 64);
-      pixel[2] = 255;
-    }
-    else
-    {
-      pixel[0] = 255;
-      pixel[1] = (unsigned char) (255 - in * 64);
-      pixel[2] = (unsigned char) (255 - in * 64);
-    }    
-
-    pixel[3] = m_InsidePixel[3];
-  }
-  else if(in <= -4.0)
-    {
-    pixel[0] = 0; pixel[1] = 0; pixel[2] = 255;
-    pixel[3] = 255;
-    }
-  else if(in >= 4.0)
-    {
-    pixel[0] = 255; pixel[1] = 0; pixel[2] = 0;
-    pixel[3] = 255;
-    }
-
-  return pixel;
-  */
-}
-
-LevelSetImageWrapper
-::LevelSetImageWrapper()
-: ScalarImageWrapper<float> ()
-{
-  // Intialize display filters
-  for(unsigned int i=0;i<3;i++) 
-    {
-    // Create the intensity mapping filter
-    m_DisplayFilter[i] = IntensityFilterType::New();
-
-    // Set the corresponding slice as the input image
-    m_DisplayFilter[i]->SetInput(GetSlice(i));
-    }
-
-  // Initialize to Edge mode
-  m_MappingFunctor.m_InsidePixel.Fill(0);
-  m_MappingFunctor.m_OutsidePixel.Fill(0);  
-}
-
-LevelSetImageWrapper
-::~LevelSetImageWrapper()
-{
-}
-
-LevelSetImageWrapper::DisplaySlicePointer 
-LevelSetImageWrapper
-::GetDisplaySlice(unsigned int iSlice) const
-{
-  // Depending on the current mode, return the display slice or the 
-  // original slice from the parent
-  return m_DisplayFilter[iSlice]->GetOutput();
-}
-
-void 
-LevelSetImageWrapper
-::SetColorLabel(const ColorLabel &label)
-{
-  m_MappingFunctor.m_InsidePixel[0] = label.GetRGB(0);
-  m_MappingFunctor.m_InsidePixel[1] = label.GetRGB(1);
-  m_MappingFunctor.m_InsidePixel[2] = label.GetRGB(2);
-
-  // Figure out the alpha for display
-  unsigned char alpha = 
-    label.IsVisible() ? (label.IsOpaque() ? 255 : label.GetAlpha()) : 0;
-
-  m_MappingFunctor.m_InsidePixel[3] = alpha;
-
-  // Intialize display filters
-  for(unsigned int i=0;i<3;i++) 
-    {
-    m_DisplayFilter[i]->SetFunctor(m_MappingFunctor);
-    }
-}
diff --git a/Logic/ImageWrapper/LevelSetImageWrapper.h b/Logic/ImageWrapper/LevelSetImageWrapper.h
deleted file mode 100644
index 62c8957..0000000
--- a/Logic/ImageWrapper/LevelSetImageWrapper.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: LevelSetImageWrapper.h,v $
-  Language:  C++
-  Date:      $Date: 2009/08/25 21:38:16 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __LevelSetImageWrapper_h_
-#define __LevelSetImageWrapper_h_
-
-#include "ScalarImageWrapper.h"
-
-// Forward references to ITK
-namespace itk {
-  template <class TInput,class TOutput,class TFunctor> 
-    class UnaryFunctorImageFilter;
-};
-class ColorLabel;
-
-/**
- * \class LevelSetImageWrapper
- * \brief Image wraper for level set images in SNAP
- *
- * The slices generated by this wrapper are processed such that
- * the interior (negative) regions of the level set image are mapped
- * to an RGB value and the exterior regions are black.
- * 
- * \sa ImageWrapper
- */
-class LevelSetImageWrapper : public ScalarImageWrapper<float>
-{
-public:
-
-  /** Set the color label for inside */
-  void SetColorLabel(const ColorLabel &label);
-  
-  /**
-   * Get the display slice in a given direction.  To change the
-   * display slice, call parent's MoveToSlice() method
-   */
-  DisplaySlicePointer GetDisplaySlice(unsigned int dim) const;
-
-  /** Constructor initializes mappers */
-  LevelSetImageWrapper();
-
-  /** Destructor */
-  ~LevelSetImageWrapper();
-
-private:
-  /**
-   * A very simple functor used to map intensities
-   */
-  class MappingFunctor 
-  {
-  public:
-    DisplayPixelType operator()(float in);
-    DisplayPixelType m_InsidePixel;
-    DisplayPixelType m_OutsidePixel;
-    
-    // Dummy equality operators, since there is no data here
-    bool operator == (const MappingFunctor &z) const 
-      { 
-      return
-        m_InsidePixel == z.m_InsidePixel &&
-        m_OutsidePixel == z.m_OutsidePixel;
-      }
-      
-    bool operator != (const MappingFunctor &z) const 
-      { return !(*this == z); }
-  };  
-  
-  // Type of the display intensity mapping filter used when the 
-  // input is a in-out image
-  typedef itk::UnaryFunctorImageFilter<
-    ImageWrapper<float>::SliceType,DisplaySliceType,MappingFunctor> 
-    IntensityFilterType;
-  typedef itk::SmartPointer<IntensityFilterType> IntensityFilterPointer;
-
-  /** 
-   * The filters used to remap internal level set image 
-   * to a color display image
-   */
-  IntensityFilterPointer m_DisplayFilter[3];
-
-  /** The currently used overlay functor */
-  MappingFunctor m_MappingFunctor;
-};
-
-#endif // __LevelSetImageWrapper_h_
diff --git a/Logic/ImageWrapper/NativeIntensityMappingPolicy.h b/Logic/ImageWrapper/NativeIntensityMappingPolicy.h
new file mode 100644
index 0000000..784fd0f
--- /dev/null
+++ b/Logic/ImageWrapper/NativeIntensityMappingPolicy.h
@@ -0,0 +1,83 @@
+#ifndef NATIVEINTENSITYMAPPING_H
+#define NATIVEINTENSITYMAPPING_H
+
+/**
+ * @brief The AbstractNativeIntensityMapping class
+ * This class is the parent in a hierarchy of classes describing a mapping from
+ * the internal datatype to the 'native' datatype. These mappings are used
+ * in cases where the image is represented internally as a short type, although
+ * the underlying data is in the reals.
+ */
+class AbstractNativeIntensityMapping
+{
+public:
+  virtual double operator() (double g) const = 0;
+  virtual double MapGradientMagnitudeToNative(double g) const = 0;
+  virtual double MapInternalToNative(double g) const = 0;
+  virtual double MapNativeToInternal(double g) const = 0;
+  virtual double GetScale() const = 0;
+  virtual double GetShift() const = 0;
+};
+
+class LinearInternalToNativeIntensityMapping : public AbstractNativeIntensityMapping
+{
+public:
+  double operator() (double g) const
+    { return MapInternalToNative(g); }
+
+  double MapGradientMagnitudeToNative(double internalGM) const
+    { return internalGM * scale; }
+
+  double MapInternalToNative(double internal) const
+    { return internal * scale + shift; }
+
+  double MapNativeToInternal(double native) const
+    { return (native - shift) / scale; }
+
+  virtual double GetScale() const { return scale; }
+  virtual double GetShift() const { return shift; }
+
+  LinearInternalToNativeIntensityMapping() : scale(1.0), shift(0.0) {}
+  LinearInternalToNativeIntensityMapping(double a, double b) : scale(a), shift(b) {}
+
+protected:
+  double scale;
+  double shift;
+};
+
+class SpeedImageInternalToNativeIntensityMapping
+    : public LinearInternalToNativeIntensityMapping
+{
+public:
+  SpeedImageInternalToNativeIntensityMapping()
+  {
+    // Map the range of short to -1 : 1
+    short smin = -0x7fff, smax = 0x7fff;
+    this->scale = 2.0 / ((int) smax - (int) smin);
+    this->shift = 0.0;
+  }
+};
+
+class IdentityInternalToNativeIntensityMapping : public AbstractNativeIntensityMapping
+{
+public:
+  double operator() (double g) const
+    { return g; }
+
+  double MapGradientMagnitudeToNative(double internalGM) const
+    { return internalGM; }
+
+  double MapInternalToNative(double internal) const
+    { return internal; }
+
+  double MapNativeToInternal(double native) const
+    { return native; }
+
+  virtual double GetScale() const { return 1; }
+  virtual double GetShift() const { return 0; }
+
+};
+
+
+
+#endif // NATIVEINTENSITYMAPPING_H
diff --git a/Logic/ImageWrapper/RGBImageWrapper.cxx b/Logic/ImageWrapper/RGBImageWrapper.cxx
deleted file mode 100644
index 1b3700c..0000000
--- a/Logic/ImageWrapper/RGBImageWrapper.cxx
+++ /dev/null
@@ -1,98 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: RGBImageWrapper.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/06/28 18:45:08 $
-  Version:   $Revision: 1.7 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "RGBImageWrapper.h"
-#include "ImageWrapper.txx"
-#include "VectorImageWrapper.txx"
-
-// Create an instance of ImageWrapper of appropriate type
-template class ImageWrapper<RGBType>;
-template class VectorImageWrapper<RGBType>;
-
-
-RGBImageWrapper
-::RGBImageWrapper()
-: VectorImageWrapper<RGBType> ()
-{
-  // Intialize display filters
-  for(unsigned int i=0;i<3;i++) 
-    {
-    // Create the intensity mapping filter
-    m_DisplayFilter[i] = IntensityFilterType::New();
-
-    // Set the intensity functor
-    m_DisplayFilter[i]->SetFunctor(m_IntensityFunctor);
-
-    // Set the corresponding slice as the input image
-    m_DisplayFilter[i]->SetInput(GetSlice(i));
-    }
-}
-
-RGBImageWrapper
-::~RGBImageWrapper()
-{
-  for (size_t i = 0; i < 3; ++i)
-    {
-    m_DisplayFilter[i] = NULL;
-    }
-}
-
-RGBImageWrapper::DisplaySlicePointer
-RGBImageWrapper
-::GetDisplaySlice(unsigned int iSlice) const
-{
-  // Depending on the current mode, return the display slice or the 
-  // original slice from the parent
-  //return m_IsModeInsideOutside ? 
-  //  m_DisplayFilter[iSlice]->GetOutput() : 
-  //  GetSlice(iSlice);
-  return m_DisplayFilter[iSlice]->GetOutput();
-}
-
-RGBImageWrapper::DisplayPixelType
-RGBImageWrapper::IntensityFunctor
-::operator()(const RGBType &x) const
-{
-  // Create a new pixel
-  DisplayPixelType pixel;
-  pixel[0] = x[0];
-  pixel[1] = x[1];
-  pixel[2] = x[2];
-  if (x[0] != 0 || x[1] != 0 || x[2] != 0)
-    pixel[3] = 255;
-  else
-    pixel[3] = 0;
-  return pixel;
-}
-
diff --git a/Logic/ImageWrapper/RGBImageWrapper.h b/Logic/ImageWrapper/RGBImageWrapper.h
deleted file mode 100644
index 5220589..0000000
--- a/Logic/ImageWrapper/RGBImageWrapper.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*=========================================================================
-
-  Program:   Insight Segmentation & Registration Toolkit
-  Module:    $RCSfile: RGBImageWrapper.h,v $
-  Language:  C++
-  Date:      $Date: 2009/08/25 21:38:16 $
-  Version:   $Revision: 1.6 $
-  Copyright (c) 2003 Insight Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-#ifndef __RGBImageWrapper_h_
-#define __RGBImageWrapper_h_
-
-#include "VectorImageWrapper.h"
-
-// Forward references to ITK
-namespace itk {
-  template <class TInput,class TOutput,class TFunctor> 
-    class UnaryFunctorImageFilter;
-  template <class TOutput> class ImageSource;
-};
-
-// Disable 'inheritance by dominance' warining in VC6
-#if defined(_WIN32) && defined(_MSC_VER)
-  #pragma warning (disable: 4250)
-#endif
-
-/**
- * \class RGBImageWrapper
- * \brief Image wrapper for RGB images in SNAP
- *
- * \sa ImageWrapper
- */
-class RGBImageWrapper : public VectorImageWrapper<RGBType>
-{
-public:
-  // Basics
-  typedef RGBImageWrapper Self;
-  typedef VectorImageWrapper<RGBType> Superclass;
-  typedef Superclass::ImageType ImageType;
-
-  /**
-   * Get the display slice in a given direction.  To change the
-   * display slice, call parent's MoveToSlice() method
-   */
-  DisplaySlicePointer GetDisplaySlice(unsigned int dim) const;
-
-  /** Constructor initializes mappers */
-  RGBImageWrapper();
-
-  /** Destructor */
-  ~RGBImageWrapper();
-
-private:
-  
-  class IntensityFunctor {
-  public:
-    /** The operator that maps label to color */
-    DisplayPixelType operator()(const RGBType &x) const;
-
-    // Equality operators required, if variables defined!!!
-    bool operator == (const IntensityFunctor &z) const
-      {
-      return true;
-      }
-    bool operator != (const IntensityFunctor &z) const
-      {
-      return !(*this == z);
-      }
-  };
-
-  // Type of the display intensity mapping filter used when the 
-  // input is a in-out image
-  typedef itk::Image<RGBType,2> RGBSliceType;
-  typedef itk::UnaryFunctorImageFilter<
-    RGBSliceType,DisplaySliceType,IntensityFunctor> 
-    IntensityFilterType;
-  typedef itk::SmartPointer<IntensityFilterType> IntensityFilterPointer;
-
-  IntensityFilterPointer m_DisplayFilter[3];
-
-  IntensityFunctor m_IntensityFunctor;
-
-};
-
-#endif // __RGBImageWrapper_h_
diff --git a/Logic/ImageWrapper/ScalarImageHistogram.cxx b/Logic/ImageWrapper/ScalarImageHistogram.cxx
new file mode 100644
index 0000000..b4f2061
--- /dev/null
+++ b/Logic/ImageWrapper/ScalarImageHistogram.cxx
@@ -0,0 +1,126 @@
+#include "ScalarImageHistogram.h"
+#include <algorithm>
+
+ScalarImageHistogram::ScalarImageHistogram()
+{
+  m_BinWidth = 0;
+  m_FirstBinStart = 0;
+  m_Scale = 0;
+  m_MaxFrequency = 0;
+  m_TotalSamples = 0;
+  m_BinCount = 0;
+}
+
+ScalarImageHistogram::~ScalarImageHistogram()
+{
+
+}
+
+void
+ScalarImageHistogram
+::Initialize(double vmin, double vmax, size_t nBins)
+{
+  // Must be more than one bin
+  assert(nBins > 0);
+
+  // min and max should be the center
+  m_BinWidth = (vmax - vmin) / nBins;
+
+  // Set the edge of the first bin
+  m_FirstBinStart = vmin;
+
+  // Set the scale factor for computing the bins
+  m_Scale = 1.0 / m_BinWidth;
+
+  // Allocate the histogram
+  m_BinCount = nBins;
+  m_Bins.clear();
+  m_Bins.resize(m_BinCount, 0);
+
+  m_MaxFrequency = 0;
+  m_TotalSamples = 0;
+}
+
+
+double
+ScalarImageHistogram
+::GetBinMin(size_t iBin) const
+{
+  return m_FirstBinStart + iBin * m_BinWidth;
+}
+
+double
+ScalarImageHistogram
+::GetBinMax(size_t iBin) const
+{
+  return m_FirstBinStart + (iBin + 1) * m_BinWidth;
+}
+
+double
+ScalarImageHistogram
+::GetBinCenter(size_t iBin) const
+{
+  return m_FirstBinStart + (iBin + 0.5) * m_BinWidth;
+}
+
+unsigned long
+ScalarImageHistogram
+::GetFrequency(size_t iBin)  const
+{
+  return m_Bins[iBin];
+}
+
+size_t
+ScalarImageHistogram
+::GetSize() const
+{
+  return m_BinCount;
+}
+
+void
+ScalarImageHistogram
+::AddCompatibleHistogram(const Self &addee)
+{
+  assert(addee.m_Bins.size() == m_Bins.size());
+  assert(addee.m_FirstBinStart == m_FirstBinStart);
+  assert(addee.m_BinWidth == m_BinWidth);
+
+  for(unsigned int i = 0; i < m_Bins.size(); i++)
+    {
+    unsigned long n = addee.m_Bins[i];
+    unsigned long k = (m_Bins[i] += n);
+    m_MaxFrequency = std::max(m_MaxFrequency, k);
+    m_TotalSamples+=n;
+    }
+}
+
+void ScalarImageHistogram::ApplyIntensityTransform(double scale, double shift)
+{
+  m_FirstBinStart = scale * m_FirstBinStart + shift;
+  m_BinWidth = scale * m_BinWidth;
+  m_Scale = 1.0 / m_BinWidth;
+}
+
+double ScalarImageHistogram::GetReasonableDisplayCutoff(double quantile, double quantile_height) const
+{
+  std::vector<unsigned long> binsort = m_Bins;
+  std::sort(binsort.begin(), binsort.end());
+
+  int n = binsort.size();
+  int pos = std::min(std::max((int) (0.5 + quantile * (n - 1)) , 0), n - 1);
+  unsigned long qval = binsort[pos];
+  double cutoff_freq = std::min(qval * 1.0 / quantile_height, (double) binsort.back());
+  double cutoff_fraction = cutoff_freq / m_MaxFrequency;
+
+  // Find the closest power of 10 smaller than the cutoff
+  // p <= cutoff < 10p
+  double p = pow(10, std::floor(log10(cutoff_fraction)));
+  double cutoff_rnd = std::ceil(cutoff_fraction / p) * p;
+
+  return cutoff_rnd;
+}
+
+
+
+
+
diff --git a/Logic/ImageWrapper/ScalarImageHistogram.h b/Logic/ImageWrapper/ScalarImageHistogram.h
new file mode 100644
index 0000000..176614f
--- /dev/null
+++ b/Logic/ImageWrapper/ScalarImageHistogram.h
@@ -0,0 +1,90 @@
+#ifndef SCALARIMAGEHISTOGRAM_H
+#define SCALARIMAGEHISTOGRAM_H
+
+#include <itkDataObject.h>
+#include <itkObjectFactory.h>
+#include <SNAPCommon.h>
+
+#include <vector>
+
+/**
+  A very simple histogram object. It just contains a set of bins
+  counting the intensities in an image.
+  */
+class ScalarImageHistogram : public itk::DataObject
+{
+public:
+  irisITKObjectMacro(ScalarImageHistogram, itk::DataObject)
+
+  void Initialize(double vmin, double vmax, size_t nBins);
+  void AddSample(double v);
+  double GetBinMin(size_t iBin) const;
+  double GetBinMax(size_t iBin) const;
+  double GetBinCenter(size_t iBin) const;
+  unsigned long GetFrequency(size_t iBin) const;
+  size_t GetSize() const;
+
+  /**
+   * Add the contents of an existing histogram to the current histogram. The
+   * code assumes that the histograms have been initialized with the same
+   * parameters to Initialize(). This is used in multi-threaded code to build
+   * histograms
+   */
+  void AddCompatibleHistogram(const Self &addee);
+
+  /**
+   * Apply an intensity transform to the histogram. This applies scaling and
+   * shift to the bin boundaries.
+   */
+  void ApplyIntensityTransform(double scale, double shift);
+
+  /**
+   * Determine the largest frequency to display in the plot of the histogram.
+   * Sometimes histograms have bins that are much higher than most of the
+   * histogram (e.g., background voxels all zero in an image), and we want to
+   * set a cutoff for the y-axis when showing such a histogram, so that the
+   * bulk of the histogram is visible. We determine range here by taking the
+   * 95th percentile of the histogram bin frequencies, and plotting that at
+   * the level of 80% of the y-axis.
+   *
+   * The return value is relative to MaxFrequency, e.g., 0.1
+   */
+  double GetReasonableDisplayCutoff(double quantile=0.95, double quantile_height=0.80) const;
+
+  irisGetMacro(MaxFrequency, unsigned long)
+  irisGetMacro(TotalSamples, unsigned long)
+  irisGetMacro(BinWidth, double)
+
+protected:
+  ScalarImageHistogram();
+  virtual ~ScalarImageHistogram();
+
+  std::vector<unsigned long> m_Bins;
+
+  double m_FirstBinStart, m_BinWidth, m_Scale;
+  unsigned long m_MaxFrequency, m_TotalSamples;
+  int m_BinCount;
+
+};
+
+inline void ScalarImageHistogram::AddSample(double v)
+{
+  int index = (int) (m_Scale * (v - m_FirstBinStart));
+
+  if(index < 0)
+    index = 0;
+  else if(index >= m_BinCount)
+    index = m_BinCount - 1;
+
+  unsigned long k = ++m_Bins[index];
+
+  // Update total, max frequency
+  if(m_MaxFrequency < k)
+    m_MaxFrequency = k;
+
+  m_TotalSamples++;
+}
+
+
+
+#endif // SCALARIMAGEHISTOGRAM_H
diff --git a/Logic/ImageWrapper/ScalarImageWrapper.cxx b/Logic/ImageWrapper/ScalarImageWrapper.cxx
new file mode 100644
index 0000000..8c7d814
--- /dev/null
+++ b/Logic/ImageWrapper/ScalarImageWrapper.cxx
@@ -0,0 +1,357 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: ScalarImageWrapper.txx,v $
+  Language:  C++
+  Date:      $Date: 2009/01/24 01:50:21 $
+  Version:   $Revision: 1.4 $
+  Copyright (c) 2003 Insight Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even 
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     PURPOSE.  See the above copyright notices for more information.
+=========================================================================*/
+
+#include "ScalarImageWrapper.h"
+#include "ImageWrapperTraits.h"
+#include "itkImageRegionIterator.h"
+#include "itkImageSliceConstIteratorWithIndex.h"
+#include "itkNumericTraits.h"
+#include "itkRegionOfInterestImageFilter.h"
+#include "itkRescaleIntensityImageFilter.h"
+#include "itkIdentityTransform.h"
+#include "itkResampleImageFilter.h"
+#include "itkNearestNeighborInterpolateImageFunction.h"
+#include "itkBSplineInterpolateImageFunction.h"
+#include "itkWindowedSincInterpolateImageFunction.h"
+#include "itkLinearInterpolateImageFunction.h"
+#include "itkVTKImageExport.h"
+#include "itkStreamingImageFilter.h"
+
+#include "IRISSlicer.h"
+#include "SNAPSegmentationROISettings.h"
+#include "itkCommand.h"
+#include "itkMinimumMaximumImageFilter.h"
+#include "itkGradientMagnitudeImageFilter.h"
+#include "itkVectorImageToImageAdaptor.h"
+#include "IRISException.h"
+#include "VectorImageWrapper.h"
+#include "ScalarImageHistogram.h"
+#include "ThreadedHistogramImageFilter.h"
+
+#include "vtkImageImport.h"
+
+#include <iostream>
+
+template<class TTraits, class TBase>
+ScalarImageWrapper<TTraits,TBase>
+::ScalarImageWrapper()
+{
+  m_MinMaxFilter = MinMaxFilter::New();
+  m_HistogramFilter = HistogramFilterType::New();
+
+  m_GradientMagnitudeFilter = GradMagFilter::New();
+  m_GradientMagnitudeFilter->ReleaseDataFlagOn();
+
+  // TODO: This filter is a huge waste of memory because it computes the
+  // gradient of the image just to obtain a maximum value. Not only that,
+  // the filter is applied to the common representation (float) image, so
+  // it requires another intermediate volume. The right thing to do would
+  // be to implement a filter that computes the maximum possible gradient
+  // magnitude of the image using a streaming implementation, and without
+  // having to cast to float.
+  m_GradientMagnitudeMaximumFilter = GradMagMaxFilter::New();
+  m_GradientMagnitudeMaximumFilter->SetInput(m_GradientMagnitudeFilter->GetOutput());
+
+  // Set up VTK export pipeline
+  this->SetupVTKImportExport();
+}
+
+template<class TTraits, class TBase>
+ScalarImageWrapper<TTraits,TBase>
+::ScalarImageWrapper(const Self &copy)
+{
+  Superclass::CommonInitialization();
+
+  // If the source contains an image, make a copy of that image
+  if (copy.IsInitialized() && copy.GetImage())
+    {
+    // Create and allocate the image
+    ImagePointer newImage = ImageType::New();
+    newImage->SetRegions(copy.GetImage()->GetBufferedRegion());
+    newImage->Allocate();
+
+    // Copy the image contents
+    typedef typename ImageType::InternalPixelType InternalPixelType;
+    InternalPixelType *ptrTarget = newImage->GetBufferPointer();
+    InternalPixelType *ptrSource = copy.GetImage()->GetBufferPointer();
+    memcpy(ptrTarget,ptrSource,
+           sizeof(InternalPixelType) * newImage->GetBufferedRegion().GetNumberOfPixels());
+    
+    UpdateImagePointer(newImage);
+    }
+}
+
+template<class TTraits, class TBase>
+ScalarImageWrapper<TTraits,TBase>
+::~ScalarImageWrapper()
+{
+
+}
+
+
+template<class TTraits, class TBase>
+void 
+ScalarImageWrapper<TTraits,TBase>
+::UpdateImagePointer(ImageType *newImage) 
+{
+  // Call the parent
+  Superclass::UpdateImagePointer(newImage);
+
+  // Update the max-min pipeline once we have one setup
+  m_MinMaxFilter->SetInput(newImage);
+
+  // Update the histogram mini-pipeline
+  m_HistogramFilter->SetInput(newImage);
+  m_HistogramFilter->SetRangeInputs(m_MinMaxFilter->GetMinimumOutput(),
+                                    m_MinMaxFilter->GetMaximumOutput());
+
+  // Set the number of bins to default
+  m_HistogramFilter->SetNumberOfBins(DEFAULT_HISTOGRAM_BINS);
+
+  // Update the common representation policy
+  m_CommonRepresentationPolicy.UpdateInputImage(newImage);
+
+  // Also update the grad max range pipeline
+  CommonFormatImageType *imgCommon =
+      m_CommonRepresentationPolicy.GetOutput(ScalarImageWrapperBase::WHOLE_IMAGE);
+
+  m_GradientMagnitudeFilter->SetInput(imgCommon);
+
+  m_VTKExporter->SetInput(newImage);
+}
+
+template <class TTraits, class TBase>
+void
+ScalarImageWrapper<TTraits,TBase>
+::SetNativeMapping(NativeIntensityMapping mapping)
+{
+  Superclass::SetNativeMapping(mapping);
+
+  // Propagate the mapping to the histogram
+  m_HistogramFilter->SetIntensityTransform(mapping.GetScale(), mapping.GetShift());
+}
+
+
+template<class TTraits, class TBase>
+void 
+ScalarImageWrapper<TTraits,TBase>
+::CheckImageIntensityRange() 
+{
+  // Image should be loaded
+  assert(this->m_Image);
+
+  // Check if the image has been updated since the last time that
+  // the min/max has been computed
+  m_MinMaxFilter->Update();
+  m_ImageScaleFactor = 1.0 / (m_MinMaxFilter->GetMaximum() - m_MinMaxFilter->GetMinimum());
+}
+
+template<class TTraits, class TBase>
+typename ScalarImageWrapper<TTraits,TBase>::ComponentTypeObject *
+ScalarImageWrapper<TTraits,TBase>
+::GetImageMinObject() const
+{
+  return m_MinMaxFilter->GetMinimumOutput();
+}
+
+template<class TTraits, class TBase>
+typename ScalarImageWrapper<TTraits,TBase>::ComponentTypeObject *
+ScalarImageWrapper<TTraits,TBase>
+::GetImageMaxObject() const
+{
+  return m_MinMaxFilter->GetMaximumOutput();
+}
+
+template<class TTraits, class TBase>
+double
+ScalarImageWrapper<TTraits,TBase>
+::GetImageGradientMagnitudeUpperLimit()
+{
+  m_GradientMagnitudeMaximumFilter->Update();
+  return m_GradientMagnitudeMaximumFilter->GetMaximum();
+}
+
+template<class TTraits, class TBase>
+double
+ScalarImageWrapper<TTraits,TBase>
+::GetImageGradientMagnitudeUpperLimitNative()
+{
+  return this->m_NativeMapping.MapGradientMagnitudeToNative(
+        this->GetImageGradientMagnitudeUpperLimit());
+}
+
+
+template<class TTraits, class TBase>
+double 
+ScalarImageWrapper<TTraits,TBase>
+::GetImageScaleFactor()
+{
+  // Make sure min/max are up-to-date
+  CheckImageIntensityRange();
+
+  // Return the max or min
+  return m_ImageScaleFactor;
+}
+
+/** Compute statistics over a run of voxels in the image starting at the index
+ * startIdx. Appends the statistics to a running sum and sum of squared. The
+ * statistics are returned in internal (not native mapped) format */
+template<class TTraits, class TBase>
+void
+ScalarImageWrapper<TTraits, TBase>
+::GetRunLengthIntensityStatistics(
+    const itk::ImageRegion<3> &region,
+    const itk::Index<3> &startIdx, long runlength,
+    double *out_sum, double *out_sumsq) const
+{
+  ConstIterator it(this->m_Image, region);
+  it.SetIndex(startIdx);
+
+  // Perform the integration
+  for(long q = 0; q < runlength; q++, ++it)
+    {
+    double p = (double) it.Get();
+    *out_sum += p;
+    *out_sumsq += p * p;
+    }
+}
+
+/**
+  Get the RGBA apperance of the voxel at the intersection of the three
+  display slices.
+  */
+template<class TTraits, class TBase>
+void
+ScalarImageWrapper<TTraits,TBase>
+::GetVoxelUnderCursorDisplayedValueAndAppearance(
+    vnl_vector<double> &out_value, DisplayPixelType &out_appearance)
+{
+  // Make sure the display slice is updated
+  this->GetDisplaySlice(0)->GetSource()->UpdateLargestPossibleRegion();
+
+  // Find the correct voxel in the space of the first display slice
+  Vector3ui idxDisp =
+      this->GetImageToDisplayTransform(0).TransformVoxelIndex(this->GetSliceIndex());
+
+  // Get the RGB value
+  typename DisplaySliceType::IndexType idx2D = {{idxDisp[0], idxDisp[1]}};
+  out_appearance = this->GetDisplaySlice(0)->GetPixel(idx2D);
+
+  // Get the numerical value
+  PixelType val_raw = this->GetSlicer(0)->GetOutput()->GetPixel(idx2D);
+  out_value.set_size(1);
+  out_value[0] = this->m_NativeMapping(val_raw);
+}
+
+template<class TTraits, class TBase>
+void
+ScalarImageWrapper<TTraits,TBase>
+::SetupVTKImportExport()
+{
+  // Initialize the VTK Exporter
+  m_VTKExporter = VTKExporter::New();
+  m_VTKExporter->ReleaseDataFlagOn();
+
+  // Initialize the VTK Importer
+  m_VTKImporter = vtkImageImport::New();
+  m_VTKImporter->ReleaseDataFlagOn();
+
+  // Pipe the importer into the exporter (that's a lot of code)
+  m_VTKImporter->SetUpdateInformationCallback(
+        m_VTKExporter->GetUpdateInformationCallback());
+  m_VTKImporter->SetPipelineModifiedCallback(
+        m_VTKExporter->GetPipelineModifiedCallback());
+  m_VTKImporter->SetWholeExtentCallback(
+        m_VTKExporter->GetWholeExtentCallback());
+  m_VTKImporter->SetSpacingCallback(
+        m_VTKExporter->GetSpacingCallback());
+  m_VTKImporter->SetOriginCallback(
+        m_VTKExporter->GetOriginCallback());
+  m_VTKImporter->SetScalarTypeCallback(
+        m_VTKExporter->GetScalarTypeCallback());
+  m_VTKImporter->SetNumberOfComponentsCallback(
+        m_VTKExporter->GetNumberOfComponentsCallback());
+  m_VTKImporter->SetPropagateUpdateExtentCallback(
+        m_VTKExporter->GetPropagateUpdateExtentCallback());
+  m_VTKImporter->SetUpdateDataCallback(
+        m_VTKExporter->GetUpdateDataCallback());
+  m_VTKImporter->SetDataExtentCallback(
+        m_VTKExporter->GetDataExtentCallback());
+  m_VTKImporter->SetBufferPointerCallback(
+        m_VTKExporter->GetBufferPointerCallback());
+  m_VTKImporter->SetCallbackUserData(
+        m_VTKExporter->GetCallbackUserData());
+}
+
+template<class TTraits, class TBase>
+vtkImageImport *
+ScalarImageWrapper<TTraits,TBase>
+::GetVTKImporter()
+{
+  return m_VTKImporter;
+}
+
+template<class TTraits, class TBase>
+typename ScalarImageWrapper<TTraits, TBase>::CommonFormatImageType *
+ScalarImageWrapper<TTraits, TBase>
+::GetCommonFormatImage(ExportChannel channel)
+{
+  return m_CommonRepresentationPolicy.GetOutput(channel);
+}
+
+template<class TTraits, class TBase>
+IntensityCurveInterface *
+ScalarImageWrapper<TTraits, TBase>
+::GetIntensityCurve() const
+{
+  return this->m_DisplayMapping->GetIntensityCurve();
+}
+
+template<class TTraits, class TBase>
+ColorMap *
+ScalarImageWrapper<TTraits, TBase>
+::GetColorMap() const
+{
+  return this->m_DisplayMapping->GetColorMap();
+}
+
+template<class TTraits, class TBase>
+const ScalarImageHistogram *
+ScalarImageWrapper<TTraits,TBase>
+::GetHistogram(size_t nBins)
+{
+  // If the user passes in a non-zero number of bins, we pass that as a
+  // parameter to the filter
+  if(nBins > 0)
+    m_HistogramFilter->SetNumberOfBins(nBins);
+
+  m_HistogramFilter->Update();
+  return m_HistogramFilter->GetHistogramOutput();
+}
+
+
+template class ScalarImageWrapper<LabelImageWrapperTraits>;
+template class ScalarImageWrapper<SpeedImageWrapperTraits>;
+template class ScalarImageWrapper<LevelSetImageWrapperTraits>;
+template class ScalarImageWrapper< ComponentImageWrapperTraits<GreyType> >;
+template class ScalarImageWrapper< AnatomicScalarImageWrapperTraits<GreyType> >;
+
+typedef VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMagnitudeFunctor> MagTraits;
+typedef VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMaxFunctor> MaxTraits;
+typedef VectorDerivedQuantityImageWrapperTraits<GreyVectorToScalarMeanFunctor> MeanTraits;
+template class ScalarImageWrapper<MagTraits>;
+template class ScalarImageWrapper<MaxTraits>;
+template class ScalarImageWrapper<MeanTraits>;
+
diff --git a/Logic/ImageWrapper/ScalarImageWrapper.h b/Logic/ImageWrapper/ScalarImageWrapper.h
index b08db63..944a434 100644
--- a/Logic/ImageWrapper/ScalarImageWrapper.h
+++ b/Logic/ImageWrapper/ScalarImageWrapper.h
@@ -35,9 +35,19 @@
 #ifndef __ScalarImageWrapper_h_
 #define __ScalarImageWrapper_h_
 
-// Smart pointers have to be included from ITK, can't forward reference them
 #include "ImageWrapper.h"
-#include <itkMinimumMaximumImageCalculator.h>
+#include "vtkSmartPointer.h"
+
+// Forward references
+template<class TIn> class ThreadedHistogramImageFilter;
+namespace itk {
+  template<class TIn> class MinimumMaximumImageFilter;
+  template<class TIn, class TOut> class GradientMagnitudeImageFilter;
+  template<class TInputImage> class VTKImageExport;
+}
+
+class vtkImageImport;
+
 
 /**
  * \class ScalarImageWrapper
@@ -47,56 +57,68 @@
  * is used to unify the treatment of different kinds of scalar images in
  * SNaP.  
  */
-template<class TPixel> class ScalarImageWrapper : public ImageWrapper<TPixel>
+template<class TTraits, class TBase = ScalarImageWrapperBase>
+class ScalarImageWrapper : public ImageWrapper<TTraits, TBase>
 {
 public:
 
-  // Basic type definitions
-  typedef itk::OrientedImage<TPixel,3> ImageType;
-  typedef typename itk::SmartPointer<ImageType> ImagePointer;
+  // Standard ITK business
+  typedef ScalarImageWrapper<TTraits, TBase>                              Self;
+  typedef ImageWrapper<TTraits, TBase>                              Superclass;
+  typedef SmartPtr<Self>                                               Pointer;
+  typedef SmartPtr<const Self>                                    ConstPointer;
+  itkTypeMacro(ScalarImageWrapper, ImageWrapper)
+  itkNewMacro(Self)
+
+
+  // Image Types
+  typedef typename Superclass::ImageType                             ImageType;
+  typedef typename Superclass::ImagePointer                       ImagePointer;
+  typedef typename Superclass::PixelType                             PixelType;
+  typedef typename Superclass::CommonFormatImageType     CommonFormatImageType;
 
   // Slice image type
-  typedef itk::Image<TPixel,2> SliceType;
-  typedef typename itk::SmartPointer<SliceType> SlicePointer;
+  typedef typename Superclass::SliceType                             SliceType;
+  typedef typename Superclass::SlicePointer                       SlicePointer;
 
   // Slicer type
-  typedef IRISSlicer<TPixel> SlicerType;
-  typedef typename itk::SmartPointer<SlicerType> SlicerPointer;
+  typedef typename Superclass::SlicerType                           SlicerType;
+  typedef typename Superclass::SlicerPointer                     SlicerPointer;
+
+  // Display types
+  typedef typename Superclass::DisplaySliceType               DisplaySliceType;
+  typedef typename Superclass::DisplayPixelType               DisplayPixelType;
 
   // MinMax calculator type
-  typedef itk::MinimumMaximumImageCalculator<ImageType> MinMaxCalculatorType;
-  typedef typename itk::SmartPointer<MinMaxCalculatorType> 
-    MinMaxCalculatorPointer;
+  typedef itk::MinimumMaximumImageFilter<ImageType>               MinMaxFilter;
+
+  // Histogram filter
+  typedef ThreadedHistogramImageFilter<ImageType>          HistogramFilterType;
 
   // Iterator types
-  typedef typename itk::ImageRegionIterator<ImageType> Iterator;
-  typedef typename itk::ImageRegionConstIterator<ImageType> ConstIterator;
+  typedef typename Superclass::Iterator                               Iterator;
+  typedef typename Superclass::ConstIterator                     ConstIterator;
 
-  /** 
-   * Default constructor.  Creates an image wrapper with a blank internal 
-   * image 
-   */
-  ScalarImageWrapper() {};
+  // Output channels
+  typedef typename Superclass::ExportChannel                     ExportChannel;
 
-  /** 
-   * Copy constructor.  Copies the contents of the passed-in image wrapper. 
-   */
-  ScalarImageWrapper(const ScalarImageWrapper<TPixel> &copy);
-  
-  /** Destructor */
-  virtual ~ScalarImageWrapper() {};
+  // Pipeline objects wrapped around values
+  typedef typename Superclass::ComponentTypeObject         ComponentTypeObject;
+
+  typedef typename Superclass::NativeIntensityMapping   NativeIntensityMapping;
 
-  /**
-   * Get the minimum intensity value.  Call ComputeImageIntensityRange() 
-   * first.
-   */
-  virtual TPixel GetImageMin();
+
+  virtual bool IsScalar() const { return true; }
 
   /**
-   * Get the maximum intensity value.  Call ComputeImageIntensityRange() 
-   * first.
+   * This function just returns the pointer to itself, as the scalar representation
+   * of a scalar image wrapper is itself.
+   * @see ImageWrapperBase::GetScalarRepresentation
    */
-  virtual TPixel GetImageMax();
+  ScalarImageWrapperBase *GetDefaultScalarRepresentation() { return this; }
+
+  /** Access the min/max filter */
+  irisGetMacro(MinMaxFilter, MinMaxFilter *)
 
   /**
    * Get the scaling factor used to convert between intensities stored
@@ -104,31 +126,150 @@ public:
    */
   virtual double GetImageScaleFactor();
 
+  typedef typename ImageWrapperBase::ShortImageType ShortImageType;
+
+  /** This image type has only one component */
+  virtual size_t GetNumberOfComponents() const { return 1; }
+
+  /** Voxel access */
+  virtual double GetVoxelAsDouble(const itk::Index<3> &idx) const
+    { return (double) Superclass::GetVoxel(idx); }
+
+  virtual double GetVoxelAsDouble(const Vector3ui &v) const
+    { return (double) Superclass::GetVoxel(v); }
+
+  virtual void GetVoxelAsDouble(const Vector3ui &x, double *out) const
+    { out[0] = Superclass::GetVoxel(x); }
+
+  virtual void GetVoxelAsDouble(const itk::Index<3> &idx, double *out) const
+    { out[0] = Superclass::GetVoxel(idx); }
+
   /**
-   * Remap the intensity range of the image to a given range
+   * Get voxel intensity in native space
    */
-  virtual void RemapIntensityToRange(TPixel min, TPixel max);
+  double GetVoxelMappedToNative(const Vector3ui &vec) const
+    { return this->m_NativeMapping(this->GetVoxel(vec)); }
+
+  double GetVoxelMappedToNative(const itk::Index<3> &idx) const
+    { return this->m_NativeMapping(this->GetVoxel(idx)); }
+
+  virtual void GetVoxelMappedToNative(const Vector3ui &vec, double *out) const
+    { out[0] = this->m_NativeMapping(Superclass::GetVoxel(vec)); }
+
+  virtual void GetVoxelMappedToNative(const itk::Index<3> &idx, double *out) const
+    { out[0] = this->m_NativeMapping(Superclass::GetVoxel(idx)); }
+
+  /** Compute statistics over a run of voxels in the image starting at the index
+   * startIdx. Appends the statistics to a running sum and sum of squared. The
+   * statistics are returned in internal (not native mapped) format */
+  virtual void GetRunLengthIntensityStatistics(
+      const itk::ImageRegion<3> &region,
+      const itk::Index<3> &startIdx, long runlength,
+      double *out_sum, double *out_sumsq) const;
 
   /**
-   * Remap the intensity range to max possible range
+   * This method returns a vector of values for the voxel under the cursor.
+   * This is the natural value or set of values that should be displayed to
+   * the user. The value depends on the current display mode. For scalar
+   * images, it's just the value of the voxel, but for multi-component images,
+   * it's the value of the selected component (if there is one) or the value
+   * of the multiple components when the mode is RGB. In the second parameter,
+   * the method returns the RGB appearance of the voxel under the cursor
    */
-  virtual void RemapIntensityToMaximumRange();
+  virtual void GetVoxelUnderCursorDisplayedValueAndAppearance(
+      vnl_vector<double> &out_value, DisplayPixelType &out_appearance);
+
+  virtual ComponentTypeObject *GetImageMinObject() const;
+
+  virtual ComponentTypeObject *GetImageMaxObject() const;
 
   /**
-   * This method is used to perform a deep copy of a region of this image 
-   * into another image, potentially resampling the region to use a different
-   * voxel size
+    Compute the image histogram. The histogram is cached inside of the
+    object, so repeated calls to this function with the same nBins parameter
+    will not require additional computation.
+
+    Calling with default parameter (0) will use the same number of bins that
+    is currently in the histogram (i.e., return/recompute current histogram).
+    If there is no current histogram, a default histogram with 128 entries
+    will be generated.
+
+    For multi-component data, the histogram is pooled over all components.
+    */
+  const ScalarImageHistogram *GetHistogram(size_t nBins = 0);
+
+  /**
+    Get the maximum possible value of the gradient magnitude. This will
+    compute the gradient magnitude of the image (without Gaussian smoothing)
+    and return the maximum. The value will be cached so repeated calls to
+    this are not expensive.
+    */
+  double GetImageGradientMagnitudeUpperLimit();
+
+  /**
+    Get the maximum possible value of the gradient magnitude in native units
+    */
+  double GetImageGradientMagnitudeUpperLimitNative();
+
+  /**
+   * Get an image cast to a common representation.
+   * @see ScalarImageWrapperBase::GetCommonFormatImage()
    */
-  ImagePointer DeepCopyRegion(const SNAPSegmentationROISettings &roi,
-                              itk::Command *progressCommand = NULL) const;
+  CommonFormatImageType* GetCommonFormatImage(
+      ExportChannel channel = ScalarImageWrapperBase::WHOLE_IMAGE);
+
+  /** Return the intensity curve for this layer if it exists */
+  virtual IntensityCurveInterface *GetIntensityCurve() const;
+
+  /** Return the color map for this layer if it exists */
+  virtual ColorMap *GetColorMap() const;
+
+  /** Get a version of this image that is usable in VTK pipelines */
+  vtkImageImport *GetVTKImporter();
+
+  /** Extends parent method */
+  virtual void SetNativeMapping(NativeIntensityMapping mapping);
+
 
 protected:
 
+  /**
+   * Default constructor.  Creates an image wrapper with a blank internal
+   * image
+   */
+  ScalarImageWrapper();
+
+  /**
+   * Copy constructor.  Copies the contents of the passed-in image wrapper.
+   */
+  ScalarImageWrapper(const Self &copy);
+
+  /** Destructor */
+  virtual ~ScalarImageWrapper();
+
   /** 
-   * The min-max calculator used to hold min/max values.  This should be
-   * replaced by a filter, when the latter is more efficient
+   * The min-max filter used to compute the range of the image on demand.
+   */
+  SmartPtr<MinMaxFilter> m_MinMaxFilter;
+
+  /**
+   * The filter used for histogram computation
    */
-  MinMaxCalculatorPointer m_MinMaxCalc;
+  SmartPtr<HistogramFilterType> m_HistogramFilter;
+
+  // The policy used to extract a common representation image
+  typedef typename TTraits::CommonRepresentationPolicy CommonRepresentationPolicy;
+  CommonRepresentationPolicy m_CommonRepresentationPolicy;
+
+  /**
+    A mini-pipeline to compute the maximum value of the gradient of
+    the input image on demand.
+    */
+  typedef itk::Image<float ,3> FloatImageType;
+  typedef itk::GradientMagnitudeImageFilter<CommonFormatImageType, FloatImageType> GradMagFilter;
+  typedef itk::MinimumMaximumImageFilter<FloatImageType> GradMagMaxFilter;
+
+  SmartPtr<GradMagFilter> m_GradientMagnitudeFilter;
+  SmartPtr<GradMagMaxFilter> m_GradientMagnitudeMaximumFilter;
 
   /** The intensity scaling factor */
   double m_ImageScaleFactor;
@@ -145,6 +286,13 @@ protected:
    */
   virtual void UpdateImagePointer(ImageType *);
 
+
+  typedef itk::VTKImageExport<ImageType> VTKExporter;
+  SmartPtr<VTKExporter> m_VTKExporter;
+
+  vtkSmartPointer<vtkImageImport> m_VTKImporter;
+
+  void SetupVTKImportExport();
 };
 
 #endif // __ScalarImageWrapper_h_
diff --git a/Logic/ImageWrapper/ScalarImageWrapper.txx b/Logic/ImageWrapper/ScalarImageWrapper.txx
deleted file mode 100644
index 504de7f..0000000
--- a/Logic/ImageWrapper/ScalarImageWrapper.txx
+++ /dev/null
@@ -1,269 +0,0 @@
-/*=========================================================================
-
-  Program:   Insight Segmentation & Registration Toolkit
-  Module:    $RCSfile: ScalarImageWrapper.txx,v $
-  Language:  C++
-  Date:      $Date: 2009/01/24 01:50:21 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2003 Insight Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-#ifndef __ScalarImageWrapper_txx_
-#define __ScalarImageWrapper_txx_
-
-#include "ScalarImageWrapper.h"
-#include "itkImageRegionIterator.h"
-#include "itkImageSliceConstIteratorWithIndex.h"
-#include "itkNumericTraits.h"
-#include "itkRegionOfInterestImageFilter.h"
-#include "itkRescaleIntensityImageFilter.h"
-#include "itkIdentityTransform.h"
-#include "itkResampleImageFilter.h"
-#include "itkNearestNeighborInterpolateImageFunction.h"
-#include "itkBSplineInterpolateImageFunction.h"
-#include "itkWindowedSincInterpolateImageFunction.h"
-#include "itkLinearInterpolateImageFunction.h"
-#include "IRISSlicer.h"
-#include "SNAPSegmentationROISettings.h"
-#include "itkCommand.h"
-
-#include <iostream>
-
-template <class TPixel>
-ScalarImageWrapper<TPixel>
-::ScalarImageWrapper(const ScalarImageWrapper<TPixel> &copy) 
-{
-  ImageWrapper<TPixel>::CommonInitialization();
-
-  // If the source contains an image, make a copy of that image
-  if (copy.IsInitialized() && copy.GetImage())
-    {
-    // Create and allocate the image
-    ImagePointer newImage = ImageType::New();
-    newImage->SetRegions(copy.GetImage()->GetBufferedRegion());
-    newImage->Allocate();
-
-    // Copy the image contents
-    TPixel *ptrTarget = newImage->GetBufferPointer();
-    TPixel *ptrSource = copy.GetImage()->GetBufferPointer();
-    memcpy(ptrTarget,ptrSource,
-           sizeof(TPixel) * newImage->GetBufferedRegion().GetNumberOfPixels());
-    
-    UpdateImagePointer(newImage);
-    }
-}
-
-template <class TPixel>
-void 
-ScalarImageWrapper<TPixel>
-::UpdateImagePointer(ImageType *newImage) 
-{
-  // Update the max-min pipeline once we have one setup
-  m_MinMaxCalc = MinMaxCalculatorType::New();
-  m_MinMaxCalc->SetImage(newImage);
-
-  ImageWrapper<TPixel>::UpdateImagePointer(newImage);
-}
-
-template <class TPixel>
-typename ScalarImageWrapper<TPixel>::ImagePointer
-ScalarImageWrapper<TPixel>
-::DeepCopyRegion(const SNAPSegmentationROISettings &roi,
-                 itk::Command *progressCommand) const
-{
-  // The filter used to chop off the region of interest
-  typedef itk::RegionOfInterestImageFilter <ImageType,ImageType> ChopFilterType;
-  typename ChopFilterType::Pointer fltChop = ChopFilterType::New();
-
-  // Check if there is a difference in voxel size, i.e., user wants resampling
-  Vector3ul vOldSize(this->m_Image->GetLargestPossibleRegion().GetSize().GetSize());
-  Vector3d vOldSpacing(this->m_Image->GetSpacing().GetDataPointer());
-  
-  if(roi.GetResampleFlag())
-    {
-    // Compute the number of voxels in the output
-    typedef typename itk::ImageRegion<3> RegionType;
-    typedef typename itk::Size<3> SizeType;
-
-    SizeType vNewSize;
-    RegionType vNewROI;
-    Vector3d vNewSpacing;
-
-    for(unsigned int i = 0; i < 3; i++) 
-      {
-      double scale = roi.GetVoxelScale()[i];
-      vNewSize.SetElement(i, (unsigned long) (vOldSize[i] / scale));
-      vNewROI.SetSize(i,(unsigned long) (roi.GetROI().GetSize(i) / scale));
-      vNewROI.SetIndex(i,(long) (roi.GetROI().GetIndex(i) / scale));
-      vNewSpacing[i] = scale * vOldSpacing[i];
-      }
-
-    // Create a filter for resampling the image
-    typedef itk::ResampleImageFilter<ImageType,ImageType> ResampleFilterType;
-    typename ResampleFilterType::Pointer fltSample = ResampleFilterType::New();
-
-    // Initialize the resampling filter
-    fltSample->SetInput(this->m_Image);
-    fltSample->SetTransform(itk::IdentityTransform<double,3>::New());
-
-    // Typedefs for interpolators
-    typedef itk::NearestNeighborInterpolateImageFunction<
-      ImageType,double> NNInterpolatorType;
-    typedef itk::LinearInterpolateImageFunction<
-      ImageType,double> LinearInterpolatorType;
-    typedef itk::BSplineInterpolateImageFunction<
-      ImageType,double> CubicInterpolatorType;
-
-    // More typedefs are needed for the sinc interpolator
-    static const unsigned int VRadius = 5;
-    typedef itk::Function::HammingWindowFunction<VRadius> WindowFunction;
-    typedef itk::ConstantBoundaryCondition<ImageType> Condition;
-    typedef itk::WindowedSincInterpolateImageFunction<
-      ImageType, VRadius, 
-      WindowFunction, Condition, double> SincInterpolatorType;
-
-    // Choose the interpolator
-    switch(roi.GetInterpolationMethod())
-      {
-      case SNAPSegmentationROISettings::NEAREST_NEIGHBOR :
-        fltSample->SetInterpolator(NNInterpolatorType::New());
-        break;
-
-      case SNAPSegmentationROISettings::TRILINEAR : 
-        fltSample->SetInterpolator(LinearInterpolatorType::New());
-        break;
-
-      case SNAPSegmentationROISettings::TRICUBIC :
-        fltSample->SetInterpolator(CubicInterpolatorType::New());
-        break;  
-
-      case SNAPSegmentationROISettings::SINC_WINDOW_05 :
-        fltSample->SetInterpolator(SincInterpolatorType::New());
-        break;  
-      };
-
-    // Set the image sizes and spacing
-    fltSample->SetSize(vNewSize);
-    fltSample->SetOutputSpacing(vNewSpacing.data_block());
-    fltSample->SetOutputOrigin(this->m_Image->GetOrigin());
-    fltSample->SetOutputDirection(this->m_Image->GetDirection());
-
-    // Set the progress bar
-    if(progressCommand)
-      fltSample->AddObserver(itk::AnyEvent(),progressCommand);
-
-    // Perform resampling
-    fltSample->GetOutput()->SetRequestedRegion(vNewROI);
-    fltSample->Update();  
-
-    // Pipe into the chopper
-    fltChop->SetInput(fltSample->GetOutput());
-
-    // Update the region of interest
-    fltChop->SetRegionOfInterest(vNewROI);
-    }
-  else
-    {
-    // Pipe image into the chopper
-    fltChop->SetInput(this->m_Image);    
-    
-    // Set the region of interest
-    fltChop->SetRegionOfInterest(roi.GetROI());
-    }
-
-  // Update the pipeline
-  fltChop->Update();
-
-  // Return the resulting image
-  return fltChop->GetOutput();
-}
-
-template <class TPixel> 
-void 
-ScalarImageWrapper<TPixel>
-::CheckImageIntensityRange() 
-{
-  // Image should be loaded
-  assert(this->m_Image && m_MinMaxCalc);
-
-  // Check if the image has been updated since the last time that
-  // the min/max has been computed
-  if (this->m_Image->GetMTime() > m_MinMaxCalc->GetMTime())
-    {
-    m_MinMaxCalc->Compute();
-    m_MinMaxCalc->Modified();
-    m_ImageScaleFactor = 1.0 / (m_MinMaxCalc->GetMaximum() - m_MinMaxCalc->GetMinimum());
-    }
-}
-
-template <class TPixel> 
-TPixel 
-ScalarImageWrapper<TPixel>
-::GetImageMin() 
-{
-  // Make sure min/max are up-to-date
-  CheckImageIntensityRange();
-
-  // Return the max or min
-  return m_MinMaxCalc->GetMinimum();
-}
-
-template <class TPixel> 
-TPixel 
-ScalarImageWrapper<TPixel>
-::GetImageMax()
-{
-  // Make sure min/max are up-to-date
-  CheckImageIntensityRange();
-
-  // Return the max or min
-  return m_MinMaxCalc->GetMaximum();
-}
-
-template <class TPixel>
-double 
-ScalarImageWrapper<TPixel>
-::GetImageScaleFactor()
-{
-  // Make sure min/max are up-to-date
-  CheckImageIntensityRange();
-
-  // Return the max or min
-  return m_ImageScaleFactor;    
-}
-
-template <class TPixel>    
-void 
-ScalarImageWrapper<TPixel>
-::RemapIntensityToRange(TPixel min, TPixel max)
-{
-  typedef itk::RescaleIntensityImageFilter<ImageType> FilterType;
-  typedef typename FilterType::Pointer FilterPointer;
-
-  // Create a filter to remap the intensities
-  FilterPointer filter = FilterType::New();
-  filter->SetInput(this->m_Image);
-  filter->SetOutputMinimum(min);
-  filter->SetOutputMaximum(max);
-
-  // Run the filter
-  filter->Update();
-
-  // Store the output and point everything to it
-  UpdateImagePointer(filter->GetOutput());
-}
-
-template <class TPixel>    
-void 
-ScalarImageWrapper<TPixel>
-::RemapIntensityToMaximumRange()
-{
-  RemapIntensityToRange(itk::NumericTraits<TPixel>::min(),
-                        itk::NumericTraits<TPixel>::max());
-}
-
-#endif // __ScalarImageWrapper_txx_
diff --git a/Logic/ImageWrapper/SpeedColorMap.cxx b/Logic/ImageWrapper/SpeedColorMap.cxx
deleted file mode 100644
index 67a93be..0000000
--- a/Logic/ImageWrapper/SpeedColorMap.cxx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SpeedColorMap.cxx,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:14 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "SpeedColorMap.h"
-
-SpeedColorMap
-::SpeedColorMap()
-{
-  OutputType allBlack[2];
-  SetColorMap(2, allBlack);
-}
-
-void
-SpeedColorMap
-::SetColorMap(unsigned int n, OutputType *colors)
-{
-  // Compute colors and color differences
-  m_ColorEntry.resize(n);
-  m_ColorEntryDelta.resize(n-1);
-  for(unsigned int i = 0; i < n; i++)
-    m_ColorEntry[i] = colors[i];
-  for(unsigned int j = 0; j < n-1; j++)  
-    for(unsigned int k = 0; k < 3; k++)
-      m_ColorEntryDelta[j][k] = 
-        ((float) colors[j+1][k]) - ((float) colors[j][k]);
-
-  // Compute scaling factors
-  m_DeltaT = 0.5 * (n - 1.0f);
-  m_Shift = -m_DeltaT;
-}
-
-SpeedColorMap
-SpeedColorMap
-::GetPresetColorMap(ColorMapPreset xPreset)
-{
-  unsigned char blue[]   = {0   , 0   , 255 , 255 };
-  unsigned char red[]    = {255 , 0   , 0   , 255 };
-  unsigned char white[]  = {255 , 255 , 255 , 255 };
-  unsigned char gray[]   = {128 , 128 , 128 , 255 };
-  unsigned char black[]  = {0   , 0   , 0   , 255 };
-  unsigned char yellow[] = {255 , 255 , 0   , 255 };
-  
-  SpeedColorMap xMap;
-  switch(xPreset) 
-    {
-    case COLORMAP_BLUE_BLACK_WHITE : 
-      xMap.SetColorMap(
-        OutputType(blue), OutputType(black), OutputType(white));
-      break;
-      
-    case COLORMAP_BLACK_GRAY_WHITE : 
-      xMap.SetColorMap(
-        OutputType(black), OutputType(gray), OutputType(white));
-      break;
-      
-    case COLORMAP_BLUE_WHITE_RED : 
-      xMap.SetColorMap(
-        OutputType(blue), OutputType(white), OutputType(red));
-      break;
-
-    case COLORMAP_BLACK_BLACK_WHITE : 
-      xMap.SetColorMap(
-        OutputType(black), OutputType(black), OutputType(white));
-      break;
-
-    case COLORMAP_BLACK_YELLOW_WHITE : 
-      xMap.SetColorMapPositive(
-        OutputType(black), OutputType(yellow), OutputType(white));
-      break;
-    }
-
-  return xMap;
-}
-
diff --git a/Logic/ImageWrapper/SpeedColorMap.h b/Logic/ImageWrapper/SpeedColorMap.h
deleted file mode 100644
index 1613cb3..0000000
--- a/Logic/ImageWrapper/SpeedColorMap.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SpeedColorMap.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:14 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SpeedColorMap_h_
-#define __SpeedColorMap_h_
-
-#include "itkRGBAPixel.h"
-#include "GlobalState.h"
-
-/**
- * \class SpeedColorMap
- * \brief A very simple functor used to map intensities from 
- * the range (-1,1) to RGB color space.
- */
-class SpeedColorMap 
-{
-public:
-  typedef itk::RGBAPixel<unsigned char> OutputType;
-
-  /** Constructor, sets default color map */
-  SpeedColorMap();
-
-  /** 
-   * Mapping operator, maps range [-1, 1] into colors. This operator must
-   * be very fast, because it is called a lot of times in the rendering 
-   * pipeline. So we define it inline, and sacrifice generality for speed 
-   */
-  OutputType operator()(float t)
-    {
-    // We do bounds checking, just in case
-    if(t < -0.99999f) return m_ColorEntry.front();
-    if(t >= 0.99999f) return m_ColorEntry.back();
-
-    // Project u into the array of intensities
-    float u = t * m_DeltaT - m_Shift;
-    unsigned int iu = (int) u;
-    float a = u - iu;
-
-    // Compute the correct color
-    // (1 - a) c[iu] + a c[iu + 1] = c[iu] - a * (c[iu+1] - c[iu])
-    OutputType p = m_ColorEntry[iu];
-    p[0] = (unsigned char) (p[0] + a * m_ColorEntryDelta[iu][0]);
-    p[1] = (unsigned char) (p[1] + a * m_ColorEntryDelta[iu][1]);
-    p[2] = (unsigned char) (p[2] + a * m_ColorEntryDelta[iu][2]);
-
-    // Return the point
-    return p;
-    }
-
-  bool operator == (const SpeedColorMap &z)
-    {
-    return 
-      m_DeltaT == z.m_DeltaT && 
-      m_Shift == z.m_Shift && 
-      m_ColorMapSize == z.m_ColorMapSize &&
-      m_ColorEntry == z.m_ColorEntry;
-    }
-
-  bool operator != (const SpeedColorMap &z)
-    { return !(*this == z); }
-  
-  /** Set the color map by specifying three points (-1, 0 and 1) */
-  void SetColorMap(OutputType inMinus, OutputType inZero, OutputType inPlus) 
-    {
-    OutputType colors[] = {inMinus, inZero, inPlus};
-    SetColorMap(3, colors);
-    }
-
-  /** Set the color map for the positive range only */
-  void SetColorMapPositive(OutputType inZero, OutputType inHalf, OutputType inOne)
-    {
-    OutputType colors[] = {inZero, inZero, inZero, inHalf, inOne};
-    SetColorMap(5, colors);
-    }
-
-  /** Set the color map by specifying a set of n colors between -1 and 1 */
-  void SetColorMap(unsigned int n, OutputType *colors);
-
-  /** Generate a color map for one of the presets */
-  static SpeedColorMap GetPresetColorMap(ColorMapPreset xPreset);
-
-  bool operator!=( const SpeedColorMap & other ) const
-  {
-    bool value = ( ( this->m_DeltaT != other.m_DeltaT ) || 
-                   ( this->m_Shift  != other.m_Shift  ) || 
-                   ( this->m_ColorMapSize  != other.m_ColorMapSize ) );
-      return value;
-  }
-    
-private:
-  // The colors in the color map
-  std::vector<OutputType> m_ColorEntry;
-
-  // Differences between pairs of colors
-  std::vector<Vector3f> m_ColorEntryDelta;
-
-  // Scaling factors used to reference color entries
-  float m_DeltaT;
-  float m_Shift;
-  float m_ColorMapSize;
-};  
-
-#endif
diff --git a/Logic/ImageWrapper/SpeedImageWrapper.cxx b/Logic/ImageWrapper/SpeedImageWrapper.cxx
deleted file mode 100644
index a00eb7e..0000000
--- a/Logic/ImageWrapper/SpeedImageWrapper.cxx
+++ /dev/null
@@ -1,219 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SpeedImageWrapper.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/06/28 18:45:08 $
-  Version:   $Revision: 1.5 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "SpeedImageWrapper.h"
-#include "ImageWrapper.txx"
-#include "ScalarImageWrapper.txx"
-
-
-SpeedImageWrapper
-::SpeedImageWrapper()
-: ScalarImageWrapper<float> ()
-{
-  // Intialize display filters
-  for(unsigned int i=0;i<3;i++) 
-    {
-    // Create the intensity mapping filter
-    m_DisplayFilter[i] = IntensityFilterType::New();
-
-    // Set the corresponding slice as the input image
-    m_DisplayFilter[i]->SetInput(GetSlice(i));
-
-    // Create the overlay mapping filter
-    m_OverlayFilter[i] = OverlayFilterType::New();
-
-    // Set the corresponding slice as the input image
-    m_OverlayFilter[i]->SetInput(GetSlice(i));
-    }
-
-  // Initialize the overlay functor
-  m_OverlayFunctor.m_Cutoff = 0.0f;
-
-  // Initialize to Edge mode
-  m_IsModeInsideOutside = false;
-}
-
-SpeedImageWrapper
-::~SpeedImageWrapper()
-{
-}
-
-SpeedImageWrapper::DisplaySlicePointer
-SpeedImageWrapper
-::GetDisplaySlice(unsigned int iSlice) const
-{
-  // Depending on the current mode, return the display slice or the 
-  // original slice from the parent
-  //return m_IsModeInsideOutside ? 
-  //  m_DisplayFilter[iSlice]->GetOutput() : 
-  //  GetSlice(iSlice);
-  return m_DisplayFilter[iSlice]->GetOutput();
-}
-
-
-SpeedImageWrapper::OverlaySliceType * 
-SpeedImageWrapper
-::GetOverlaySlice(unsigned int dim)
-{
-  return m_OverlayFilter[dim]->GetOutput();
-}
-
-void
-SpeedImageWrapper
-::SetOverlayCutoff(float cutoff)
-{
-  if(cutoff != m_OverlayFunctor.m_Cutoff) 
-    {
-    // Update the variable
-    m_OverlayFunctor.m_Cutoff = cutoff;
-
-    // Update the filters
-    for(unsigned int i=0;i<3;i++)
-      m_OverlayFilter[i]->SetFunctor(m_OverlayFunctor);
-    }
-}
-
-float
-SpeedImageWrapper
-::GetOverlayCutoff() const
-{
-  return m_OverlayFunctor.m_Cutoff;
-}
-
-void
-SpeedImageWrapper
-::SetOverlayColor(const OverlayPixelType &color)
-{
-  if(color != m_OverlayFunctor.m_Color) 
-    {
-    // Update the variable
-    m_OverlayFunctor.m_Color = color;
-
-    // Update the filters
-    for(unsigned int i=0;i<3;i++)
-      m_OverlayFilter[i]->SetFunctor(m_OverlayFunctor);
-    }
-}
-
-void 
-SpeedImageWrapper
-::UpdateImagePointer(ImageType *newImage)
-{
-  // Call the parent's method
-  ImageWrapper<float>::UpdateImagePointer(newImage);
-
-  // Update the sources
-  for(unsigned int i=0;i<3;i++)
-    if(m_PreviewSource[i])
-      m_Slicer[i]->SetInput(m_PreviewSource[i]);      
-}
-
-
-SpeedImageWrapper::OverlayPixelType 
-SpeedImageWrapper
-::GetOverlayColor() const
-{
-  return m_OverlayFunctor.m_Color;
-}
-  
-SpeedImageWrapper::OverlayPixelType 
-SpeedImageWrapper::OverlayFunctor
-::operator()(float in)
-{
-  // Initialize with a clear pixel
-  const unsigned char clear[] = {0,0,0,0};
-  SpeedImageWrapper::OverlayPixelType rtn(clear);
-  
-  // Check the threshold and return appropriate value
-  if(in<m_Cutoff)
-    {
-    return clear;
-    } 
-  return m_Color;
-}
-
-void 
-SpeedImageWrapper
-::SetSliceSourceForPreview(unsigned int slice,ImageType *source)
-{
-  m_PreviewSource[slice] = source;
-  m_Slicer[slice]->SetInput(source);    
-}
-
-void 
-SpeedImageWrapper
-::RemoveSliceSourcesForPreview()
-{
-  for(unsigned int i=0;i<3;i++)
-    {
-    m_PreviewSource[i] = NULL;
-    m_Slicer[i]->SetInput(m_Image);
-    }
-}
-
-float 
-SpeedImageWrapper
-::GetPreviewVoxel(const Vector3ui &point) const
-{
-  // Better be in preview mode
-  assert(m_PreviewSource[0] && m_PreviewSource[1] && m_PreviewSource[2]);
-
-  // Create an index
-  itk::Index<3> index;
-  index[0] = point[0];
-  index[1] = point[1];
-  index[2] = point[2];
-
-  // Make sure the slice is current
-  m_Slicer[0]->Update();
-
-  // Make sure the voxel is in the computed region
-  assert(m_Slicer[0]->GetInput()->GetBufferedRegion().IsInside(index));
-
-  // Return the pixel
-  return m_Slicer[0]->GetInput()->GetPixel(index);    
-}
-
-void
-SpeedImageWrapper
-::SetColorMap(const SpeedColorMap &xColorMap)
-{
-  // Store the color map
-  m_ColorMap = xColorMap;
-
-  // Assign it to the three filters
-  m_DisplayFilter[0]->SetFunctor(m_ColorMap);
-  m_DisplayFilter[1]->SetFunctor(m_ColorMap);
-  m_DisplayFilter[2]->SetFunctor(m_ColorMap);
-}
diff --git a/Logic/ImageWrapper/SpeedImageWrapper.h b/Logic/ImageWrapper/SpeedImageWrapper.h
deleted file mode 100644
index 4140900..0000000
--- a/Logic/ImageWrapper/SpeedImageWrapper.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SpeedImageWrapper.h,v $
-  Language:  C++
-  Date:      $Date: 2009/08/25 21:38:16 $
-  Version:   $Revision: 1.5 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SpeedImageWrapper_h_
-#define __SpeedImageWrapper_h_
-
-#include "ScalarImageWrapper.h"
-#include "SpeedImageWrapper.h"
-#include "SpeedColorMap.h"
-
-// Forward references to ITK
-namespace itk {
-  template <class TInput,class TOutput,class TFunctor> 
-    class UnaryFunctorImageFilter;
-  template <class TOutput> class ImageSource;
-};
-
-// Disable 'inheritance by dominance' warining in VC6
-#if defined(_WIN32) && defined(_MSC_VER)
-  #pragma warning (disable: 4250)
-#endif
-
-/**
- * \class SpeedImageWrapper
- * \brief Image wraper for speed images in SNAP
- *
- * This wrapper remaps floating point slices to byte slices differently
- * depending on if it's in InOut snake mode (some speed values are negative) or
- * in Edge snake mode (speed values are nonnegative).
- *
- * \sa ImageWrapper
- */
-class SpeedImageWrapper : public ScalarImageWrapper<float>
-{
-public:
-  // Basics
-  typedef SpeedImageWrapper Self;
-  typedef ScalarImageWrapper<float> Superclass;
-  typedef Superclass::ImageType ImageType;
-
-  // The type definition for the image used to display overlays based on
-  // speed images
-  typedef itk::RGBAPixel<unsigned char> OverlayPixelType;
-  typedef itk::Image<OverlayPixelType,2> OverlaySliceType;
-  typedef itk::SmartPointer<OverlaySliceType> OverlaySlicePointer;
-
-  /**
-   * Set the preview source for the slices.  This means that the slices
-   * will be generated not from the internal image but from external 
-   * images (outputs of some preprocessing filters)
-   */
-  void SetSliceSourceForPreview(unsigned int slice,ImageType *source);
-
-  /** 
-   * Unset the preview sources for all slices.  The slices will be now
-   * generated from the internal image 
-   */
-  void RemoveSliceSourcesForPreview();
-
-  /** Get a 'preview' voxel, i.e., a voxel from the previewing slices.  For
-   * the results to be valid, the voxel has to be on one of the previewing
-   * slices, and this method is intended for getting the voxel at the
-   * cross-hairs position */
-  float GetPreviewVoxel(const Vector3ui &point) const;
-
-  /**
-   * Indicate that this image is a In/Out speed image that has a 
-   * range of -1 to +1.  
-   */
-  void SetModeToInsideOutsideSnake()
-    {
-    m_IsModeInsideOutside = true;
-    }
-  
-  /**
-   * Indicate that this image is a Edge speed image that has a 
-   * range of 0 to 1.  
-   */
-  void SetModeToEdgeSnake()
-    {
-    m_IsModeInsideOutside = false;
-    }
-
-  /**
-   * Check if the image is in the Inside/Outside or Edge mode
-   */
-  bool IsModeInsideOutsideSnake() const
-    {
-    return m_IsModeInsideOutside;
-    }
-    
-  /**
-   * Check if the image is in the Inside/Outside or Edge mode
-   */
-  bool IsModeEdgeOutsideSnake() const
-    {
-    return !m_IsModeInsideOutside;
-    }
-  
-  /**
-   * Get the display slice in a given direction.  To change the
-   * display slice, call parent's MoveToSlice() method
-   */
-  DisplaySlicePointer GetDisplaySlice(unsigned int dim) const;
-
-  /**
-   * Get an overlay mask slice for displaying on top of the greylevel
-   * segmentation image.  Such slices are used for example to overlay
-   * the thresholding result over the grey slice to give users feedback 
-   * of the segmentation
-   */
-  OverlaySliceType *GetOverlaySlice(unsigned int dim);
-
-  /**
-   * Set the overlay cutoff range.  The intensities above the cutoff will
-   * be included in the overlay
-   */
-  void SetOverlayCutoff(float cutoff);  
-  float GetOverlayCutoff() const;
-
-  typedef itk::ImageSource<ImageType> PreviewFilterType;
-  typedef itk::SmartPointer<PreviewFilterType> PreviewFilterPointer;
-  
-  /**
-   * Set the color for overlay drawing
-   */
-  void SetOverlayColor(const OverlayPixelType &color);
-  OverlayPixelType GetOverlayColor() const;
-
-  /** Set the color map to use for generating color output */
-  void SetColorMap(const SpeedColorMap &xColorMap);
-  
-  /** Constructor initializes mappers */
-  SpeedImageWrapper();
-
-  /** Destructor */
-  ~SpeedImageWrapper();
-
-protected:
-  /** We override this method in order to maintain the preview sources 
-   * when the image gets changed */
-  void UpdateImagePointer(ImageType *newImage);
-
-private:
-  
-  /**
-   * A functor used for overlay mapping
-   */
-  class OverlayFunctor 
-  {
-  public:
-    /** Operator used to map pixels to color */
-    OverlayPixelType operator()(float in);
-
-    bool operator == (const OverlayFunctor &z) const
-      {
-      return
-        m_Cutoff == z.m_Cutoff &&
-        m_Color == z.m_Color;
-      }
-
-    bool operator != (const OverlayFunctor &z) const
-      { return !(*this == z); }
-
-    /** Overlay cutoff */
-    float m_Cutoff;
-
-    /** Overlay color */
-    OverlayPixelType m_Color;
-  };  
-  
-  // Type of the display intensity mapping filter used when the 
-  // input is a in-out image
-  typedef itk::UnaryFunctorImageFilter<
-    ImageWrapper<float>::SliceType,DisplaySliceType,SpeedColorMap> 
-    IntensityFilterType;
-  typedef itk::SmartPointer<IntensityFilterType> IntensityFilterPointer;
-
-  // A mapping filter used to construct overlay images.  This filter assigns
-  // an opaque color to pixels over the cutoff threshold
-  typedef itk::UnaryFunctorImageFilter<
-    ImageWrapper<float>::SliceType,OverlaySliceType,OverlayFunctor> 
-    OverlayFilterType;
-  typedef itk::SmartPointer<OverlayFilterType> OverlayFilterPointer;
-    
-  /** Whether or not the image is in edge or in-out mode */
-  bool m_IsModeInsideOutside;
-
-  /** 
-   * The filters used to remap internal speed image that can be 
-   * in range of -1 to 1 to a display image in range 0 to 1
-   */
-  IntensityFilterPointer m_DisplayFilter[3];
-
-  /**
-   * The filters used to create overlay slices
-   */
-  OverlayFilterPointer m_OverlayFilter[3];
-
-  /** The currently used overlay functor */
-  OverlayFunctor m_OverlayFunctor;
-
-  /** The currently used color map */
-  SpeedColorMap m_ColorMap;
-
-  /** Preview sources */
-  ImagePointer m_PreviewSource[3];
-};
-
-#endif // __SpeedImageWrapper_h_
diff --git a/Logic/ImageWrapper/ThreadedHistogramImageFilter.h b/Logic/ImageWrapper/ThreadedHistogramImageFilter.h
new file mode 100644
index 0000000..289c2dc
--- /dev/null
+++ b/Logic/ImageWrapper/ThreadedHistogramImageFilter.h
@@ -0,0 +1,137 @@
+#ifndef THREADEDHISTOGRAMIMAGEFILTER_H
+#define THREADEDHISTOGRAMIMAGEFILTER_H
+
+#include <itkImageToImageFilter.h>
+#include <itkSimpleDataObjectDecorator.h>
+#include <itkNumericTraits.h>
+#include <ScalarImageHistogram.h>
+
+/**
+ * This ITK-style filter computes the histogram of an ITK scalar image. It
+ * uses threading for faster histogram computation. It also is meant to be
+ * used with the itk::MinimumMaximumImageFilter to avoid an extra pass for
+ * determining the range of the histogram. The histogram in this filter is
+ * constructed from equal size bins between the input min and max, and the
+ * number of bins is a power of two.
+ */
+template <class TInputImage>
+class ThreadedHistogramImageFilter :
+    public itk::ImageToImageFilter<TInputImage, TInputImage>
+{
+public:
+
+  /** Extract dimension from input image. */
+  itkStaticConstMacro(InputImageDimension, unsigned int,
+                      TInputImage::ImageDimension);
+  itkStaticConstMacro(OutputImageDimension, unsigned int,
+                      TInputImage::ImageDimension);
+
+  /** Standard class typedefs. */
+  typedef ThreadedHistogramImageFilter                        Self;
+  typedef itk::ImageToImageFilter< TInputImage, TInputImage > Superclass;
+  typedef itk::SmartPointer< Self >                           Pointer;
+  typedef itk::SmartPointer< const Self >                     ConstPointer;
+
+  /** Image related typedefs. */
+  typedef typename TInputImage::Pointer InputImagePointer;
+
+  typedef typename TInputImage::RegionType RegionType;
+  typedef typename TInputImage::SizeType   SizeType;
+  typedef typename TInputImage::IndexType  IndexType;
+  typedef typename TInputImage::PixelType  PixelType;
+
+  /** Histogram typedefs */
+  typedef ScalarImageHistogram HistogramType;
+  typedef SmartPtr<HistogramType> HistogramPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self)
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(ThreadedHistogramImageFilter, ImageToImageFilter)
+
+  /** Image typedef support. */
+  typedef TInputImage InputImageType;
+
+  /** Type of DataObjects used for scalar outputs */
+  typedef itk::SimpleDataObjectDecorator< PixelType > PixelObjectType;
+
+  /**
+   * Set the range inputs. These are in the format returned by the min/max
+   * image filter. These are inputs to the filter, so will be updated through
+   * the pipeline mechanism if the image itself is updated. It is also possible
+   * for the min/max to be sourced from another image.
+   */
+  void SetRangeInputs(PixelObjectType *inMin, PixelObjectType *inMax);
+
+  /**
+   * Set the desired number of bins for the histogram.
+   */
+  void SetNumberOfBins(int nBins);
+
+  /**
+   * Set an optional transform for the histogram. The range of the output
+   * histogram will be transformed as (scale * x + shift). By default, the
+   * transform is (1, 0).
+   */
+  void SetIntensityTransform(double scale, double shift);
+
+  /**
+   * Get the histogram output
+   */
+  HistogramType *GetHistogramOutput() const { return m_OutputHistogram; }
+
+protected:
+
+  ThreadedHistogramImageFilter();
+  virtual ~ThreadedHistogramImageFilter() {}
+  void PrintSelf(std::ostream & os, itk::Indent indent) const;
+
+  /** Pass the input through unmodified. Do this by Grafting in the
+    AllocateOutputs method. */
+  void AllocateOutputs();
+
+  /** Initialize some accumulators before the threads run. */
+  void BeforeThreadedGenerateData();
+
+  /** Do final mean and variance computation from data accumulated in threads.
+    */
+  void AfterThreadedGenerateData();
+
+  /** Multi-thread version GenerateData. */
+  void  ThreadedGenerateData(const RegionType &outputRegionForThread,
+                             itk::ThreadIdType threadId);
+
+  // Override since the filter needs all the data for the algorithm
+  void GenerateInputRequestedRegion();
+
+  // Override since the filter produces all of its output
+  void EnlargeOutputRequestedRegion(itk::DataObject *data);
+
+private:
+
+  ThreadedHistogramImageFilter(const Self &); //purposely not implemented
+  void operator=(const Self &);               //purposely not implemented
+
+  // Inputs
+  SmartPtr<PixelObjectType> m_InputMin, m_InputMax;
+
+  // Parameter: number of bins
+  unsigned int m_Bins;
+
+  // Intensity transform
+  double m_TransformScale, m_TransformShift;
+
+  // Per-thread histograms
+  std::vector< HistogramPointer > m_ThreadHistogram;
+
+  // The output histogram
+  HistogramPointer m_OutputHistogram;
+};
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "ThreadedHistogramImageFilter.hxx"
+#endif
+
+
+#endif // THREADEDHISTOGRAMIMAGEFILTER_H
diff --git a/Logic/ImageWrapper/ThreadedHistogramImageFilter.hxx b/Logic/ImageWrapper/ThreadedHistogramImageFilter.hxx
new file mode 100644
index 0000000..f5508a6
--- /dev/null
+++ b/Logic/ImageWrapper/ThreadedHistogramImageFilter.hxx
@@ -0,0 +1,167 @@
+#ifndef THREADEDHISTOGRAMIMAGEFILTER_HXX
+#define THREADEDHISTOGRAMIMAGEFILTER_HXX
+
+#include "ThreadedHistogramImageFilter.h"
+#include <itkProgressReporter.h>
+#include <itkImageRegionConstIterator.h>
+
+template <class TInputImage>
+ThreadedHistogramImageFilter<TInputImage>
+::ThreadedHistogramImageFilter()
+{
+  this->SetNumberOfRequiredInputs(3);
+  this->SetNumberOfRequiredOutputs(2);
+
+  // Allocate the output histogram
+  m_OutputHistogram = ScalarImageHistogram::New();
+  this->SetNthOutput(1, m_OutputHistogram);
+
+  m_Bins = 0;
+  m_TransformScale = 1.0;
+  m_TransformShift = 0.0;
+}
+
+template <class TInputImage>
+void
+ThreadedHistogramImageFilter<TInputImage>
+::SetRangeInputs(PixelObjectType *inMin, PixelObjectType *inMax)
+{
+  m_InputMin = inMin;
+  m_InputMax = inMax;
+  this->SetNthInput(1, inMin);
+  this->SetNthInput(2, inMax);
+}
+
+template <class TInputImage>
+void
+ThreadedHistogramImageFilter<TInputImage>
+::SetNumberOfBins(int nBins)
+{
+  if(m_Bins != nBins)
+    {
+    m_Bins = nBins;
+    this->Modified();
+    }
+}
+
+template <class TInputImage>
+void
+ThreadedHistogramImageFilter<TInputImage>
+::SetIntensityTransform(double scale, double shift)
+{
+  if(m_TransformScale != scale || m_TransformShift != shift)
+    {
+    m_TransformScale = scale;
+    m_TransformShift = shift;
+    this->Modified();
+    }
+}
+
+template <class TInputImage>
+void
+ThreadedHistogramImageFilter<TInputImage>
+::GenerateInputRequestedRegion()
+{
+  Superclass::GenerateInputRequestedRegion();
+  if ( this->GetInput() )
+    {
+    InputImagePointer image =
+      const_cast< typename Superclass::InputImageType * >( this->GetInput() );
+    image->SetRequestedRegionToLargestPossibleRegion();
+    }
+}
+
+template <class TInputImage>
+void
+ThreadedHistogramImageFilter<TInputImage>
+::EnlargeOutputRequestedRegion(itk::DataObject *data)
+{
+  Superclass::EnlargeOutputRequestedRegion(data);
+  data->SetRequestedRegionToLargestPossibleRegion();
+}
+
+template <class TInputImage>
+void
+ThreadedHistogramImageFilter<TInputImage>
+::AllocateOutputs()
+{
+  // Pass the input through as the output
+  InputImagePointer image =
+    const_cast< TInputImage * >( this->GetInput() );
+
+  this->GraftOutput(image);
+
+  // Nothing to be done for the histogram output
+}
+
+template <class TInputImage>
+void
+ThreadedHistogramImageFilter<TInputImage>
+::BeforeThreadedGenerateData()
+{
+  itk::ThreadIdType numberOfThreads = this->GetNumberOfThreads();
+
+  // Get the range of the histogram
+  PixelType pxmin = m_InputMin->Get();
+  PixelType pxmax = m_InputMax->Get();
+
+  // Initialize the per-thread histograms
+  m_ThreadHistogram.resize(numberOfThreads);
+  for(unsigned int i = 0; i < numberOfThreads; i++)
+    {
+    m_ThreadHistogram[i] = HistogramType::New();
+    m_ThreadHistogram[i]->Initialize(pxmin, pxmax, m_Bins);
+    }
+
+  // Initialize the output
+  m_OutputHistogram->Initialize(pxmin, pxmax, m_Bins);
+}
+
+template< class TInputImage >
+void
+ThreadedHistogramImageFilter<TInputImage>
+::ThreadedGenerateData(const RegionType &outputRegionForThread,
+                       itk::ThreadIdType threadId)
+{
+  if ( outputRegionForThread.GetNumberOfPixels() == 0 )
+    return;
+
+  // Get the histogram for this thread
+  HistogramType *hist = m_ThreadHistogram[threadId];
+
+  itk::ImageRegionConstIterator< TInputImage > it(this->GetInput(), outputRegionForThread);
+  while(!it.IsAtEnd())
+    {
+    hist->AddSample(it.Get());
+    ++it;
+    }
+}
+
+template< class TInputImage >
+void
+ThreadedHistogramImageFilter<TInputImage>
+::AfterThreadedGenerateData()
+{
+  // Add up the partial histograms
+  for(unsigned int i = 0; i < m_ThreadHistogram.size(); i++)
+    {
+    m_OutputHistogram->AddCompatibleHistogram(*m_ThreadHistogram[i]);
+    }
+
+  // Apply the transform to the histogram
+  m_OutputHistogram->ApplyIntensityTransform(m_TransformScale, m_TransformShift);
+}
+
+template< class TInputImage >
+void
+ThreadedHistogramImageFilter<TInputImage>
+::PrintSelf(std::ostream &os, itk::Indent indent) const
+{
+  Superclass::PrintSelf(os, indent);
+}
+
+
+
+
+
+#endif // THREADEDHISTOGRAMIMAGEFILTER_HXX
diff --git a/Logic/ImageWrapper/UnaryValueToValueFilter.h b/Logic/ImageWrapper/UnaryValueToValueFilter.h
new file mode 100644
index 0000000..e5ef70e
--- /dev/null
+++ b/Logic/ImageWrapper/UnaryValueToValueFilter.h
@@ -0,0 +1,73 @@
+#ifndef UNARYVALUETOVALUEFILTER_H
+#define UNARYVALUETOVALUEFILTER_H
+
+#include "itkProcessObject.h"
+#include "itkSimpleDataObjectDecorator.h"
+#include "SNAPCommon.h"
+
+/**
+ * An ITK pipeline filter that applies transformations to atomic values. The
+ * filter can be used to cast a value from one type to another, or to scale
+ * the value by a constant, etc. The filter is used with objects of type
+ * itk::SimpleDataObjectDecorator. It's main use in SNAP is to manipluate
+ * objects generated by filters like the itk::MinimumMaximumImageFilter. For
+ * example, we can take the minimum of an image (represented as a short),
+ * cast it to double, scale it by some value, and pass it in as an input
+ * to another filter.
+ */
+template <class TFunctor>
+class UnaryValueToValueFilter : public itk::ProcessObject
+{
+public:
+  irisITKObjectMacro(UnaryValueToValueFilter<TFunctor>, itk::ProcessObject)
+
+  typedef typename TFunctor::InputType InputType;
+  typedef typename TFunctor::OutputType OutputType;
+
+  typedef itk::SimpleDataObjectDecorator<InputType> InputObjectType;
+  typedef itk::SimpleDataObjectDecorator<OutputType> OutputObjectType;
+
+  using Superclass::SetInput;
+
+  const InputObjectType *GetInput()
+  {
+    return static_cast<const InputObjectType *>(this->GetPrimaryInput());
+  }
+
+  void SetInput(const InputObjectType *object)
+  {
+    Superclass::SetPrimaryInput(object);
+  }
+
+  OutputObjectType *GetOutput()
+  {
+    return static_cast<OutputObjectType *>(Superclass::GetPrimaryOutput());
+  }
+
+  typename Superclass::DataObjectPointer
+  MakeOutput(DataObjectPointerArraySizeType)
+  {
+    return static_cast<OutputObjectType *>(
+          OutputObjectType::New().GetPointer());
+  }
+
+  void SetFunctor(const TFunctor &f)
+  {
+    m_Functor = f;
+    this->Modified();
+  }
+
+  void GenerateData()
+  {
+    InputType in = this->GetInput()->Get();
+    OutputType out = m_Functor(in);
+    this->GetOutput()->Set(out);
+  }
+
+protected:
+  TFunctor m_Functor;
+
+};
+
+
+#endif // UNARYVALUETOVALUEFILTER_H
diff --git a/Logic/ImageWrapper/VectorImageWrapper.cxx b/Logic/ImageWrapper/VectorImageWrapper.cxx
new file mode 100644
index 0000000..40ec44b
--- /dev/null
+++ b/Logic/ImageWrapper/VectorImageWrapper.cxx
@@ -0,0 +1,477 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: VectorImageWrapper.txx,v $
+  Language:  C++
+  Date:      $Date: 2007/06/06 22:27:21 $
+  Version:   $Revision: 1.1 $
+  Copyright (c) 2003 Insight Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even 
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     PURPOSE.  See the above copyright notices for more information.
+=========================================================================*/
+
+#include "VectorImageWrapper.h"
+#include "itkImageRegionIterator.h"
+#include "itkImageSliceConstIteratorWithIndex.h"
+#include "itkNumericTraits.h"
+#include "itkRegionOfInterestImageFilter.h"
+#include "itkRescaleIntensityImageFilter.h"
+#include "itkIdentityTransform.h"
+#include "IRISSlicer.h"
+#include "SNAPSegmentationROISettings.h"
+#include "itkCommand.h"
+#include "ImageWrapperTraits.h"
+#include "itkVectorImageToImageAdaptor.h"
+#include "itkMinimumMaximumImageFilter.h"
+#include "ThreadedHistogramImageFilter.h"
+#include "ScalarImageHistogram.h"
+#include "Rebroadcaster.h"
+
+#include <iostream>
+
+#include "itkVectorGradientAnisotropicDiffusionImageFilter.h"
+
+
+template <class TTraits, class TBase>
+VectorImageWrapper<TTraits,TBase>
+::VectorImageWrapper()
+{
+  // Initialize the flattened image
+  m_FlatImage = NULL;
+
+  // Initialize the filters
+  m_MinMaxFilter = MinMaxFilterType::New();
+  m_HistogramFilter = HistogramFilterType::New();
+}
+
+template <class TTraits, class TBase>
+VectorImageWrapper<TTraits,TBase>
+::~VectorImageWrapper()
+{
+}
+
+
+
+template <class TTraits, class TBase>
+typename VectorImageWrapper<TTraits,TBase>::ImagePointer
+VectorImageWrapper<TTraits,TBase>
+::DeepCopyRegion(const SNAPSegmentationROISettings &roi,
+                 itk::Command *progressCommand) const
+{
+   return Superclass::DeepCopyRegion(roi, progressCommand);
+}
+
+template<class TTraits, class TBase>
+void
+VectorImageWrapper<TTraits, TBase>
+::GetRunLengthIntensityStatistics(
+    const itk::ImageRegion<3> &region,
+    const itk::Index<3> &startIdx, long runlength,
+    double *out_sum, double *out_sumsq) const
+{
+  ConstIterator it(this->m_Image, region);
+  it.SetIndex(startIdx);
+  size_t nc = this->GetNumberOfComponents();
+
+  // Perform the integration
+  for(long q = 0; q < runlength; q++, ++it)
+    {
+    PixelType p = it.Get();
+    for(size_t c = 0; c < nc; c++)
+      {
+      double v = (double) p[c];
+      out_sum[c] += v;
+      out_sumsq[c] += v * v;
+      }
+    }
+}
+
+template<class TTraits, class TBase>
+void
+VectorImageWrapper<TTraits,TBase>
+::GetVoxelUnderCursorDisplayedValueAndAppearance(
+    vnl_vector<double> &out_value, DisplayPixelType &out_appearance)
+{
+  // Get the numerical value
+  MultiChannelDisplayMode mode = this->m_DisplayMapping->GetDisplayMode();
+  if(mode.UseRGB)
+    {
+    // Make sure the display slice is updated
+    this->GetDisplaySlice(0)->Update();
+
+    // Find the correct voxel in the space of the first display slice
+    Vector3ui idxDisp =
+        this->GetImageToDisplayTransform(0).TransformVoxelIndex(this->GetSliceIndex());
+
+    // Get the RGB value
+    typename DisplaySliceType::IndexType idx2D = {{idxDisp[0], idxDisp[1]}};
+    out_appearance = this->GetDisplaySlice(0)->GetPixel(idx2D);
+
+    // Get the value vector in native range
+    out_value.set_size(this->GetNumberOfComponents());
+    for(int i = 0; i < this->GetNumberOfComponents(); i++)
+      {
+      InternalPixelType p =
+          this->GetComponentWrapper(i)->GetSlicer(0)->GetOutput()->GetPixel(idx2D);
+      out_value[i] = this->m_NativeMapping(p);
+      }
+    }
+  else
+    {
+    // Just delegate to the scalar wrapper
+    ScalarImageWrapperBase *siw =
+        this->GetScalarRepresentation(mode.SelectedScalarRep, mode.SelectedComponent);
+    siw->GetVoxelUnderCursorDisplayedValueAndAppearance(out_value, out_appearance);
+    }
+}
+
+
+template <class TTraits, class TBase>
+void
+VectorImageWrapper<TTraits,TBase>
+::SetNativeMapping(NativeIntensityMapping mapping)
+{
+  Superclass::SetNativeMapping(mapping);
+
+  // Propagate the mapping to the histogram
+  m_HistogramFilter->SetIntensityTransform(mapping.GetScale(), mapping.GetShift());
+
+  // Propagate to owned scalar wrappers
+  for(ScalarRepIterator it = m_ScalarReps.begin(); it != m_ScalarReps.end(); ++it)
+    {
+    ScalarRepIndex idx = it->first;
+    if(idx.first == SCALAR_REP_COMPONENT)
+      {
+      // Cast the wrapper the right type
+      ComponentWrapperType *cw =
+          dynamic_cast<ComponentWrapperType *>(it->second.GetPointer());
+
+      // Pass the native to the component wrapper
+      cw->SetNativeMapping(mapping);
+      }
+
+    // These are the derived wrappers. They use the identity mapping, but they
+    // need to know what the source native mapping is.
+    else if(idx.first == SCALAR_REP_MAGNITUDE)
+      {
+      SetNativeMappingInDerivedWrapper<MagnitudeFunctor>(it->second, mapping);
+      }
+    else if(idx.first == SCALAR_REP_MAX)
+      {
+      SetNativeMappingInDerivedWrapper<MaxFunctor>(it->second, mapping);
+      }
+    else if(idx.first == SCALAR_REP_AVERAGE)
+      {
+      SetNativeMappingInDerivedWrapper<MeanFunctor>(it->second, mapping);
+      }
+    }
+}
+
+template <class TTraits, class TBase>
+template <class TFunctor>
+void
+VectorImageWrapper<TTraits,TBase>
+::SetNativeMappingInDerivedWrapper(
+    ScalarImageWrapperBase *w,
+    NativeIntensityMapping &mapping)
+{
+  typedef VectorDerivedQuantityImageWrapperTraits<TFunctor> WrapperTraits;
+  typedef typename WrapperTraits::WrapperType DerivedWrapper;
+  typedef typename DerivedWrapper::ImageType AdaptorType;
+  typedef typename AdaptorType::AccessorType PixelAccessor;
+
+  // Cast to the right type
+  DerivedWrapper *dw = dynamic_cast<DerivedWrapper *>(w);
+
+  // Get the accessor
+  PixelAccessor &accessor = dw->GetImage()->GetPixelAccessor();
+  accessor.SetSourceNativeMapping(mapping.GetScale(), mapping.GetShift());
+}
+
+template <class TTraits, class TBase>
+template <class TFunctor>
+SmartPtr<ScalarImageWrapperBase>
+VectorImageWrapper<TTraits,TBase>
+::CreateDerivedWrapper(ImageType *image)
+{
+  typedef VectorDerivedQuantityImageWrapperTraits<TFunctor> WrapperTraits;
+  typedef typename WrapperTraits::WrapperType DerivedWrapper;
+  typedef typename DerivedWrapper::ImageType AdaptorType;
+
+  SmartPtr<AdaptorType> adaptor = AdaptorType::New();
+  adaptor->SetImage(image);
+
+  SmartPtr<DerivedWrapper> wrapper = DerivedWrapper::New();
+  wrapper->InitializeToWrapper(this, adaptor);
+
+  // Assign a parent wrapper to the derived wrapper
+  wrapper->SetParentWrapper(this);
+
+  SmartPtr<ScalarImageWrapperBase> ptrout = wrapper.GetPointer();
+
+  // When creating derived wrappers, we need to rebroadcast the events from
+  // that wrapper as our own events
+  Rebroadcaster::RebroadcastAsSourceEvent(wrapper, WrapperChangeEvent(), this);
+
+  return ptrout;
+}
+
+template <class TTraits, class TBase>
+void
+VectorImageWrapper<TTraits,TBase>
+::UpdateImagePointer(ImageType *newImage)
+{
+  // Create the component wrappers before calling the parent's method.
+  int nc = newImage->GetNumberOfComponentsPerPixel();
+
+  // The first component image will serve as the reference for the other
+  // component images
+  ComponentWrapperType *cref = NULL;
+
+  for(int i = 0; i < nc; i++)
+    {
+    // Create a component image
+    typedef itk::VectorImageToImageAdaptor<InternalPixelType,3> ComponentImage;
+    SmartPtr<ComponentImage> comp = ComponentImage::New();
+    comp->SetImage(newImage);
+    comp->SetExtractComponentIndex(i);
+
+    // Create a wrapper for this image and assign the component image
+    SmartPtr<ComponentWrapperType> cw = ComponentWrapperType::New();
+    cw->InitializeToWrapper(this, comp);
+
+    // Assign a parent wrapper to the derived wrapper
+    cw->SetParentWrapper(this);
+
+    // Store the wrapper
+    m_ScalarReps[std::make_pair(
+          SCALAR_REP_COMPONENT, i)] = cw.GetPointer();
+
+    // Rebroadcast the events from that wrapper
+    Rebroadcaster::RebroadcastAsSourceEvent(cw, WrapperChangeEvent(), this);
+    }
+
+  m_ScalarReps[std::make_pair(SCALAR_REP_MAGNITUDE, 0)]
+      = this->template CreateDerivedWrapper<MagnitudeFunctor>(newImage);
+
+  m_ScalarReps[std::make_pair(SCALAR_REP_MAX, 0)]
+      = this->template CreateDerivedWrapper<MaxFunctor>(newImage);
+
+  m_ScalarReps[std::make_pair(SCALAR_REP_AVERAGE, 0)]
+      = this->template CreateDerivedWrapper<MeanFunctor>(newImage);
+
+  // Create a flat representation of the image
+  m_FlatImage = FlatImageType::New();
+  typename FlatImageType::SizeType flatsize;
+  flatsize[0] = newImage->GetPixelContainer()->Size();
+  m_FlatImage->SetRegions(flatsize);
+  m_FlatImage->SetPixelContainer(newImage->GetPixelContainer());
+
+  // Connect the flat image to the min/max computer
+  m_MinMaxFilter->SetInput(m_FlatImage);
+
+  // Hook up the histogram computer to the flat image and min/max filter
+  m_HistogramFilter->SetInput(m_FlatImage);
+  m_HistogramFilter->SetRangeInputs(m_MinMaxFilter->GetMinimumOutput(),
+                                    m_MinMaxFilter->GetMaximumOutput());
+
+  // Set the number of bins (TODO - how to do this smartly?)
+  m_HistogramFilter->SetNumberOfBins(DEFAULT_HISTOGRAM_BINS);
+
+  /*
+
+    // Make sure intensity curve is shared by the components
+    // TODO: what should be shared is the entire pipeline. That requires us to
+    // compute the min/max of the vector components and return them as an
+    // itk::DataObject.
+    if(i == 0)
+      {
+      cref = cw;
+      }
+    else
+      {
+      typedef typename ComponentWrapperType::DisplayMapping ComponentDM;
+      SmartPtr<ComponentDM> cdm = cw->GetDisplayMapping();
+      SmartPtr<ComponentDM> cdmref = cref->GetDisplayMapping();
+      cdm->SetIntensityCurve(cdmref->GetIntensityCurve());
+      cdm->SetColorMap(cdmref->GetColorMap());
+      }
+
+    // Store the component
+    m_ScalarReps[std::make_pair(SCALAR_REP_COMPONENT, i)]
+        = cw.GetPointer();
+    }
+
+  // Initialize the computed derived wrappers
+  ColorMap *cm = cref->GetDisplayMapping()->GetColorMap(); */
+
+  // Call the parent's method = this will initialize the display mapping
+  Superclass::UpdateImagePointer(newImage);
+
+}
+
+template <class TTraits, class TBase>
+inline ScalarImageWrapperBase *
+VectorImageWrapper<TTraits,TBase>
+::GetDefaultScalarRepresentation()
+{
+  ScalarImageWrapperBase *rep =
+      this->m_DisplayMapping->GetScalarRepresentation();
+  if(rep)
+    return rep;
+
+  // TODO: This is somewhat arbitrary! Maybe it should be something the user
+  // can change under settings, i.e., "Default scalar representation for RGB images".
+  return this->GetScalarRepresentation(SCALAR_REP_MAX);
+}
+
+template<class TTraits, class TBase>
+const ScalarImageHistogram *
+VectorImageWrapper<TTraits,TBase>
+::GetHistogram(size_t nBins)
+{
+  // If the user passes in a non-zero number of bins, we pass that as a
+  // parameter to the filter
+  if(nBins > 0)
+    m_HistogramFilter->SetNumberOfBins(nBins);
+
+  m_HistogramFilter->Update();
+  return m_HistogramFilter->GetHistogramOutput();
+}
+
+
+template <class TTraits, class TBase>
+inline ScalarImageWrapperBase *
+VectorImageWrapper<TTraits,TBase>
+::GetScalarRepresentation(
+    ScalarRepresentation type,
+    int index)
+{
+  return m_ScalarReps[std::make_pair(type, index)];
+}
+
+template <class TTraits, class TBase>
+inline ScalarImageWrapperBase *
+VectorImageWrapper<TTraits,TBase>
+::GetScalarRepresentation(const ScalarRepresentationIterator &it)
+{
+  assert(!it.IsAtEnd());
+  return this->GetScalarRepresentation(it.GetCurrent(), it.GetIndex());
+}
+
+template <class TTraits, class TBase>
+bool
+VectorImageWrapper<TTraits,TBase>
+::FindScalarRepresentation(
+    ImageWrapperBase *scalar_rep, ScalarRepresentation &type, int &index) const
+{
+  for(ScalarRepConstIterator it = m_ScalarReps.begin(); it != m_ScalarReps.end(); ++it)
+    {
+    if(it->second.GetPointer() == scalar_rep)
+      {
+      type = it->first.first;
+      index = it->first.second;
+      return true;
+      }
+    }
+
+  return false;
+}
+
+template <class TTraits, class TBase>
+typename VectorImageWrapper<TTraits,TBase>::ComponentWrapperType *
+VectorImageWrapper<TTraits,TBase>
+::GetComponentWrapper(unsigned int index)
+{
+  ScalarRepIndex repidx(SCALAR_REP_COMPONENT, index);
+  return static_cast<ComponentWrapperType *>(m_ScalarReps[repidx].GetPointer());
+}
+
+template <class TTraits, class TBase>
+void
+VectorImageWrapper<TTraits,TBase>
+::SetSliceIndex(const Vector3ui &cursor)
+{
+  Superclass::SetSliceIndex(cursor);
+
+  // Propagate to owned scalar wrappers
+  for(ScalarRepIterator it = m_ScalarReps.begin(); it != m_ScalarReps.end(); ++it)
+    {
+    it->second->SetSliceIndex(cursor);
+    }
+}
+
+template <class TTraits, class TBase>
+void
+VectorImageWrapper<TTraits,TBase>
+::SetDisplayGeometry(IRISDisplayGeometry &dispGeom)
+{
+  Superclass::SetDisplayGeometry(dispGeom);
+  for(ScalarRepIterator it = m_ScalarReps.begin(); it != m_ScalarReps.end(); ++it)
+    it->second->SetDisplayGeometry(dispGeom);
+}
+
+template <class TTraits, class TBase>
+void
+VectorImageWrapper<TTraits,TBase>
+::SetDirectionMatrix(const vnl_matrix<double> &direction)
+{
+  Superclass::SetDirectionMatrix(direction);
+  for(ScalarRepIterator it = m_ScalarReps.begin(); it != m_ScalarReps.end(); ++it)
+    it->second->SetDirectionMatrix(direction);
+}
+
+template <class TTraits, class TBase>
+void
+VectorImageWrapper<TTraits,TBase>
+::CopyImageCoordinateTransform(const ImageWrapperBase *source)
+{
+  Superclass::CopyImageCoordinateTransform(source);
+  for(ScalarRepIterator it = m_ScalarReps.begin(); it != m_ScalarReps.end(); ++it)
+    it->second->CopyImageCoordinateTransform(source);
+}
+
+
+template<class TTraits, class TBase>
+typename VectorImageWrapper<TTraits,TBase>::ComponentTypeObject *
+VectorImageWrapper<TTraits,TBase>
+::GetImageMinObject() const
+{
+  return m_MinMaxFilter->GetMinimumOutput();
+}
+
+template<class TTraits, class TBase>
+typename VectorImageWrapper<TTraits,TBase>::ComponentTypeObject *
+VectorImageWrapper<TTraits,TBase>
+::GetImageMaxObject() const
+{
+  return m_MinMaxFilter->GetMaximumOutput();
+}
+
+
+
+/*
+template <class TImage, class TBase>
+inline double
+VectorImageWrapper<TImage,TBase>
+::GetVoxelAsDouble(const itk::Index<3> &idx) const
+{
+  // By default, return the first component
+  return (double) this->GetVoxel(idx)[0];
+}
+
+template <class TImage, class TBase>
+inline double
+VectorImageWrapper<TImage,TBase>
+::GetVoxelAsDouble(const Vector3ui &x) const
+{
+  // By default, return the first component
+  return (double) this->GetVoxel(x)[0];
+}
+*/
+
+template class VectorImageWrapper<AnatomicImageWrapperTraits<GreyType> >;
+
diff --git a/Logic/ImageWrapper/VectorImageWrapper.h b/Logic/ImageWrapper/VectorImageWrapper.h
index 024f47e..8599eaa 100644
--- a/Logic/ImageWrapper/VectorImageWrapper.h
+++ b/Logic/ImageWrapper/VectorImageWrapper.h
@@ -17,6 +17,17 @@
 
 // Smart pointers have to be included from ITK, can't forward reference them
 #include "ImageWrapper.h"
+#include "itkVariableLengthVector.h"
+#include "itkVectorImageToImageAdaptor.h"
+#include "ScalarImageWrapper.h"
+#include "itkImageAdaptor.h"
+#include "VectorToScalarImageAccessor.h"
+
+template<class TIn> class ThreadedHistogramImageFilter;
+namespace itk
+{
+template<class TIn> class MinimumMaximumImageFilter;
+}
 
 /**
  * \class VectorImageWrapper
@@ -26,39 +37,89 @@
  * is used to unify the treatment of different kinds of vector images in
  * SNaP.  
  */
-template<class TPixel> class VectorImageWrapper : public ImageWrapper<TPixel>
+template<class TTraits, class TBase = VectorImageWrapperBase>
+class VectorImageWrapper
+    : public ImageWrapper<TTraits, TBase>
 {
 public:
 
-  // Basic type definitions
-  typedef itk::OrientedImage<TPixel,3> ImageType;
-  typedef typename itk::SmartPointer<ImageType> ImagePointer;
+  // Standard ITK business
+  typedef VectorImageWrapper<TTraits, TBase>                              Self;
+  typedef ImageWrapper<TTraits, TBase>                              Superclass;
+  typedef SmartPtr<Self>                                               Pointer;
+  typedef SmartPtr<const Self>                                    ConstPointer;
+  itkTypeMacro(VectorImageWrapper, ImageWrapper)
+  itkNewMacro(Self)
+
+  // Image Types
+  typedef typename Superclass::ImageType                             ImageType;
+  typedef typename Superclass::ImagePointer                       ImagePointer;
+
+  // Pixel type
+  typedef typename Superclass::PixelType                             PixelType;
+  typedef typename ImageType::InternalPixelType              InternalPixelType;
 
   // Slice image type
-  typedef itk::Image<TPixel,2> SliceType;
-  typedef typename itk::SmartPointer<SliceType> SlicePointer;
+  typedef typename Superclass::SliceType                             SliceType;
+  typedef typename Superclass::SlicePointer                       SlicePointer;
 
   // Slicer type
-  typedef IRISSlicer<TPixel> SlicerType;
-  typedef typename itk::SmartPointer<SlicerType> SlicerPointer;
+  typedef typename Superclass::SlicerType                           SlicerType;
+  typedef typename Superclass::SlicerPointer                     SlicerPointer;
+
+  // Display types
+  typedef typename Superclass::DisplaySliceType               DisplaySliceType;
+  typedef typename Superclass::DisplayPixelType               DisplayPixelType;
 
   // Iterator types
-  typedef typename itk::ImageRegionIterator<ImageType> Iterator;
-  typedef typename itk::ImageRegionConstIterator<ImageType> ConstIterator;
+  typedef typename Superclass::Iterator                               Iterator;
+  typedef typename Superclass::ConstIterator                     ConstIterator;
+
+  typedef typename Superclass::NativeIntensityMapping   NativeIntensityMapping;
+
+  // Access to the components
+  typedef typename TTraits::ComponentWrapperType          ComponentWrapperType;
+
+  // Pipeline objects wrapped around values
+  typedef typename Superclass::ComponentTypeObject         ComponentTypeObject;
 
-  /** 
-   * Default constructor.  Creates an image wrapper with a blank internal 
-   * image 
+  virtual bool IsScalar() const { return false; }
+
+  /**
+   * This function returns whatever scalar representation is current. The
+   * current representation depends on the display mode of the wrapper. If the
+   * display mode is RGB, the default scalar representation in MaximumComponent,
+   * which is somewhat arbitrary. If the components are being animated, there
+   * is also some ambiguity as to what the default scalar component should be.
+   * @see ImageWrapperBase::GetScalarRepresentation
    */
-  VectorImageWrapper() : ImageWrapper<TPixel>() {};
+  ScalarImageWrapperBase *GetDefaultScalarRepresentation();
 
-  /** 
-   * Copy constructor.  Copies the contents of the passed-in image wrapper. 
+  /**
+   * Get a pointer to the given scalar representation of this vector image.
    */
-  VectorImageWrapper(const VectorImageWrapper<TPixel> &copy) : ImageWrapper<TPixel>(copy) {};
-  
-  /** Destructor */
-  virtual ~VectorImageWrapper() {};
+  ScalarImageWrapperBase *GetScalarRepresentation(
+      ScalarRepresentation type,
+      int index = 0);
+
+  /**
+   * Access a scalar representation using an iterator
+   */
+  virtual ScalarImageWrapperBase *GetScalarRepresentation(
+      const ScalarRepresentationIterator &it);
+
+  /**
+   * If scalar_rep is a scalar representation of the vector image wrapper, find
+   * the type of the representation and the index. Otherwise return false;
+   */
+  bool FindScalarRepresentation(
+      ImageWrapperBase *scalar_rep, ScalarRepresentation &type, int &index) const;
+
+  /**
+   * This returns the same as GetScalarRepresentation(SCALAR_REP_COMPONENT, i),
+   * but cast to its true type, rather than ScalarImageWrapperBase.
+   */
+  ComponentWrapperType *GetComponentWrapper(unsigned int index);
 
   /**
    * This method is used to perform a deep copy of a region of this image 
@@ -68,8 +129,152 @@ public:
   ImagePointer DeepCopyRegion(const SNAPSegmentationROISettings &roi,
                               itk::Command *progressCommand = NULL) const;
 
+
+  /** This image type has only one component */
+  virtual size_t GetNumberOfComponents() const
+  {
+    return this->m_Image->GetNumberOfComponentsPerPixel();
+  }
+
+  /** Voxel access */
+  // virtual double GetVoxelAsDouble(const itk::Index<3> &idx) const;
+
+  /** Voxel access */
+  // virtual double GetVoxelAsDouble(const Vector3ui &v) const;
+
+  virtual void GetVoxelAsDouble(const Vector3ui &x, double *out) const
+  {
+    const PixelType &p = Superclass::GetVoxel(x);
+    for(unsigned int i = 0; i < this->GetNumberOfComponents(); i++)
+      out[i] = p[i];
+  }
+
+  virtual void GetVoxelAsDouble(const itk::Index<3> &idx, double *out) const
+  {
+    const PixelType &p = Superclass::GetVoxel(idx);
+    for(unsigned int i = 0; i < this->GetNumberOfComponents(); i++)
+      out[i] = p[i];
+  }
+
+  virtual void GetVoxelMappedToNative(const Vector3ui &x, double *out) const
+  {
+    const PixelType &p = Superclass::GetVoxel(x);
+    for(unsigned int i = 0; i < this->GetNumberOfComponents(); i++)
+      out[i] = this->m_NativeMapping(p[i]);
+  }
+
+  virtual void GetVoxelMappedToNative(const itk::Index<3> &idx, double *out) const
+  {
+    const PixelType &p = Superclass::GetVoxel(idx);
+    for(unsigned int i = 0; i < this->GetNumberOfComponents(); i++)
+      out[i] = this->m_NativeMapping(p[i]);
+  }
+
+  /**
+   * Get the component-wise minimum and maximum of the image in native format
+   */
+  virtual ComponentTypeObject *GetImageMinObject() const;
+  virtual ComponentTypeObject *GetImageMaxObject() const;
+
+  /** Compute statistics over a run of voxels in the image starting at the index
+   * startIdx. Appends the statistics to a running sum and sum of squared. The
+   * statistics are returned in internal (not native mapped) format */
+  virtual void GetRunLengthIntensityStatistics(
+      const itk::ImageRegion<3> &region,
+      const itk::Index<3> &startIdx, long runlength,
+      double *out_sum, double *out_sumsq) const;
+
+  /**
+   * This method returns a vector of values for the voxel under the cursor.
+   * This is the natural value or set of values that should be displayed to
+   * the user. The value depends on the current display mode. For scalar
+   * images, it's just the value of the voxel, but for multi-component images,
+   * it's the value of the selected component (if there is one) or the value
+   * of the multiple components when the mode is RGB. In the second parameter,
+   * the method returns the RGB appearance of the voxel under the cursor
+   */
+  virtual void GetVoxelUnderCursorDisplayedValueAndAppearance(
+      vnl_vector<double> &out_value, DisplayPixelType &out_appearance);
+
+  virtual void SetNativeMapping(NativeIntensityMapping mapping);
+
+  virtual void SetSliceIndex(const Vector3ui &cursor);
+
+  virtual void SetDisplayGeometry(IRISDisplayGeometry &dispGeom);
+
+  virtual void SetDirectionMatrix(const vnl_matrix<double> &direction);
+
+  virtual void CopyImageCoordinateTransform(const ImageWrapperBase *source);
+
+  /**
+    Compute the image histogram. The histogram is cached inside of the
+    object, so repeated calls to this function with the same nBins parameter
+    will not require additional computation.
+
+    Calling with default parameter (0) will use the same number of bins that
+    is currently in the histogram (i.e., return/recompute current histogram).
+    If there is no current histogram, a default histogram with 128 entries
+    will be generated.
+
+    For multi-component data, the histogram is pooled over all components.
+    */
+  const ScalarImageHistogram *GetHistogram(size_t nBins = 0);
+
 protected:
 
+  /**
+   * Default constructor.  Creates an image wrapper with a blank internal
+   * image
+   */
+  VectorImageWrapper();
+
+  /**
+   * Copy constructor.  Copies the contents of the passed-in image wrapper.
+   */
+  VectorImageWrapper(const Self &copy) : Superclass(copy) {}
+
+  virtual void UpdateImagePointer(ImageType *newImage);
+
+  /** Destructor */
+  virtual ~VectorImageWrapper();
+
+  /** Create a derived wrapper of a certain type */
+  template <class TFunctor>
+  SmartPtr<ScalarImageWrapperBase> CreateDerivedWrapper(ImageType *image);
+
+  template <class TFunctor>
+  void SetNativeMappingInDerivedWrapper(
+      ScalarImageWrapperBase *w, NativeIntensityMapping &mapping);
+
+  // Array of derived quantities
+  typedef SmartPtr<ScalarImageWrapperBase> ScalarWrapperPointer;
+  typedef std::pair<ScalarRepresentation, int> ScalarRepIndex;
+
+  typedef std::map<ScalarRepIndex, ScalarWrapperPointer> ScalarRepMap;
+  typedef typename ScalarRepMap::iterator ScalarRepIterator;
+  typedef typename ScalarRepMap::const_iterator ScalarRepConstIterator;
+  ScalarRepMap m_ScalarReps;
+
+  // For computing image statistics, we can represent the image as a one-dimensional
+  // image of size n_voxels * n_components. This image can then be fed as input to
+  // the min/max and histogram computation filters. Of course the flat image
+  // shares the buffer with the 3D image so there is no memory waste
+  typedef itk::Image<InternalPixelType, 1>                       FlatImageType;
+  SmartPtr<FlatImageType> m_FlatImage;
+
+  // Min/max filter
+  typedef itk::MinimumMaximumImageFilter<FlatImageType> MinMaxFilterType;
+  SmartPtr<MinMaxFilterType> m_MinMaxFilter;
+
+  // Histogram filter
+  typedef ThreadedHistogramImageFilter<FlatImageType> HistogramFilterType;
+  SmartPtr<HistogramFilterType> m_HistogramFilter;
+
+  // Other derived wrappers
+  typedef VectorToScalarMagnitudeFunctor<InternalPixelType,float> MagnitudeFunctor;
+  typedef VectorToScalarMaxFunctor<InternalPixelType, float> MaxFunctor;
+  typedef VectorToScalarMeanFunctor<InternalPixelType,float> MeanFunctor;
+
 };
 
 #endif // __VectorImageWrapper_h_
diff --git a/Logic/ImageWrapper/VectorImageWrapper.txx b/Logic/ImageWrapper/VectorImageWrapper.txx
deleted file mode 100644
index 3d36f7f..0000000
--- a/Logic/ImageWrapper/VectorImageWrapper.txx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*=========================================================================
-
-  Program:   Insight Segmentation & Registration Toolkit
-  Module:    $RCSfile: VectorImageWrapper.txx,v $
-  Language:  C++
-  Date:      $Date: 2007/06/06 22:27:21 $
-  Version:   $Revision: 1.1 $
-  Copyright (c) 2003 Insight Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-#ifndef __VectorImageWrapper_txx_
-#define __VectorImageWrapper_txx_
-
-#include "VectorImageWrapper.h"
-#include "itkImageRegionIterator.h"
-#include "itkImageSliceConstIteratorWithIndex.h"
-#include "itkNumericTraits.h"
-#include "itkRegionOfInterestImageFilter.h"
-#include "itkRescaleIntensityImageFilter.h"
-#include "itkIdentityTransform.h"
-#include "IRISSlicer.h"
-#include "SNAPSegmentationROISettings.h"
-#include "itkCommand.h"
-
-#include <iostream>
-
-template <class TPixel>
-typename VectorImageWrapper<TPixel>::ImagePointer
-VectorImageWrapper<TPixel>
-::DeepCopyRegion(const SNAPSegmentationROISettings &roi,
-                 itk::Command *progressCommand) const
-{
-   std::cout << "VectorImageWrapper::DeepCopyRegion" << std::endl;
-   std::cout << std::flush;
-  return NULL;
-}
-
-#endif // __VectorImageWrapper_txx_
diff --git a/Logic/ImageWrapper/VectorToScalarImageAccessor.h b/Logic/ImageWrapper/VectorToScalarImageAccessor.h
new file mode 100644
index 0000000..4bbc33e
--- /dev/null
+++ b/Logic/ImageWrapper/VectorToScalarImageAccessor.h
@@ -0,0 +1,201 @@
+#ifndef VECTORTOSCALARIMAGEACCESSOR_H
+#define VECTORTOSCALARIMAGEACCESSOR_H
+
+#include "itkDefaultVectorPixelAccessor.h"
+
+namespace itk
+{
+template <class TImage, class TAccessor> class ImageAdaptor;
+template <class TPixel, unsigned int Vdim> class VectorImage;
+}
+
+/**
+ * An accessor very similar to itk::VectorImageToImageAccessor that allows us
+ * to extract certain computed quantities from the vectors, such as magnitude
+ */
+template <class TFunctor>
+class VectorToScalarImageAccessor
+      : private itk::DefaultVectorPixelAccessor< typename TFunctor::InputPixelType >
+{
+public:
+  typedef itk::DefaultVectorPixelAccessor< typename TFunctor::InputPixelType > Superclass;
+  typedef typename TFunctor::OutputPixelType ExternalType;
+  typedef typename TFunctor::InputPixelType InternalType;
+  typedef itk::SizeValueType SizeValueType;
+  typedef itk::VariableLengthVector<ExternalType> ActualPixelType;
+  typedef unsigned int VectorLengthType;
+
+  inline void Set(ActualPixelType output, const ExternalType &input) const
+    { output.Fill(input); }
+
+  inline void Set(InternalType &output, const ExternalType &input,
+                  const SizeValueType offset) const
+    { Set( Superclass::Get(output, offset), input); }
+
+  inline ExternalType Get(const ActualPixelType &input) const
+    { return m_Functor.Get(input); }
+
+  inline ExternalType Get(const InternalType &input,
+                          const SizeValueType offset) const
+    { return Get(Superclass::Get(input, offset)); }
+
+  void SetVectorLength(VectorLengthType l)
+    {
+    m_Functor.SetVectorLength(l);
+    Superclass::SetVectorLength(l);
+    }
+
+  /**
+   * Set the linear mapping from the vector image internal values to the
+   * native data type. The mapping is native = internal * scale + shift
+   */
+  void SetSourceNativeMapping(double scale, double shift)
+  {
+    m_Functor.SetSourceNativeMapping(scale, shift);
+  }
+
+protected:
+  TFunctor m_Functor;
+};
+
+/**
+ * This is the parent class for the functors below, encompassing shared
+ * functionality
+ */
+class AbstractVectorToDerivedQuantityFunctor
+{
+public:
+
+  AbstractVectorToDerivedQuantityFunctor()
+  {
+    m_Length = 1;
+    m_Scale = 1;
+    m_Shift = 0;
+    this->ParametersUpdated();
+  }
+
+  virtual ~AbstractVectorToDerivedQuantityFunctor() {}
+
+  virtual void SetSourceNativeMapping(double scale, double shift)
+  {
+    m_Shift = shift;
+    m_Scale = scale;
+    this->ParametersUpdated();
+  }
+
+  virtual void SetVectorLength(unsigned int l)
+  {
+    m_Length = l;
+    this->ParametersUpdated();
+  }
+
+  virtual void ParametersUpdated() {};
+
+protected:
+
+  // Mapping from internal to native in the wrapped image
+  double m_Shift, m_Scale;
+  unsigned int m_Length;
+};
+
+
+
+/**
+ * This class returns the magnitude of the vector. Since the vector is stored
+ * internally as a shifted and scaled version of the native intensity value,
+ * to compute magnitude, we first need to map the input values back to the
+ * native value, take magnitude, and map back to the stored integral value
+ *
+ * TODO: magnitude adapters should be treated as float images, not short,
+ * which will allow us to avoid this mess.
+ */
+template <class TInputPixel, class TOutputPixel>
+class VectorToScalarMagnitudeFunctor : public AbstractVectorToDerivedQuantityFunctor
+{
+public:
+  typedef TInputPixel InputPixelType;
+  typedef TOutputPixel OutputPixelType;
+  OutputPixelType Get(const itk::VariableLengthVector<InputPixelType> &input) const
+  {
+    double sumT2 = 0.0, sumT = 0.0;
+    for(int i = 0; i < input.Size(); i++)
+      {
+      double t = input[i];
+      sumT2 += t * t;
+      sumT += t;
+      }
+
+    double norm_raw_out =
+        sqrt(m_CoeffT2 * sumT2 + m_CoeffT1 * sumT + m_CoeffT0);
+
+    return static_cast<OutputPixelType>(norm_raw_out);
+  }
+
+  virtual void ParametersUpdated()
+  {
+    m_CoeffT2 = (this->m_Scale * this->m_Scale);
+    m_CoeffT1 = (2 * this->m_Scale * this->m_Shift);
+    m_CoeffT0 = (this->m_Shift * this->m_Shift) * this->m_Length;
+  }
+
+protected:
+
+  // Used internally to compute norm with fewest operations
+  double m_CoeffT2, m_CoeffT1, m_CoeffT0;
+};
+
+template <class TInputPixel, class TOutputPixel>
+class VectorToScalarMaxFunctor : public AbstractVectorToDerivedQuantityFunctor
+{
+public:
+  typedef TInputPixel InputPixelType;
+  typedef TOutputPixel OutputPixelType;
+  OutputPixelType Get(const itk::VariableLengthVector<InputPixelType> &input) const
+  {
+    InputPixelType mymax = input[0];
+    for(int i = 1; i < input.Size(); i++)
+      mymax = std::max(input[i], mymax);
+    return static_cast<OutputPixelType>(mymax * this->m_Scale + this->m_Shift);
+  }
+};
+
+template <class TInputPixel, class TOutputPixel>
+class VectorToScalarMeanFunctor : public AbstractVectorToDerivedQuantityFunctor
+{
+public:
+  typedef TInputPixel InputPixelType;
+  typedef TOutputPixel OutputPixelType;
+
+  OutputPixelType Get(const itk::VariableLengthVector<InputPixelType> &input) const
+  {
+    double mean = 0.0;
+    for(int i = 0; i < input.Size(); i++)
+      mean += input[i];
+    mean /= input.Size();
+    return static_cast<OutputPixelType>(mean * this->m_Scale + this->m_Shift);
+  }
+};
+
+
+// Typedefs for GreyType
+typedef VectorToScalarMagnitudeFunctor<GreyType, float> GreyVectorToScalarMagnitudeFunctor;
+typedef VectorToScalarImageAccessor<GreyVectorToScalarMagnitudeFunctor>
+  GreyVectorMagnitudeImageAccessor;
+typedef itk::ImageAdaptor< itk::VectorImage<GreyType, 3>, GreyVectorMagnitudeImageAccessor>
+  GreyVectorMagnitudeImageAdaptor;
+
+typedef VectorToScalarMaxFunctor<GreyType, float> GreyVectorToScalarMaxFunctor;
+typedef VectorToScalarImageAccessor<GreyVectorToScalarMaxFunctor>
+  GreyVectorMaxImageAccessor;
+typedef itk::ImageAdaptor< itk::VectorImage<GreyType, 3>, GreyVectorMaxImageAccessor>
+  GreyVectorMaxImageAdaptor;
+
+typedef VectorToScalarMeanFunctor<GreyType,float> GreyVectorToScalarMeanFunctor;
+typedef VectorToScalarImageAccessor<GreyVectorToScalarMeanFunctor>
+  GreyVectorMeanImageAccessor;
+typedef itk::ImageAdaptor< itk::VectorImage<GreyType, 3>, GreyVectorMeanImageAccessor>
+  GreyVectorMeanImageAdaptor;
+
+
+
+#endif // VECTORTOSCALARIMAGEACCESSOR_H
diff --git a/Logic/LevelSet/SNAPAdvectionFieldImageFilter.h b/Logic/LevelSet/SNAPAdvectionFieldImageFilter.h
index f808206..a3315f6 100644
--- a/Logic/LevelSet/SNAPAdvectionFieldImageFilter.h
+++ b/Logic/LevelSet/SNAPAdvectionFieldImageFilter.h
@@ -36,7 +36,7 @@
 #define __SNAPAdvectionFieldImageFilter_h_
 
 #include "itkCovariantVector.h"
-#include "itkOrientedImage.h"
+#include "itkImage.h"
 #include "itkImageToImageFilter.h"
 
 /**
@@ -48,10 +48,8 @@ template <class TInputImage, class TOutputValueType=float>
 class SNAPAdvectionFieldImageFilter: 
   public itk::ImageToImageFilter<
     TInputImage,
-    itk::Image<
-      itk::CovariantVector<TOutputValueType,
-        ::itk::GetImageDimension<TInputImage>::ImageDimension>,
-      ::itk::GetImageDimension<TInputImage>::ImageDimension> >
+    itk::Image<itk::CovariantVector<TOutputValueType, TInputImage::ImageDimension>,
+      TInputImage::ImageDimension> >
 {
 public:
   
diff --git a/Logic/LevelSet/SNAPAdvectionFieldImageFilter.txx b/Logic/LevelSet/SNAPAdvectionFieldImageFilter.txx
index f691522..bd8eef8 100644
--- a/Logic/LevelSet/SNAPAdvectionFieldImageFilter.txx
+++ b/Logic/LevelSet/SNAPAdvectionFieldImageFilter.txx
@@ -85,7 +85,7 @@ SNAPAdvectionFieldImageFilter<TInputImage,TOutputValueType>
 
   // graft the mini-pipeline output back onto this filter's output.
   // this is needed to get the appropriate regions passed back.
-  GraftOutput( fltPipeEnd->GetOutput() );
+  this->GraftOutput( fltPipeEnd->GetOutput() );
 }
 
 template<class TInputImage, class TOutputValueType>
diff --git a/Logic/LevelSet/SNAPLevelSetDriver.cxx b/Logic/LevelSet/SNAPLevelSetDriver.cxx
deleted file mode 100644
index 2eff1cb..0000000
--- a/Logic/LevelSet/SNAPLevelSetDriver.cxx
+++ /dev/null
@@ -1,351 +0,0 @@
-/*=========================================================================
-
-  Program:   Insight Segmentation & Registration Toolkit
-  Module:    $RCSfile: SNAPLevelSetDriver.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/06/28 18:45:08 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2003 Insight Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-#include "SNAPLevelSetDriver.h"
-#include "IRISVectorTypesToITKConversion.h"
-
-#include "itkCommand.h"
-#include "itkNarrowBandLevelSetImageFilter.h"
-#include "itkParallelSparseFieldLevelSetImageFilter.h"
-#include "itkDenseFiniteDifferenceImageFilter.h"
-#include "LevelSetExtensionFilter.h"
-
-// Disable some windows debug length messages
-#if defined(_MSC_VER)
-#pragma warning ( disable : 4786 )
-#pragma warning ( disable : 4503 )
-#endif
-
-
-template<unsigned int VDimension>
-SNAPLevelSetDriver<VDimension>
-::SNAPLevelSetDriver(FloatImageType *init, FloatImageType *speed,
-                     const SnakeParameters &sparms,
-                     VectorImageType *externalAdvection)
-{
-  // Create the level set function
-  m_LevelSetFunction = LevelSetFunctionType::New();
-  // m_LevelSetFunction = FastSNAPLevelSetFunction::New();
-
-  // Pass the speed image to the function
-  m_LevelSetFunction->SetSpeedImage(speed);  
-
-  // Set the external advection if any
-  if(externalAdvection)
-    m_LevelSetFunction->SetAdvectionField(externalAdvection);
-
-  // Remember the input and output images for later initialization
-  m_InitializationImage = init;
-
-  // Pass the parameters to the level set function
-  AssignParametersToPhi(sparms,true);
-
-  // Create the filter
-  DoCreateLevelSetFilter();
-}
-
-template<unsigned int VDimension>
-void 
-SNAPLevelSetDriver<VDimension>
-::AssignParametersToPhi(const SnakeParameters &p, bool irisNotUsed(firstTime))
-{
-  // Set up the level set function
-
-  // The sign of the advection term is flipped in our equation
-  m_LevelSetFunction->SetAdvectionWeight( - p.GetAdvectionWeight());
-  m_LevelSetFunction->SetAdvectionSpeedExponent(p.GetAdvectionSpeedExponent());
-
-  // The curvature exponent for traditional/legacy reasons has a +1 value.
-  m_LevelSetFunction->SetCurvatureSpeedExponent(p.GetCurvatureSpeedExponent()+1);  
-  m_LevelSetFunction->SetCurvatureWeight(p.GetCurvatureWeight());
-  
-  m_LevelSetFunction->SetPropagationWeight(p.GetPropagationWeight());
-  m_LevelSetFunction->SetPropagationSpeedExponent(p.GetPropagationSpeedExponent());  
-  m_LevelSetFunction->SetLaplacianSmoothingWeight(p.GetLaplacianWeight());
-  m_LevelSetFunction->SetLaplacianSmoothingSpeedExponent(p.GetLaplacianSpeedExponent());  
-  
-  // We only need to recompute the internal images if the exponents to those
-  // images have changed
-  m_LevelSetFunction->CalculateInternalImages();
-  
-  // Call the initialize method
-  m_LevelSetFunction->Initialize(to_itkSize(Vector3i(1)));
-
-  // Set the time step
-  m_LevelSetFunction->SetTimeStepFactor(
-    p.GetAutomaticTimeStep() ? 1.0 : p.GetTimeStepFactor());
-
-  // Remember the parameters
-  m_Parameters = p;
-}
-
-template<unsigned int VDimension>
-void
-SNAPLevelSetDriver<VDimension>
-::DoCreateLevelSetFilter()
-{
-  // In this method we have the flexibility to create a level set filter
-  // of any ITK solver type.  This way, we can plug in different solvers:
-  // NarrowBand, ParallelSparseField, even Dense.  
-  if(m_Parameters.GetSolver() == SnakeParameters::PARALLEL_SPARSE_FIELD_SOLVER)
-    {
-    // Define an extension to the appropriate filter class
-    typedef ParallelSparseFieldLevelSetImageFilter<
-      FloatImageType,FloatImageType> LevelSetFilterType;
-    typedef LevelSetExtensionFilter<LevelSetFilterType> ExtensionFilterType;
-      
-    // Create a new extended filter
-    ExtensionFilterType::Pointer filter = ExtensionFilterType::New();
-
-    // Cast this specific filter down to the lowest common denominator that is
-    // a filter
-    m_LevelSetFilter = filter.GetPointer();
-
-    // Cast the specific filter to a generic interface, so we can call the 
-    // extended operations without knowing exactly what the filter is (this 
-    // is the beauty of polymorphism!)
-    m_ExtensionView = filter.GetPointer();
-    
-    // Perform the special configuration tasks on the filter
-    filter->SetInput(m_InitializationImage);
-    filter->SetNumberOfLayers(3);
-    filter->SetIsoSurfaceValue(0.0f);
-    filter->SetDifferenceFunction(m_LevelSetFunction);
-    }
-  else if(m_Parameters.GetSolver() == SnakeParameters::NARROW_BAND_SOLVER)
-    {
-    // Define an extension to the appropriate filter class
-    typedef NarrowBandLevelSetImageFilter<
-      FloatImageType,FloatImageType> LevelSetFilterType;
-    typedef LevelSetExtensionFilter<LevelSetFilterType> ExtensionFilterType;
-    
-    // Create a new extended filter
-    ExtensionFilterType::Pointer filter = ExtensionFilterType::New();
-
-    // Cast this specific filter down to the lowest common denominator that is
-    // a filter
-    m_LevelSetFilter = filter.GetPointer();
-
-    // Cast the specific filter to a generic interface, so we can call the 
-    // extended operations without knowing exactly what the filter is (this 
-    // is the beauty of polymorphism!)
-    m_ExtensionView = filter.GetPointer();
-    
-    // Perform the special configuration tasks on the filter
-    filter->SetSegmentationFunction(m_LevelSetFunction);
-    filter->SetInput(m_InitializationImage);
-    filter->SetNarrowBandTotalRadius(5);
-    filter->SetNarrowBandInnerRadius(3);
-    filter->SetFeatureImage(m_LevelSetFunction->GetSpeedImage());  
-    }
-  else if(m_Parameters.GetSolver() == SnakeParameters::DENSE_SOLVER)
-    {
-    // Define an extension to the appropriate filter class
-    typedef DenseFiniteDifferenceImageFilter<
-      FloatImageType,FloatImageType> LevelSetFilterType;
-    typedef LevelSetExtensionFilter<LevelSetFilterType> ExtensionFilterType;
-    
-    // Create a new extended filter
-    ExtensionFilterType::Pointer filter = ExtensionFilterType::New();
-
-    // Cast this specific filter down to the lowest common denominator that is
-    // a filter
-    m_LevelSetFilter = filter.GetPointer();
-
-    // Cast the specific filter to a generic interface, so we can call the 
-    // extended operations without knowing exactly what the filter is (this 
-    // is the beauty of polymorphism!)
-    m_ExtensionView = filter.GetPointer();
-    
-    // Perform the special configuration tasks on the filter
-    filter->SetInput(m_InitializationImage);
-    filter->SetDifferenceFunction(m_LevelSetFunction);
-    }
-}
-
-template<unsigned int VDimension>
-void
-SNAPLevelSetDriver<VDimension>
-::RequestRestart()
-{ 
-  // Makes no sense to call this if not in update cycle
-  assert(this->IsInUpdateLoop());
-
-  // Request a stop in the update
-  m_ExtensionView->RequestStop();
-
-  // Tell the method that called Update that it needs to call DoRestart()
-  m_CommandAfterUpdate = SelfCommandType::New();
-  m_CommandAfterUpdate->SetCallbackFunction(this,&SNAPLevelSetDriver::DoRestart);
-}
-
-template<unsigned int VDimension>
-void
-SNAPLevelSetDriver<VDimension>
-::DoRestart()
-{
-  // To be on the safe side, just create a new filter (alternative is commented
-  // out below, but seems to be unstable)
-  DoCreateLevelSetFilter();
-
-  // Update the image currently in the filter
-  // m_LevelSetFilter->SetInput(m_InitializationImage);
-
-  // Reset the filter, so the next time it is Updated, it will run again, even
-  // if the input image has not changed
-  // m_LevelSetFilter->Modified();
-}
-
-template<unsigned int VDimension>
-void 
-SNAPLevelSetDriver<VDimension>
-::BeginUpdate(Command *pauseCallback)
-{
-  // This call may not nest
-  assert(!this->IsInUpdateLoop());
-
-  // This call loops until the filter returns from an update with no consequent
-  // request specified
-  while(true)
-    {
-    // Tell the filter how many iterations to perform
-    m_ExtensionView->SetIterationsUntilPause(0);
-
-    // Tell the filter to call back to the command passed in here.  If the 
-    // command is NULL, the filter will return after executing the iterations
-    m_ExtensionView->SetPauseCommand(pauseCallback);
-
-    // Clear the post-update command
-    m_CommandAfterUpdate = NULL;
-    
-    // Run the filter (at this point, we're stuck in this method, and rely on
-    // the callback function to handle user interaction)
-    m_LevelSetFilter->UpdateLargestPossibleRegion();
-
-    // The control returns here after the filter finishes updating.  
-    if(m_CommandAfterUpdate)
-      {          
-      // The callback may have set the post-update command pointer, asking us to 
-      // execute another action before returning control to the parent
-      m_CommandAfterUpdate->Execute(m_LevelSetFilter,AnyEvent());
-      }      
-    else
-      {
-      // There was no subsequent command requested, hence there was no  
-      // reason for aborting Update() other that the user wants us to quit and
-      // return control
-      break;
-      }      
-    }
-}
-
-template<unsigned int VDimension>
-bool
-SNAPLevelSetDriver<VDimension>
-::IsInUpdateLoop()
-{
-  return ((m_ExtensionView != NULL) && m_ExtensionView->IsUpdating());
-}
-
-template<unsigned int VDimension>
-void 
-SNAPLevelSetDriver<VDimension>
-::RequestEndUpdate()
-{
-  // Makes no sense to call this if not in update cycle
-  assert(this->IsInUpdateLoop());
-
-  // Tell the filter it has to stop
-  m_ExtensionView->RequestStop();
-}
-
-
-template<unsigned int VDimension>
-void 
-SNAPLevelSetDriver<VDimension>
-::RequestIterations(int nIterations)
-{
-  // This method should only be called once the filter is updating, from the
-  // pause callback
-  assert(this->IsInUpdateLoop());
-    
-  // Since the filter is already running, so Run is being called from the 
-  // pause callback.  In this case, we just tell the filter to run for more 
-  // iterations once the pause callback returns
-  m_ExtensionView->SetIterationsUntilPause(nIterations);
-}
-
-template<unsigned int VDimension>
-typename SNAPLevelSetDriver<VDimension>::FloatImageType * 
-SNAPLevelSetDriver<VDimension>
-::GetCurrentState()
-{
-  // Fix the spacing of the level set filter's output
-  m_LevelSetFilter->GetOutput()->SetSpacing(m_InitializationImage->GetSpacing());
-
-  // Return the filter's output
-  return m_LevelSetFilter->GetOutput();
-}
-
-template<unsigned int VDimension>
-void 
-SNAPLevelSetDriver<VDimension>
-::CleanUp()
-{
-  // This method should not be called within the pause callback, or else
-  // we would trash memory
-  assert(!this->IsInUpdateLoop());
-
-  // Basically, the filter is finished, and we can finally return 
-  // from running the filter.  Let's clear the level set and the 
-  // function to free memory
-  m_LevelSetFilter = NULL;
-  m_LevelSetFunction = NULL;
-}
-
-template<unsigned int VDimension>
-void
-SNAPLevelSetDriver<VDimension>
-::SetSnakeParameters(const SnakeParameters &sparms)
-{
-  // Parameter setting can be destructive or passive.  If the solver has 
-  // has changed, then it's destructive, otherwise it's passive
-  bool destructive = sparms.GetSolver() != m_Parameters.GetSolver();
-
-  // First of all, pass the parameters to the phi function, which may or
-  // may not cause it to recompute it's images
-  AssignParametersToPhi(sparms,false);
-
-  if(destructive)
-    {
-    // We need to reinitialize the internal filter.  However, if the filter
-    // is already running, all we can do is schedule that update
-    if(this->IsInUpdateLoop())
-      {
-      // Tell the filter to stop when it regains control from the pause callback
-      m_ExtensionView->RequestStop();
-
-      // Schedule a subsequent call to create a new filter
-      m_CommandAfterUpdate = SelfCommandType::New();
-      m_CommandAfterUpdate->SetCallbackFunction(
-        this,&SNAPLevelSetDriver::DoCreateLevelSetFilter);
-      }
-    else
-      {
-      // We are not in an update loop, but between updates, so just recreate the 
-      // level set filter
-      DoCreateLevelSetFilter();
-      }
-    }
-}
diff --git a/Logic/LevelSet/SNAPLevelSetDriver.h b/Logic/LevelSet/SNAPLevelSetDriver.h
index 49c6e33..1a5c83a 100644
--- a/Logic/LevelSet/SNAPLevelSetDriver.h
+++ b/Logic/LevelSet/SNAPLevelSetDriver.h
@@ -51,6 +51,27 @@ namespace itk {
   class Command;
 };
 
+/** Accessor class to cast speed image to float or double */
+/*
+template <class TExternalType>
+class SpeedImageToFloatAccessor
+{
+public:
+  typedef short InternalType;
+  typedef TExternalType ExternalType;
+
+  static inline void Set(InternalType &output, const ExternalType &input)
+  {
+    output = static_cast<InternalType>(input * 0x7fff);
+  }
+
+  static inline ExternalType Get(const InternalType &input)
+  {
+    return static_cast<ExternalType>(input * (1.0 / 0x7fff));
+  }
+};
+*/
+
 /** 
  * \class SNAPLevelSetDriverBase
  * \brief An abstract interface that allows code to be written independently of
@@ -89,20 +110,24 @@ class SNAPLevelSetDriver : public SNAPLevelSetDriverBase
 {
 public:
 
-  typedef SNAPLevelSetDriver Self;
+  typedef SNAPLevelSetDriver                                           Self;
 
   // A callback type
-  typedef itk::SmartPointer<itk::Command> CommandPointer;
-  typedef itk::SimpleMemberCommand<Self> SelfCommandType;
-  typedef itk::SmartPointer<SelfCommandType> SelfCommandPointer;
+  typedef itk::SmartPointer<itk::Command>                    CommandPointer;
+  typedef itk::SimpleMemberCommand<Self>                    SelfCommandType;
+  typedef itk::SmartPointer<SelfCommandType>             SelfCommandPointer;
+
+  /** Speed image type: short, to conserve memory */
+  typedef itk::Image<short, VDimension>              ShortImageType;
 
   /** Floating point image type used internally */
-  typedef itk::OrientedImage<float, VDimension> FloatImageType;
-  typedef typename itk::SmartPointer<FloatImageType> FloatImagePointer;
+  typedef itk::Image<float, VDimension>              FloatImageType;
+  typedef typename itk::SmartPointer<FloatImageType>      FloatImagePointer;
 
   /** Type definition for the level set function */
-  typedef SNAPLevelSetFunction<FloatImageType> LevelSetFunctionType;
-  typedef typename LevelSetFunctionType::VectorImageType VectorImageType;
+  typedef SNAPLevelSetFunction<ShortImageType, FloatImageType>
+                                                       LevelSetFunctionType;
+  typedef typename LevelSetFunctionType::VectorImageType    VectorImageType;
 
   /** Initialize the level set driver.  Note that the type of snake (in/out
    * or edge) is determined entirely by the speed image and by the values
@@ -111,7 +136,7 @@ public:
    * advection field, that can be used instead of the default advection
    * field that is based on the image gradient */
   SNAPLevelSetDriver(FloatImageType *initialLevelSet,
-                     FloatImageType *speed,
+                     ShortImageType *speed,
                      const SnakeParameters &parms,
                      VectorImageType *externalAdvection = NULL);
 
@@ -124,6 +149,9 @@ public:
   /** Run the filter */
   void Run(unsigned int nIterations);
 
+  /** Check for convergence */
+  bool IsEvolutionConverged();
+
   /** Restart the snake */
   void Restart();
 
@@ -159,6 +187,9 @@ private:
   /** An initialization image */
   FloatImagePointer m_InitializationImage;
 
+  /** Speed image adaptor */
+  typename ShortImageType::Pointer m_SpeedAdaptor;
+
   /** Last accepted snake parameters */
   SnakeParameters m_Parameters;
 
diff --git a/Logic/LevelSet/SNAPLevelSetDriver.txx b/Logic/LevelSet/SNAPLevelSetDriver.txx
index 1b3062f..e84d591 100644
--- a/Logic/LevelSet/SNAPLevelSetDriver.txx
+++ b/Logic/LevelSet/SNAPLevelSetDriver.txx
@@ -49,11 +49,7 @@
 #include "itkDenseFiniteDifferenceImageFilter.h"
 #include "LevelSetExtensionFilter.h"
 
-#if defined(USE_ITK36_ITK38_SPARSEFIELD_BUGFIX)
-#include "itkParallelSparseFieldLevelSetImageFilterBugFix.h"
-#else 
-#include "itkSparseFieldLevelSetImageFilter.h"
-#endif
+#include "itkParallelSparseFieldLevelSetImageFilter.h"
 
 // Disable some windows debug length messages
 #if defined(_MSC_VER)
@@ -61,6 +57,45 @@
 #pragma warning ( disable : 4503 )
 #endif
 
+/**
+ * THIS IS A WORKAROUND FOR A BUG THAT I FOUND IN THE PARALLEL SPARSE LEVEL SET
+ * FILTER. For small seeds, the way the filter splits up the image into regions
+ * for different threads, some threads end up with empty regions (no nodes). The
+ * function that computes the timestep from the per-region timesteps then sets
+ * the timestep to 0, and the filter stops. The work-around changes the step size
+ * for empty regions to 1 and fixes the problem.
+ */
+template< class TInputImage, class TOutputImage >
+class ParallelSparseFieldLevelSetImageFilterBugFix
+    : public itk::ParallelSparseFieldLevelSetImageFilter< TInputImage, TOutputImage >
+{
+public:
+
+  typedef ParallelSparseFieldLevelSetImageFilterBugFix                             Self;
+  typedef itk::ParallelSparseFieldLevelSetImageFilter< TInputImage, TOutputImage > Superclass;
+  typedef itk::SmartPointer< Self >                                                Pointer;
+  typedef itk::SmartPointer< const Self >                                          ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self)
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(ParallelSparseFieldLevelSetImageFilterBugFix,
+               itk::ParallelSparseFieldLevelSetImageFilter)
+
+  virtual typename Superclass::TimeStepType ThreadedCalculateChange(itk::ThreadIdType ThreadId)
+  {
+    typename Superclass::TimeStepType ts = Superclass::ThreadedCalculateChange(ThreadId);
+
+    if(ThreadId > 0 && this->m_Data[ThreadId].m_Count == 0)
+      return 1.0;
+    else
+      return ts;
+  }
+
+  itk::SimpleFastMutexLock locky;
+};
+
 
 // Create an inverting functor
 class InvertFunctor {
@@ -72,7 +107,7 @@ public:
 
 template<unsigned int VDimension>
 SNAPLevelSetDriver<VDimension>
-::SNAPLevelSetDriver(FloatImageType *init, FloatImageType *speed,
+::SNAPLevelSetDriver(FloatImageType *init, ShortImageType *speed,
                      const SnakeParameters &sparms,
                      VectorImageType *externalAdvection)
 {
@@ -80,7 +115,10 @@ SNAPLevelSetDriver<VDimension>
   m_LevelSetFunction = LevelSetFunctionType::New();
 
   // Pass the speed image to the function
-  m_LevelSetFunction->SetSpeedImage(speed);  
+  m_LevelSetFunction->SetSpeedImage(speed);
+
+  // Scale the speed function to range -1 to 1
+  m_LevelSetFunction->SetSpeedScaleFactor(1.0 / 0x7fff);
 
   // Set the external advection if any
   if(externalAdvection)
@@ -104,7 +142,7 @@ SNAPLevelSetDriver<VDimension>
   // Set up the level set function
 
   // The sign of the advection term is flipped in our equation
-  m_LevelSetFunction->SetAdvectionWeight( - p.GetAdvectionWeight());
+  m_LevelSetFunction->SetAdvectionWeight(- p.GetAdvectionWeight());
   m_LevelSetFunction->SetAdvectionSpeedExponent(p.GetAdvectionSpeedExponent());
 
   // The curvature exponent for traditional/legacy reasons has a +1 value.
@@ -144,13 +182,8 @@ SNAPLevelSetDriver<VDimension>
   if(m_Parameters.GetSolver() == SnakeParameters::PARALLEL_SPARSE_FIELD_SOLVER)
     {
     // Define an extension to the appropriate filter class
-#if defined(USE_ITK36_ITK38_SPARSEFIELD_BUGFIX)
-    typedef itk::ParallelSparseFieldLevelSetImageFilterBugFix<
-      FloatImageType, FloatImageType> LevelSetFilterType;
-#else
-    typedef itk::SparseFieldLevelSetImageFilter<
-      FloatImageType, FloatImageType> LevelSetFilterType;
-#endif
+    typedef ParallelSparseFieldLevelSetImageFilterBugFix<
+        FloatImageType, FloatImageType> LevelSetFilterType;
 
     typedef typename LevelSetFilterType::Pointer LevelSetFilterPointer;
     LevelSetFilterPointer filter = LevelSetFilterType::New();
@@ -164,13 +197,14 @@ SNAPLevelSetDriver<VDimension>
     filter->SetNumberOfLayers(3);
     filter->SetIsoSurfaceValue(0.0f);
     filter->SetDifferenceFunction(m_LevelSetFunction);
+    filter->InPlaceOn();
     }
-
+/*
   else if(m_Parameters.GetSolver() == SnakeParameters::NARROW_BAND_SOLVER)
     {
     // Define an extension to the appropriate filter class
     typedef itk::NarrowBandLevelSetImageFilter<
-      FloatImageType,FloatImageType,float,FloatImageType> LevelSetFilterType;
+      FloatImageType,SpeedAdaptorType,float,FloatImageType> LevelSetFilterType;
     typedef LevelSetExtensionFilter<LevelSetFilterType> ExtensionFilter;
     typename ExtensionFilter::Pointer filter = ExtensionFilter::New();
 
@@ -185,7 +219,7 @@ SNAPLevelSetDriver<VDimension>
     filter->SetNarrowBandInnerRadius(3);
     filter->SetFeatureImage(m_LevelSetFunction->GetSpeedImage());  
     }
-
+*/
   else if(m_Parameters.GetSolver() == SnakeParameters::DENSE_SOLVER)
     {
     // Define an extension to the appropriate filter class
@@ -201,6 +235,7 @@ SNAPLevelSetDriver<VDimension>
     // Perform the special configuration tasks on the filter
     filter->SetInput(m_InitializationImage);
     filter->SetDifferenceFunction(m_LevelSetFunction);
+    filter->InPlaceOn();
     }
 
   else
@@ -251,6 +286,20 @@ SNAPLevelSetDriver<VDimension>
 }
 
 template<unsigned int VDimension>
+bool
+SNAPLevelSetDriver<VDimension>
+::IsEvolutionConverged()
+{
+  if(m_LevelSetFilter->GetElapsedIterations() == 0)
+    return false;
+
+  // For now, require absolute convergence
+  std::cout << m_LevelSetFilter->GetRMSChange() << std::endl;
+  return (m_LevelSetFilter->GetRMSChange() == 0.0);
+}
+
+
+template<unsigned int VDimension>
 typename SNAPLevelSetDriver<VDimension>::FloatImageType * 
 SNAPLevelSetDriver<VDimension>
 ::GetCurrentState()
diff --git a/Logic/LevelSet/SNAPLevelSetFunction.h b/Logic/LevelSet/SNAPLevelSetFunction.h
index 174bc67..cbdaebb 100644
--- a/Logic/LevelSet/SNAPLevelSetFunction.h
+++ b/Logic/LevelSet/SNAPLevelSetFunction.h
@@ -35,12 +35,16 @@
 #ifndef __SNAPLevelSetFunction_h_
 #define __SNAPLevelSetFunction_h_
 
+#if ITK_VERSION_MAJOR >= 4
+#define ITK_TYPENAME typename
+#endif
+
 //#include "itkLevelSetFunction.h"
 #include "itkSegmentationLevelSetFunction.h"
 #include "itkLinearInterpolateImageFunction.h"
 #include "itkVectorLinearInterpolateImageFunction.h"
 #include "itkVectorCastImageFilter.h"
-// #include "itkGradientImageFilter.h"
+#include "ThreadSpecificData.h"
 
 #include "SNAPAdvectionFieldImageFilter.h"
 
@@ -83,52 +87,64 @@
   SetXXXWeight() and SetXXXSpeedExponent() methods. Then  pass in a speed image 
   using SetSpeedImage() and then compute the internal images by 
   calling CalculateInternalImages().  
+
+  PY 2012: The function has been modified to cache the speed values, so that
+  separate calls to GetXXXSpeed do not result in unnecessary interpolations.
+  This takes advantage of the ThreadSpecificData object, which acts like a
+  class member that is thread-specific. A better solution still would be to
+  change the behaviour of ComputeUpdate in the LevelSetFunction to query all
+  of the speed values at once from the child class. But that requires making
+  a copy of the large chunk of the ITK API, which causes maintenance issues.
  */
-template <class TImageType>
+template <class TSpeedImageType, class TImageType>
 class ITK_EXPORT SNAPLevelSetFunction
-  : public itk::SegmentationLevelSetFunction<TImageType>
+  : public itk::LevelSetFunction<TImageType>
 {
 public:
   /** Standard class typedefs. */
   typedef SNAPLevelSetFunction Self;
-  typedef itk::SegmentationLevelSetFunction<TImageType> Superclass;
+  typedef itk::LevelSetFunction<TImageType> Superclass;
   typedef itk::SmartPointer<Self> Pointer;
   typedef itk::SmartPointer<const Self> ConstPointer;
                                                                                 
   /** Method for creation through the object factory. */
-  itkNewMacro(Self);
+  itkNewMacro(Self)
                                                                                 
   /** Run-time type information (and related methods) */
-  itkTypeMacro( SNAPLevelSetFunction, itk::LevelSetFunction );
-                                                                                
-                                                                                
+  itkTypeMacro( SNAPLevelSetFunction, itk::LevelSetFunction )
+
   /** Extract some parameters from the superclass. */
   itkStaticConstMacro(ImageDimension, unsigned int,
                       Superclass::ImageDimension);
 
   /** Extract some parameters from the superclass. */
-  typedef typename Superclass::ImageType ImageType;
-  typedef typename ImageType::Pointer ImagePointer;
-  typedef typename Superclass::NeighborhoodType NeighborhoodType;
-  typedef typename Superclass::ScalarValueType ScalarValueType;
-  typedef typename Superclass::RadiusType RadiusType;
-  typedef typename Superclass::FloatOffsetType FloatOffsetType;
+  typedef typename Superclass::ImageType                       ImageType;
+  typedef typename ImageType::Pointer                       ImagePointer;
+
+  typedef TSpeedImageType SpeedImageType;
+  typedef typename SpeedImageType::Pointer             SpeedImagePointer;
+
+  typedef typename Superclass::NeighborhoodType         NeighborhoodType;
+  typedef typename Superclass::ScalarValueType           ScalarValueType;
+  typedef typename Superclass::RadiusType                     RadiusType;
+  typedef typename Superclass::FloatOffsetType           FloatOffsetType;
   
-  typedef typename Superclass::VectorType VectorType;
-  typedef itk::Image<VectorType, ImageDimension> VectorImageType;
-  typedef typename VectorImageType::Pointer VectorImagePointer;
+  typedef typename Superclass::PixelType                       PixelType;
+  typedef typename Superclass::VectorType                     VectorType;
+  typedef itk::Image<VectorType, ImageDimension>         VectorImageType;
+  typedef typename VectorImageType::Pointer           VectorImagePointer;
 
-  typedef typename Superclass::TimeStepType TimeStepType;
-  typedef typename Superclass::GlobalDataStruct GlobalDataStruct;
+  typedef typename Superclass::TimeStepType                 TimeStepType;
+  typedef typename Superclass::GlobalDataStruct         GlobalDataStruct;
 
   /** Interpolators used to access the speed images */
   typedef itk::LinearInterpolateImageFunction<
-    ImageType> ImageInterpolatorType;
+    SpeedImageType>                           SpeedImageInterpolatorType;
   typedef itk::VectorLinearInterpolateImageFunction<
-    VectorImageType,float> VectorInterpolatorType;
+    VectorImageType,float>                        VectorInterpolatorType;
 
   typedef typename ImageType::IndexType IndexType;
-  typedef typename ImageInterpolatorType::ContinuousIndexType 
+  typedef typename SpeedImageInterpolatorType::ContinuousIndexType
     ContinuousIndexType;
 
   
@@ -136,13 +152,20 @@ public:
       computation of the variuous internal speed images is
       based.  The function g() should be near zero at edges
       of structures in the image and near one at flat regions */
-  virtual void SetSpeedImage(ImageType *pointer);
+  virtual void SetSpeedImage(SpeedImageType *pointer);
       
   /** Get the speed image g() */
-  virtual ImageType *GetSpeedImage()
-    {
-    return m_SpeedImage;
-    }
+  virtual SpeedImageType *GetSpeedImage() const
+    { return m_SpeedImage; }
+
+  /** Set the scaling for the speed image. In ITK-SNAP 3.0, speed images
+    are of short type, with the range between -0x7fff and 0x7fff. So we
+    need to scale them to the range -1 to 1. */
+  void SetSpeedScaleFactor(ScalarValueType value)
+    { m_SpeedScaleFactor = value; }
+
+  ScalarValueType GetSpeedScaleFactor() const
+    { return m_SpeedScaleFactor; }
 
   /** Set the external advection image (optional). This is only 
    * needed if your advection image is not the gradient of the
@@ -155,24 +178,54 @@ public:
 
   /** Compute speed and advection images from feature image. */
   virtual void CalculateInternalImages();
-                                                                                
+
+  /**
+    My implementation of ComputeUpdate. This will calculate the speed
+    image value just once, instead of having to interpolate it for
+    every type of calculation
+    */
+  virtual PixelType ComputeUpdate(const NeighborhoodType &neighborhood,
+                                  void *globalData,
+                                  const FloatOffsetType &);
+
+  // Inline function shared by the three XXXSpeed() functions
+  inline ScalarValueType GetSpeedWithExponent(
+      int exponent,
+      const NeighborhoodType &neighbourhood,
+      const FloatOffsetType &offset,
+      GlobalDataStruct * = 0 ) const;
+
   /** Local multiplier for the curvature term */
   virtual ScalarValueType CurvatureSpeed(
     const NeighborhoodType &neighbourhood,
     const FloatOffsetType &offset, 
-    GlobalDataStruct * = 0 ) const;
+    GlobalDataStruct * = 0 ) const
+  {
+    return GetSpeedWithExponent(m_CurvatureSpeedExponent,
+                                neighbourhood, offset);
+  }
 
   /** Local multiplier for the laplacian smoothing term */
   virtual ScalarValueType LaplacianSmoothingSpeed(
     const NeighborhoodType &neighbourhood,
     const FloatOffsetType &offset, 
-    GlobalDataStruct * = 0 ) const;
+    GlobalDataStruct * = 0 ) const
+  {
+    return GetSpeedWithExponent(m_LaplacianSmoothingSpeedExponent,
+                                neighbourhood, offset);
+  }
 
   /** Local multiplier for the propagation term */
   virtual ScalarValueType PropagationSpeed(
     const NeighborhoodType &neighbourhood,
     const FloatOffsetType &offset, 
-    GlobalDataStruct * = 0 ) const;
+    GlobalDataStruct * = 0 ) const
+  {
+    ScalarValueType v = GetSpeedWithExponent(m_PropagationSpeedExponent,
+                                neighbourhood, offset);
+    return v;
+  }
+
 
   /** Local multiplier for the advection term */
   virtual VectorType AdvectionField(
@@ -182,65 +235,50 @@ public:
 
   /** Set the exponent to which the speed image g() is taken
       when converted to the curvature speed */
-  void SetCurvatureSpeedExponent(int exponent) 
-    {
-    m_CurvatureSpeedExponent = exponent;
-    }
+  void SetCurvatureSpeedExponent(const int value)
+    { m_CurvatureSpeedExponent = value; }
  
   /** Get the exponent to which the speed image g() is taken
       when converted to the curvature speed */
-  int GetCurvatureSpeedExponent() const 
-    {
-    return m_CurvatureSpeedExponent;
-    }
+  int GetCurvatureSpeedExponent() const
+    { return m_CurvatureSpeedExponent; }
   
   /** Set the exponent to which the speed image g() is taken
       when computing the advection field */
-  void SetAdvectionSpeedExponent(int exponent) 
-    {
-    m_AdvectionSpeedExponent = exponent;
-    }
+  void SetAdvectionSpeedExponent(const int value)
+    { m_AdvectionSpeedExponent = value; }
  
   /** Get the exponent to which the speed image g() is taken
       when computing the advection field */
-  int GetAdvectionSpeedExponent() const 
-    {
-    return m_AdvectionSpeedExponent;
-    }
-  
+  int GetAdvectionSpeedExponent() const
+    { return m_AdvectionSpeedExponent; }
+
   /** Set the exponent to which the speed image g() is taken
       when converted to the propagation speed */
-  void SetPropagationSpeedExponent(int exponent) 
-    {
-    m_PropagationSpeedExponent = exponent;
-    }
- 
+  void SetPropagationSpeedExponent(const int value)
+    { m_PropagationSpeedExponent = value; }
+
   /** Get the exponent to which the speed image g() is taken
       when converted to the propagation speed */
-  int GetPropagationSpeedExponent() const 
-    {
-    return m_PropagationSpeedExponent;
-    }
-  
+  int GetPropagationSpeedExponent() const
+    { return m_PropagationSpeedExponent; }
+
   /** Set the exponent to which the speed image g() is taken
       when converted to the laplacian smoothing speed */
-  void SetLaplacianSmoothingSpeedExponent(int exponent) 
-    {
-    m_LaplacianSmoothingSpeedExponent = exponent;
-    }
- 
+  void SetLaplacianSmoothingSpeedExponent(const int value)
+    { m_LaplacianSmoothingSpeedExponent = value; }
+
   /** Get the exponent to which the speed image g() is taken
       when converted to the laplacian smoothing speed */
-  int GetLaplacianSmoothingSpeedExponent() const 
-    {
-    return m_LaplacianSmoothingSpeedExponent;
-    }
-  
+  int GetLaplacianSmoothingSpeedExponent() const
+    { return m_LaplacianSmoothingSpeedExponent; }
+
   /** Set/Get the time step. For this filter the time-step is supplied 
       by the user and remains fixed for all updates. */
-  void SetTimeStepFactor(const TimeStepType &t)
-    { m_TimeStepFactor = t; }
-  const TimeStepType &GetTimeStepFactor() const
+  void SetTimeStepFactor(TimeStepType value)
+    { m_TimeStepFactor = value; }
+
+  TimeStepType GetTimeStepFactor() const
     { return m_TimeStepFactor; }
 
   /** Returns the time step supplied by the user.  If the time step value
@@ -249,9 +287,10 @@ public:
       is non-zero, the fixed time step will be returned. */
   virtual TimeStepType ComputeGlobalTimeStep(void *GlobalData) const
     { 
+    TimeStepType step = Superclass::ComputeGlobalTimeStep(GlobalData);
     return m_TimeStepFactor == 0
-      ? Superclass::ComputeGlobalTimeStep(GlobalData)
-      : m_TimeStepFactor * Superclass::ComputeGlobalTimeStep(GlobalData); 
+      ? step
+      : m_TimeStepFactor * step;
     }
 
 protected:
@@ -277,18 +316,11 @@ private:
   /** The exponent to which speed image g() is taken to compute the 
       Laplacian smoothing speed */
   int m_LaplacianSmoothingSpeedExponent;
+
+  ScalarValueType m_SpeedScaleFactor;
   
   /** The speed image g() computed externally with user interaction */
-  ImagePointer m_SpeedImage;
-
-  /** The curvature image derived from the speed image g() */
-  ImagePointer m_CurvatureSpeedImage;
-
-  /** The propagation speed derived from the speed image g() */
-  ImagePointer m_PropagationSpeedImage;
-
-  /** The smoothing speed derived from the speed image g() */
-  ImagePointer m_LaplacianSmoothingSpeedImage;
+  SpeedImagePointer m_SpeedImage;
 
   /** The advection field (possibly scaled by speed image g() */
   VectorImagePointer m_AdvectionField;
@@ -297,51 +329,23 @@ private:
   bool m_UseExternalAdvectionField;
 
   /** Gradient filter used to produce the advection field */
-  typedef SNAPAdvectionFieldImageFilter<TImageType,float> AdvectionFilterType;
+  typedef SNAPAdvectionFieldImageFilter<SpeedImageType,float> AdvectionFilterType;
   typename AdvectionFilterType::Pointer m_AdvectionFilter;
 
   /** Instances of the interpolators */
-  typename ImageInterpolatorType::Pointer m_PropagationSpeedInterpolator;
-  typename ImageInterpolatorType::Pointer m_CurvatureSpeedInterpolator;
-  typename ImageInterpolatorType::Pointer m_LaplacianSmoothingSpeedInterpolator;
+  typename SpeedImageInterpolatorType::Pointer m_SpeedInterpolator;
   typename VectorInterpolatorType::Pointer m_AdvectionFieldInterpolator;
 
   /** The constant time step */
   TimeStepType m_TimeStepFactor;
-  
-  /** A trivial functor to square the g() image */
-  class SquareFunctor
-    {
-    public:
-      inline ScalarValueType operator()(ScalarValueType x) 
-        { return x * x; }
-    
-      // Dummy equality operators, since there is no data here
-      bool operator == (const SquareFunctor &) const { return true; }
-      bool operator != (const SquareFunctor &) const { return false; }
-    };
-  
-  /** A trivial functor to take the g() image to any power */
-  class PowFunctor
-    {
-    public: 
-      inline ScalarValueType operator()(ScalarValueType x) 
-        { return vcl_pow(x,power); }
-
-      // Dummy equality operators, since there is no data here
-      bool operator == (const PowFunctor &z) const 
-        { return power == z.power; }
-      
-      bool operator != (const PowFunctor &z) const 
-        { return !(*this == z); }
-
-      int power;
-    };
 
   /** A casting functor to convert between vector types.  */
   itk::Functor::VectorCast< 
     ITK_TYPENAME VectorInterpolatorType::OutputType,
     VectorType > m_VectorCast;
+
+  /** The current value of the speed function */
+  ThreadSpecificData<ScalarValueType> m_CachedSpeed;
 };
 
 #ifndef ITK_MANUAL_INSTANTIATION
diff --git a/Logic/LevelSet/SNAPLevelSetFunction.txx b/Logic/LevelSet/SNAPLevelSetFunction.txx
index c5d1179..3adfcfc 100644
--- a/Logic/LevelSet/SNAPLevelSetFunction.txx
+++ b/Logic/LevelSet/SNAPLevelSetFunction.txx
@@ -37,11 +37,13 @@
 #include "itkMultiplyImageFilter.h"
 #include "itkImageRegionIterator.h"
 #include "itkNumericTraits.h"
+#include "itkSimpleFastMutexLock.h"
+#include "itkMutexLockHolder.h"
 
 #include <map>
 
-template<class TImageType>
-SNAPLevelSetFunction<TImageType>
+template <class TSpeedImageType, class TImageType>
+SNAPLevelSetFunction<TSpeedImageType,TImageType>
 ::SNAPLevelSetFunction()
 : Superclass()
 {
@@ -52,131 +54,36 @@ SNAPLevelSetFunction<TImageType>
   m_PropagationSpeedExponent = 0;
   m_LaplacianSmoothingSpeedExponent = 0;
   m_UseExternalAdvectionField = false;
+  m_SpeedScaleFactor = 1.0;
 
-  m_PropagationSpeedInterpolator = ImageInterpolatorType::New();
-  m_CurvatureSpeedInterpolator = ImageInterpolatorType::New();
-  m_LaplacianSmoothingSpeedInterpolator = ImageInterpolatorType::New();
+  m_SpeedInterpolator = SpeedImageInterpolatorType::New();
   m_AdvectionFieldInterpolator = VectorInterpolatorType::New();
   
   m_AdvectionFilter = AdvectionFilterType::New();
 }
 
-template<class TImageType>
-SNAPLevelSetFunction<TImageType>
+template <class TSpeedImageType, class TImageType>
+SNAPLevelSetFunction<TSpeedImageType,TImageType>
 ::~SNAPLevelSetFunction()
 {
 
 }
 
-template<class TImageType>
+template <class TSpeedImageType, class TImageType>
 void 
-SNAPLevelSetFunction<TImageType>
-::SetSpeedImage(ImageType *pointer)
+SNAPLevelSetFunction<TSpeedImageType,TImageType>
+::SetSpeedImage(SpeedImageType *pointer)
 {
   m_SpeedImage = pointer;
+  m_SpeedInterpolator->SetInputImage(m_SpeedImage);
   m_AdvectionFilter->SetInput(m_SpeedImage);
 }
-/*
-template<class TImageType>
-void
-SNAPLevelSetFunction<TImageType>
-::SetAdvectionField(VectorImageType *pointer)
-{
-  m_UseExternalAdvectionField = true;
-  m_AdvectionField = pointer;
-}
-*/
 
-
-template<class TImageType>
+template <class TSpeedImageType, class TImageType>
 void
-SNAPLevelSetFunction<TImageType>
+SNAPLevelSetFunction<TSpeedImageType,TImageType>
 ::CalculateInternalImages()
 {
-  // Create a map of integers to image pointers.  This map will cache the 
-  // different powers of g() that must be computed (hopefully none!)
-  typedef std::map<int,ImagePointer> PowerMapType;
-  PowerMapType powerMap;
-
-  // Initialize the map for the default powers
-  powerMap[0] = NULL;
-  powerMap[1] = m_SpeedImage;
-
-  // Create a list of the required powers
-  int powers[4] = {
-    this->GetPropagationSpeedExponent(),
-    this->GetAdvectionSpeedExponent(),
-    this->GetCurvatureSpeedExponent(),
-    this->GetLaplacianSmoothingSpeedExponent()
-  };
-
-  // What equation are we solving?
-  // std::cout << "Solving Equation :  = " << std::endl;
-  // std::cout << "  P-W = " << this->GetPropagationWeight() << std::endl;
-  // std::cout << "  P-E = " << this->GetPropagationSpeedExponent() << std::endl;
-  // std::cout << "  C-W = " << this->GetCurvatureWeight() << std::endl;
-  // std::cout << "  C-E = " << this->GetCurvatureSpeedExponent() << std::endl;
-  // std::cout << "  A-W = " << this->GetAdvectionWeight() << std::endl;
-  // std::cout << "  A-E = " << this->GetAdvectionSpeedExponent() << std::endl;
-  // std::cout << "  L-W = " << this->GetLaplacianSmoothingWeight() << std::endl;
-  // std::cout << "  L-E = " << this->GetLaplacianSmoothingSpeedExponent() << std::endl;
-
-  // Create an image for each of these powers, if needed
-  for(unsigned int iPower=0; iPower < 4; iPower++)
-    {
-    // For powers of 0 and 1, which are by far the most common, there is
-    // nothing to compute
-    if(powers[iPower] == 0 || powers[iPower] == 1) 
-      {
-      continue;
-      }
-    
-    // For power 2, we square the speed image.  Since pow() is a dog, 
-    // let's handle this case explicitly
-    else if(powers[iPower] == 2)
-      {
-      // Create a filter that will square the image
-      typedef itk::UnaryFunctorImageFilter<ImageType,ImageType,SquareFunctor>
-        ExponentFilterType;
-
-      // Run the filter
-      typename ExponentFilterType::Pointer filter = 
-        ExponentFilterType::New();
-      filter->SetInput(m_SpeedImage);
-      filter->Update();
-      
-      // Stick the filter's output into the map
-      powerMap[2] = filter->GetOutput();
-      }
-
-    // For powers other than 3, let the user suffer through the pow()!
-    else
-      {
-      // Create a filter that will square the image
-      typedef itk::UnaryFunctorImageFilter<ImageType,ImageType,PowFunctor>
-        ExponentFilterType;
-
-      typename ExponentFilterType::Pointer filter = 
-        ExponentFilterType::New();
-      filter->SetInput(m_SpeedImage);
-      
-      // Create a functor with specified power
-      PowFunctor functor;
-      functor.power = powers[iPower];
-      filter->SetFunctor(functor);
-
-      // Run the filter
-      filter->Update();
-      
-      // Stick the filter's output into the map
-      powerMap[powers[iPower]] = filter->GetOutput();
-      }
-    } // For all powers
-
-  // Now that we have the powers, we can assign the speed images
-  m_PropagationSpeedImage = powerMap[m_PropagationSpeedExponent];
-  m_CurvatureSpeedImage = powerMap[m_CurvatureSpeedExponent];
-  m_LaplacianSmoothingSpeedImage = powerMap[m_LaplacianSmoothingSpeedExponent];
   
   // There is still the business of the advection image to attend to
   // Compute \f$ \nabla g() \f$ (will be cached from run to run)
@@ -190,128 +97,93 @@ SNAPLevelSetFunction<TImageType>
         m_AdvectionFilter->GetOutput());
     }
 
-  // Set up the image interpolators to point to the generated images
-  if(m_PropagationSpeedExponent != 0)
-    m_PropagationSpeedInterpolator->SetInputImage(m_PropagationSpeedImage);
-  if(m_CurvatureSpeedExponent != 0)
-    m_CurvatureSpeedInterpolator->SetInputImage(m_CurvatureSpeedImage);
-  if(m_LaplacianSmoothingSpeedExponent != 0)
-    m_LaplacianSmoothingSpeedInterpolator->SetInputImage(
-      m_LaplacianSmoothingSpeedImage);
-
   // Set up the advection interpolator
   // if(m_AdvectionSpeedExponent != 0)
   m_AdvectionFieldInterpolator->SetInputImage(m_AdvectionField);
 }
 
-
-template<class TImageType>
-typename SNAPLevelSetFunction<TImageType>::ScalarValueType
-SNAPLevelSetFunction<TImageType>
-::CurvatureSpeed(const NeighborhoodType &neighborhood, 
+template <class TSpeedImageType, class TImageType>
+typename SNAPLevelSetFunction<TSpeedImageType,TImageType>::VectorType
+SNAPLevelSetFunction<TSpeedImageType,TImageType>
+::AdvectionField(const NeighborhoodType &neighborhood,
                  const FloatOffsetType &offset,
-                 GlobalDataStruct *) const 
+                 GlobalDataStruct *) const
 {
-  // If the exponent is zero, there is nothing to return
-  if(m_CurvatureSpeedExponent == 0)
-    return itk::NumericTraits<ScalarValueType>::One; 
-  
-  // Otherwise, perform interpolation on the image
   IndexType idx = neighborhood.GetIndex();
-  ContinuousIndexType cdx;
+  typedef typename VectorInterpolatorType::ContinuousIndexType VectorContinuousIndexType;
+  VectorContinuousIndexType cdx;
+  typename SNAPLevelSetFunction<TSpeedImageType,TImageType>::VectorType avec;
   for (unsigned i = 0; i < ImageDimension; ++i)
     {
     cdx[i] = static_cast<double>(idx[i]) - offset[i];
     }
-  if ( m_CurvatureSpeedInterpolator->IsInsideBuffer(cdx) )
+  if ( m_AdvectionFieldInterpolator->IsInsideBuffer(cdx) )
+    {
+    avec = m_VectorCast(m_AdvectionFieldInterpolator->EvaluateAtContinuousIndex(cdx));
+    }
+  else
     {
-    return (static_cast<ScalarValueType>(
-        m_CurvatureSpeedInterpolator->EvaluateAtContinuousIndex(cdx)));
+    avec = m_AdvectionField->GetPixel(idx);
     }
-  else return ( static_cast<ScalarValueType>(m_CurvatureSpeedImage->GetPixel(idx)) );
+
+  for(unsigned i = 0; i < ImageDimension; i++)
+    avec[i] *= m_SpeedScaleFactor;
+
+  return avec;
 }
 
-template<class TImageType>
-typename SNAPLevelSetFunction<TImageType>::ScalarValueType
-SNAPLevelSetFunction<TImageType>
-::PropagationSpeed(const NeighborhoodType &neighborhood, 
-                   const FloatOffsetType &offset,
-                   GlobalDataStruct *) const 
+template <class TSpeedImageType, class TImageType>
+void
+SNAPLevelSetFunction<TSpeedImageType, TImageType>
+::PrintSelf(std::ostream &os, itk::Indent indent) const
 {
-  // If the exponent is zero, there is nothing to return
-  if(m_PropagationSpeedExponent == 0)
-    return itk::NumericTraits<ScalarValueType>::One; 
-
-  
-  // Otherwise, perform interpolation on the image
-  IndexType idx = neighborhood.GetIndex();
-  ContinuousIndexType cdx;
-  for (unsigned i = 0; i < ImageDimension; ++i)
-    {
-    cdx[i] = static_cast<double>(idx[i]) - offset[i];
-    }
-  if ( m_PropagationSpeedInterpolator->IsInsideBuffer(cdx) )
-    {
-    return (static_cast<ScalarValueType>(
-        m_PropagationSpeedInterpolator->EvaluateAtContinuousIndex(cdx)));
-    }
-  else return ( static_cast<ScalarValueType>(m_PropagationSpeedImage->GetPixel(idx)) );
+  Superclass::PrintSelf(os, indent);
 }
 
-template<class TImageType>
-typename SNAPLevelSetFunction<TImageType>::ScalarValueType
-SNAPLevelSetFunction<TImageType>
-::LaplacianSmoothingSpeed(const NeighborhoodType &neighborhood, 
-                          const FloatOffsetType &offset,
-                          GlobalDataStruct *) const 
+template <class TSpeedImageType, class TImageType>
+typename SNAPLevelSetFunction<TSpeedImageType, TImageType>::PixelType
+SNAPLevelSetFunction<TSpeedImageType, TImageType>
+::ComputeUpdate(
+    const NeighborhoodType &neighborhood,
+    void *globalData, const FloatOffsetType &offset)
 {
-  // If the exponent is zero, there is nothing to return
-  if(m_LaplacianSmoothingSpeedExponent == 0)
-    return itk::NumericTraits<ScalarValueType>::One; 
-  
-  // Otherwise, perform interpolation on the image
+
+  // Interpolate the speed value at this location. This way, we don't need to
+  // perform interpolation each time the GetXXXSpeed() function is called.
   IndexType idx = neighborhood.GetIndex();
   ContinuousIndexType cdx;
   for (unsigned i = 0; i < ImageDimension; ++i)
-    {
     cdx[i] = static_cast<double>(idx[i]) - offset[i];
-    }
-  if ( m_LaplacianSmoothingSpeedInterpolator->IsInsideBuffer(cdx) )
-    {
-    return (static_cast<ScalarValueType>(
-        m_LaplacianSmoothingSpeedInterpolator->EvaluateAtContinuousIndex(cdx)));
-    }
-  else return ( static_cast<ScalarValueType>(m_LaplacianSmoothingSpeedImage->GetPixel(idx)) );
+
+  // Store the speed in thread-specific memory
+  m_CachedSpeed =
+      m_SpeedScaleFactor * static_cast<ScalarValueType>(
+        m_SpeedInterpolator->IsInsideBuffer(cdx)
+        ? m_SpeedInterpolator->EvaluateAtContinuousIndex(cdx)
+        : m_SpeedImage->GetPixel(idx));
+
+  // Call the parent method
+  return Superclass::ComputeUpdate(neighborhood, globalData, offset);
 }
 
-template <class TImageType>
-typename SNAPLevelSetFunction<TImageType>::VectorType
-SNAPLevelSetFunction<TImageType>
-::AdvectionField(const NeighborhoodType &neighborhood,
-                 const FloatOffsetType &offset,
-                 GlobalDataStruct *) const
+template <class TSpeedImageType, class TImageType>
+typename SNAPLevelSetFunction<TSpeedImageType, TImageType>::ScalarValueType
+SNAPLevelSetFunction<TSpeedImageType, TImageType>
+::GetSpeedWithExponent(int exponent,
+                       const NeighborhoodType &neighbourhood,
+                       const FloatOffsetType &offset,
+                       GlobalDataStruct *) const
 {
-  IndexType idx = neighborhood.GetIndex();
-  typedef typename VectorInterpolatorType::ContinuousIndexType VectorContinuousIndexType;
-  VectorContinuousIndexType cdx;
-  for (unsigned i = 0; i < ImageDimension; ++i)
-    {
-    cdx[i] = static_cast<double>(idx[i]) - offset[i];
-    }
-  if ( m_AdvectionFieldInterpolator->IsInsideBuffer(cdx) )
+  // Get the speed value from thread-specific cache
+  ScalarValueType speed = m_CachedSpeed;
+
+  switch(exponent)
     {
-    return ( 
-      m_VectorCast(
-       m_AdvectionFieldInterpolator->EvaluateAtContinuousIndex(cdx)));
+    case 0 : return itk::NumericTraits<ScalarValueType>::One;
+    case 1 : return speed;
+    case 2 : return speed * speed;
+    case 3 : return speed * speed * speed;
+    default : return pow(speed, exponent);
     }
-  else return ( m_AdvectionField->GetPixel(idx) );
-}
-
-template <class TImageType>
-void
-SNAPLevelSetFunction<TImageType>
-::PrintSelf(std::ostream &os, itk::Indent indent) const
-{
-  Superclass::PrintSelf(os, indent);
 }
 
diff --git a/Logic/LevelSet/SnakeParameters.cxx b/Logic/LevelSet/SnakeParameters.cxx
index ddee87c..816917a 100644
--- a/Logic/LevelSet/SnakeParameters.cxx
+++ b/Logic/LevelSet/SnakeParameters.cxx
@@ -57,7 +57,7 @@ SnakeParameters
   p.m_LaplacianWeight = 0.0f;
   p.m_LaplacianSpeedExponent = 0;
 
-  p.m_AdvectionWeight = 0.5;
+  p.m_AdvectionWeight = 2.0;
   p.m_AdvectionSpeedExponent = 0;       
 
   p.m_Solver = PARALLEL_SPARSE_FIELD_SOLVER;
diff --git a/Logic/LevelSet/SnakeParameters.h b/Logic/LevelSet/SnakeParameters.h
index a25a76e..1a4c30f 100644
--- a/Logic/LevelSet/SnakeParameters.h
+++ b/Logic/LevelSet/SnakeParameters.h
@@ -37,6 +37,8 @@
 
 #include "SNAPCommon.h"
 
+// TODO: implement this using AbstractPropertyContainerModel
+
 /**
  * \class SnakeParameters
  * \brief Parameters for the Level Set evolution.
@@ -82,6 +84,8 @@ public:
 
   // Define a comparison operator
   bool operator ==(const SnakeParameters &p) const;
+  bool operator !=(const SnakeParameters &p) const
+    { return !((*this) == p); }
 
   /** Whether we wish to automatically compute optimal time step 
    * in level snake propagation */
diff --git a/Logic/LevelSet/SnakeParametersPreviewPipeline.cxx b/Logic/LevelSet/SnakeParametersPreviewPipeline.cxx
new file mode 100644
index 0000000..b16eb24
--- /dev/null
+++ b/Logic/LevelSet/SnakeParametersPreviewPipeline.cxx
@@ -0,0 +1,630 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: SnakeParametersPreviewPipeline.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/19 19:15:14 $
+  Version:   $Revision: 1.6 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#include "SnakeParametersPreviewPipeline.h"
+
+#include "SNAPOpenGL.h"
+#include "GlobalState.h"
+
+#include "LevelSetExtensionFilter.h"
+#include "SignedDistanceFilter.h"
+#include "SNAPLevelSetFunction.h"
+#include "itkBSplineInterpolationWeightFunction.h"
+#include "itkBSplineKernelFunction.h"
+#include "itkImageRegionConstIteratorWithIndex.h"
+#include "itkNarrowBandLevelSetImageFilter.h"
+#include "itkVTKImageExport.h"
+#include "vtkCellArray.h"
+#include "vtkContourFilter.h"
+#include "vtkImageData.h"
+#include "vtkImageImport.h"
+#include "vtkPolyData.h"
+
+#include "SNAPLevelSetDriver.h"
+#include "PolygonScanConvert.h"
+
+#ifndef vtkFloatingPointType
+#define vtkFloatingPointType float
+#endif
+
+using namespace std;
+
+/**
+ * This private-scope class creates a 2D demo of the level set segmentation
+ * The segmentation is a 2D version of the SNAP segmentation, with contours
+ * extracted at each iteration. The user supplies the speed image, a set of
+ * points that form the initial contour and the snake evolution parameters.
+ * Then, on a timer, call OnTimerEvent() to generate a demo loop of evolving
+ * contours.
+ */
+class LevelSetPreview2d
+{
+public:
+  typedef itk::Image<float, 2> FloatImageType;
+  typedef itk::Image<short, 2> ShortImageType;
+  typedef SnakeParametersPreviewPipeline::SampledPointList CurveType;
+
+  // Constructor
+  LevelSetPreview2d()
+    {
+    m_Driver = NULL;
+    m_SpeedImage = NULL;
+    m_DriverDirty = true;
+    m_ContourDirty = true;
+    m_DemoLoopLength = 160;
+    m_DemoLoopStep = 2;
+    m_LevelSetImage = NULL;
+
+    }
+
+  // Destructor
+  ~LevelSetPreview2d()
+    { 
+    if(m_Driver) delete m_Driver; 
+    }
+
+  // Timer callback, used to regenerate the current contour
+  void OnTimerEvent()
+    {
+    // Clear the output
+    m_CurrentCurve.clear();
+
+    // If the driver is dirty, we need to create a new one
+    if(m_DriverDirty && m_Driver != NULL)
+      { 
+      delete m_Driver;
+      m_Driver = NULL;
+      }
+
+    // If the driver is null and all the necessary components exist, create it
+    if(m_Driver == NULL && m_SpeedImage.IsNotNull() && m_Curve.size() > 0)
+      {
+      // Check if we need to allocate the level set image
+      if(m_LevelSetImage.IsNull() || m_LevelSetImage->GetBufferedRegion() != 
+          m_SpeedImage->GetBufferedRegion())
+        {
+        m_LevelSetImage = FloatImageType::New();
+        m_LevelSetImage->SetRegions(m_SpeedImage->GetBufferedRegion());
+        m_LevelSetImage->Allocate();
+        m_ContourDirty = true;
+        }
+
+      // Check if the contour is dirty, and create a contour image
+      if(m_ContourDirty)
+        {
+        // Scale the contour by the size of the image
+        std::vector<Vector2d> points; points.reserve(m_Curve.size());
+        for(CurveType::iterator it = m_Curve.begin(); it != m_Curve.end(); ++it)
+          {
+          points.push_back(Vector2d(
+            it->x[0] *  m_LevelSetImage->GetBufferedRegion().GetSize()[0], 
+            it->x[1] *  m_LevelSetImage->GetBufferedRegion().GetSize()[1]));
+          }
+
+        // Fill in the contour in the level set image
+        m_LevelSetImage->FillBuffer(0.0f);
+        typedef PolygonScanConvert<
+          float, GL_FLOAT, std::vector<Vector2d>::iterator> ScanConvertType;
+        ScanConvertType::RasterizeFilled(
+          points.begin(), points.size(), m_LevelSetImage);
+
+        // Ensure that the initial level set is zero
+        typedef itk::ImageRegionIterator<FloatImageType> IteratorType;
+        IteratorType it2(m_LevelSetImage, m_LevelSetImage->GetBufferedRegion());
+        for(; !it2.IsAtEnd(); ++it2)
+          it2.Set(it2.Get() > 0 ? -1.0 : 1.0);
+        m_LevelSetImage->Modified();
+
+        // The contour is not dirty any more
+        m_ContourDirty = false;
+        }
+
+      m_Driver = new SNAPLevelSetDriver2d(
+        m_LevelSetImage.GetPointer(), m_SpeedImage, m_Parameters);
+
+      m_DriverDirty = false;
+      m_DemoLoopTime = 0;
+      }
+
+    // Now that we've made sure that the driver is OK, run the demo loop
+    if(m_Driver != NULL)
+      {
+      // Run some number of level set evolutions
+      if(m_DemoLoopTime > m_DemoLoopLength)
+        {
+        m_DemoLoopTime = 0;
+        m_Driver->Restart();
+        }
+      else
+        {
+        m_Driver->Run(m_DemoLoopStep);
+        m_DemoLoopTime += m_DemoLoopStep;
+        }
+
+      // Initialize the VTK Importer
+      m_VTKExporter = itk::VTKImageExport<FloatImageType>::New();
+      m_VTKImporter = vtkImageImport::New();
+
+      // Pipe the importer into the exporter (that's a lot of code)
+      m_VTKImporter->SetUpdateInformationCallback(
+        m_VTKExporter->GetUpdateInformationCallback());
+      m_VTKImporter->SetPipelineModifiedCallback(
+        m_VTKExporter->GetPipelineModifiedCallback());
+      m_VTKImporter->SetWholeExtentCallback(
+        m_VTKExporter->GetWholeExtentCallback());
+      m_VTKImporter->SetSpacingCallback(
+        m_VTKExporter->GetSpacingCallback());
+      m_VTKImporter->SetOriginCallback(
+        m_VTKExporter->GetOriginCallback());
+      m_VTKImporter->SetScalarTypeCallback(
+        m_VTKExporter->GetScalarTypeCallback());
+      m_VTKImporter->SetNumberOfComponentsCallback(
+        m_VTKExporter->GetNumberOfComponentsCallback());
+      m_VTKImporter->SetPropagateUpdateExtentCallback(
+        m_VTKExporter->GetPropagateUpdateExtentCallback());
+      m_VTKImporter->SetUpdateDataCallback(
+        m_VTKExporter->GetUpdateDataCallback());
+      m_VTKImporter->SetDataExtentCallback(
+        m_VTKExporter->GetDataExtentCallback());
+      m_VTKImporter->SetBufferPointerCallback(
+        m_VTKExporter->GetBufferPointerCallback());  
+      m_VTKImporter->SetCallbackUserData(
+        m_VTKExporter->GetCallbackUserData());  
+
+      // Create and configure the contour filter
+      m_VTKContour = vtkContourFilter::New();
+      m_VTKContour->SetInputConnection(m_VTKImporter->GetOutputPort());
+      m_VTKContour->ReleaseDataFlagOn();
+      m_VTKContour->ComputeScalarsOff();
+      m_VTKContour->ComputeGradientsOff();
+      m_VTKContour->UseScalarTreeOn();
+      m_VTKContour->SetNumberOfContours(1);
+      m_VTKContour->SetValue(0, 0.0);
+
+      // Generate a contour
+      m_VTKExporter->SetInput(m_Driver->GetCurrentState());
+      m_VTKContour->Update();
+
+      // Get the list of points representing the evolving contour
+      vtkPolyData *pd = m_VTKContour->GetOutput();
+      m_CurrentCurve.reserve(pd->GetNumberOfCells() * 2);
+      for(int i=0;i<pd->GetNumberOfCells();i++)
+        {
+        vtkFloatingPointType *pt1 = pd->GetPoint(pd->GetCell(i)->GetPointId(0));
+        m_CurrentCurve.push_back(Vector2d(pt1[0] + 0.5,pt1[1] + 0.5));
+        vtkFloatingPointType *pt2 = pd->GetPoint(pd->GetCell(i)->GetPointId(1));
+        m_CurrentCurve.push_back(Vector2d(pt2[0] + 0.5,pt2[1] + 0.5));
+        }
+      }
+
+    m_VTKImporter->Delete();
+    m_VTKContour->Delete();
+    }
+
+  // Change the speed image passed as the input to the level set
+  void SetSpeedImage(ShortImageType *image)
+    {
+    if(image != m_SpeedImage)
+      {
+      m_DriverDirty = true;
+      m_ContourDirty = true;
+      m_SpeedImage = image;
+      }
+    }
+
+  // Set the initial contour curve
+  void SetInitialContour(const CurveType &curve)
+    {
+    m_Curve = curve;
+    m_ContourDirty = true;
+    m_DriverDirty = true;
+    }
+
+  // Set the snake paramters
+  void SetSnakeParameters(const SnakeParameters &parameters)
+    {
+    if(!(m_Parameters == parameters))
+      {
+      m_Parameters = parameters;
+      m_DriverDirty = true;
+      }
+    }
+
+  // Set the length of the demo loop
+  void SetDemoLoopLength(unsigned int length)
+    {
+    m_DemoLoopLength = length;
+    m_DriverDirty = true;
+    }
+
+  // Set the step size of the demo loop
+  void SetDemoLoopStep(unsigned int step)
+    {
+    m_DemoLoopStep = step;
+    m_DriverDirty = true;
+    }
+
+  // See if there is something to display
+  bool IsLevelSetComputed()
+    { return m_Driver != NULL && !m_DriverDirty; }
+
+  // Get the level set image to display
+  FloatImageType *GetLevelSetImage()
+    { return m_Driver->GetCurrentState(); }
+
+  // Get the evolving contour
+  vector<Vector2d> &GetEvolvingContour()
+    { return m_CurrentCurve; }
+
+  // Restart the demo
+  void Restart()
+    { m_DriverDirty = true; m_CurrentCurve.clear(); }
+
+private:
+  // Parameters of the level set algorithm
+  ShortImageType::Pointer m_SpeedImage;
+  FloatImageType::Pointer m_LevelSetImage;
+  CurveType m_Curve;
+  SnakeParameters m_Parameters;
+  unsigned int m_DemoLoopStep, m_DemoLoopLength, m_DemoLoopTime;
+
+  // Snake evolution driver pointer
+  SNAPLevelSetDriver2d *m_Driver;
+
+  // VTK objects for computing a contour
+  typedef itk::VTKImageExport<FloatImageType> ExporterType;
+  itk::SmartPointer<ExporterType> m_VTKExporter;
+  vtkImageImport *m_VTKImporter;
+  vtkContourFilter *m_VTKContour;
+
+  // The zero level set, as it evolves
+  vector<Vector2d> m_CurrentCurve;
+
+  bool m_DriverDirty, m_ContourDirty;
+};
+
+
+
+void 
+SnakeParametersPreviewPipeline
+::AnimationCallback()
+{
+  // Call the callback on the demo loop
+  m_DemoLoop->OnTimerEvent();
+}
+
+void SnakeParametersPreviewPipeline::AnimationRestart()
+{
+  m_DemoLoop->Restart();
+}
+
+SnakeParametersPreviewPipeline
+::SnakeParametersPreviewPipeline(GlobalState *state)
+{
+  // Store the global state
+  m_GlobalState = state;
+
+  // Start with a 100 interpolated points
+  m_NumberOfSampledPoints = 100;
+
+  m_ControlsModified = false;
+  m_SpeedModified = false;
+  m_ParametersModified = false;
+  m_QuickUpdate = false;
+
+  // Initialize the parameters
+  m_Parameters = SnakeParameters::GetDefaultEdgeParameters();
+
+  // Initialize the display filter
+  m_DisplayMapper = IntensityFilterType::New();
+
+  // TODO: the colormap from the current speed image should be used!
+
+  // Create a new demo loop
+  m_DemoLoop = new LevelSetPreview2d;
+}
+
+SnakeParametersPreviewPipeline
+::~SnakeParametersPreviewPipeline()
+{
+  delete m_DemoLoop;
+}
+
+void
+SnakeParametersPreviewPipeline
+::SetControlPoints(const std::vector<Vector2d> &points)
+{
+  if(m_ControlPoints != points)
+    {  
+    // Save the points
+    m_ControlPoints = points;
+
+    // Set the flags
+    m_ControlsModified = true;
+    m_QuickUpdate = false;
+    }
+}
+
+void 
+SnakeParametersPreviewPipeline
+::ChangeControlPoint(
+  unsigned int index, const Vector2d &point, bool quickUpdate)
+{
+  // Update the point
+  assert(index < m_ControlPoints.size());
+
+  // Update the point
+  m_ControlPoints[index] = point;
+
+  // Set the flags
+  m_ControlsModified = true;
+
+  // Set the update flag
+  m_QuickUpdate = quickUpdate;
+}
+
+void
+SnakeParametersPreviewPipeline
+::SetSpeedImage(ShortImageType *image)
+{
+  // Update the image internally
+  if(image != m_SpeedImage)
+    {
+    // Set the modified flag
+    m_SpeedModified = true;
+    m_SpeedImage = image;
+
+    // Create a filter to compute a gradient image
+    typedef itk::GradientImageFilter<ShortImageType> GradientFilter;
+    GradientFilter::Pointer filter = GradientFilter::New();
+
+    // Set up and run the filter
+    filter->SetInput(m_SpeedImage);
+    m_GradientImage = filter->GetOutput();
+    filter->Update();
+
+    // Pass the image to the display functor
+    m_DisplayMapper->SetInput(m_SpeedImage);
+    DisplayImageType *di = m_DisplayMapper->GetOutput();
+    di->Update();
+
+    // Pass the speed image to the preview object
+    m_DemoLoop->SetSpeedImage(image);
+    }
+}
+
+void
+SnakeParametersPreviewPipeline
+::SetSnakeParameters(const SnakeParameters &parameters)
+{
+  // Clean up the parameters
+  SnakeParameters clean = parameters;
+  clean.SetClamp(false);
+  clean.SetGround(0);
+  clean.SetLaplacianSpeedExponent(0);
+  clean.SetLaplacianWeight(0);
+  clean.SetSolver(SnakeParameters::PARALLEL_SPARSE_FIELD_SOLVER);
+
+  // Make the 2D example behave more like 3D ...
+  clean.SetCurvatureWeight(5 * parameters.GetCurvatureWeight());
+
+  // Don't waste time on nonsense
+  if(m_Parameters == clean) return;
+    
+  // Save the parameters
+  m_Parameters = clean;
+  m_ParametersModified = true;
+
+  // Pass the parameters to the demo loop
+  m_DemoLoop->SetSnakeParameters(m_Parameters);
+}
+
+void 
+SnakeParametersPreviewPipeline
+::SetNumberOfSampledPoints(unsigned int number)
+{
+  if(number!=m_NumberOfSampledPoints)
+    {
+    m_NumberOfSampledPoints = number;
+    m_ControlsModified = true;
+    }
+}
+
+void
+SnakeParametersPreviewPipeline
+::Update()
+{
+  // Check what work needs to be done
+  if(m_ControlsModified)
+    {
+    UpdateContour();
+    }
+  if(!m_QuickUpdate)
+    {
+    if(m_ControlsModified)
+      {
+      m_DemoLoop->SetInitialContour(GetSampledPoints());
+      // UpdateLevelSet(context);
+      }
+    if(m_ParametersModified || m_ControlsModified)
+      {
+      UpdateForces();
+      m_ParametersModified = false;
+      }
+    }
+
+  // Clear the modified flags
+  m_ControlsModified = false;
+
+  // Also, check whether the colormap used for display has changed
+  // TODO: the colormap from the current speed image should be used!
+}
+
+void 
+SnakeParametersPreviewPipeline
+::UpdateContour()
+{
+  // Create a b-spline object
+  typedef itk::BSplineInterpolationWeightFunction<double,1,3> FunctionType;
+  FunctionType::Pointer function = FunctionType::New();
+
+  // Used to compute spline derivatives
+  itk::BSplineKernelFunction<3>::Pointer kf3 = itk::BSplineKernelFunction<3>::New();
+  itk::BSplineKernelFunction<2>::Pointer kf2 = itk::BSplineKernelFunction<2>::New();
+  itk::BSplineKernelFunction<2>::Pointer kf1 = itk::BSplineKernelFunction<2>::New();
+
+  // Initialize the sampled point array
+  m_SampledPoints.clear();
+  m_SampledPoints.reserve(m_NumberOfSampledPoints);
+  
+  int uMax = m_ControlPoints.size() - 3; 
+  for(double t = 0; t < 1.0; t += 0.005)
+    {
+    double s = t * uMax;
+    
+    // The starting index
+    // int si = ((int)(t * uMax)) - 1;
+    int sidx = (int) floor(s - 1);
+    double u = s - sidx;
+
+    // Compute the position and derivatives of the b-spline
+    Vector2d x(0.0f,0.0f);
+    Vector2d xu(0.0f,0.0f);
+    Vector2d xuu(0.0f,0.0f);
+    for(int k=0; k < 4; k++)
+      {      
+      double w = kf3->Evaluate(u);
+      double wu = kf2->Evaluate(u+0.5) - kf2->Evaluate(u-0.5);
+      double wuu = kf1->Evaluate(u+1) + kf1->Evaluate(u-1) - 2 * kf1->Evaluate(u);
+      u-=1.0;
+
+      int idx = (uMax + sidx + k) % uMax;
+      x += w * m_ControlPoints[idx];
+      xu += wu * m_ControlPoints[idx];
+      xuu += wuu * m_ControlPoints[idx];
+      }
+
+    // Create and save the point
+    SampledPoint pt;
+    pt.x = x;
+    pt.t = t;
+    xu.normalize();
+    pt.n = Vector2d(-xu[1],xu[0]);    
+    pt.PropagationForce = pt.CurvatureForce = pt.AdvectionForce = 0.0;
+    pt.kappa 
+      = (xu[0] * xuu[1] - xu[1] * xuu[0]) / pow(xu[0]*xu[0] + xu[1]*xu[1],1.5);
+
+    m_SampledPoints.push_back(pt);
+    }
+}
+
+void
+SnakeParametersPreviewPipeline
+::UpdateLevelSetFunction()
+{
+}
+
+void
+SnakeParametersPreviewPipeline
+::UpdateLevelSet()
+{
+}
+
+void
+SnakeParametersPreviewPipeline
+::UpdateForces()
+{
+  // Image interpolator types
+  typedef itk::LinearInterpolateImageFunction<
+    ShortImageType,double> LerpType;
+  typedef itk::VectorLinearInterpolateImageFunction<
+    VectorImageType,double> VectorLerpType;
+  
+  // Create the speed image interpolator
+  LerpType::Pointer sLerp = LerpType::New();
+  sLerp->SetInputImage(m_SpeedImage);
+
+  // Create the gradient image interpolator
+  VectorLerpType::Pointer gLerp = VectorLerpType::New();
+  gLerp->SetInputImage(m_GradientImage);
+
+  // Get the image dimensions
+  itk::Size<2> idim = m_SpeedImage->GetBufferedRegion().GetSize();
+  
+  // Compute the geometry of each point
+  for(unsigned int i = 0; i < m_SampledPoints.size(); i++)
+    {
+    // A reference so we can access the point in shorthand
+    SampledPoint &p = m_SampledPoints[i];
+    
+    // We're done computing the geometric properties of the curve.  Now, let's
+    // compute the image-related quantities.  First, convert the point to image
+    // coordinates
+    LerpType::ContinuousIndexType idx;
+    idx[0] = idim[0] * p.x[0];
+    idx[1] = idim[1] * p.x[1];
+
+    // Get the value of the g function
+    double g = sLerp->EvaluateAtContinuousIndex(idx);
+
+    // Scale to [-1 1] range because speed is represented as a short internally
+    g /= 0x7fff;
+
+    // Get the value of the gradient
+    VectorLerpType::OutputType gradG = gLerp->EvaluateAtContinuousIndex(idx);
+    gradG /= 0x7fff;
+    
+    // Compute the propagation force component of the curve evolution
+    p.PropagationForce = m_Parameters.GetPropagationWeight() 
+      * pow(g,m_Parameters.GetPropagationSpeedExponent());
+
+    // Compute the curvature force component of the curve evolution
+    p.CurvatureForce = m_Parameters.GetCurvatureWeight() * p.kappa
+      * pow(g,m_Parameters.GetCurvatureSpeedExponent()+1);
+
+    // Compute the advection force component of the curve evolution
+    p.AdvectionForce = - m_Parameters.GetAdvectionWeight()
+      * (p.n[0] * gradG[0] + p.n[1] * gradG[1])
+      * pow(g,m_Parameters.GetAdvectionSpeedExponent());    
+    }
+}
+
+
+
+std::vector<Vector2d> &
+SnakeParametersPreviewPipeline
+::GetDemoLoopContour()
+{
+  return m_DemoLoop->GetEvolvingContour();
+}
diff --git a/Logic/LevelSet/SnakeParametersPreviewPipeline.h b/Logic/LevelSet/SnakeParametersPreviewPipeline.h
new file mode 100644
index 0000000..ce6359b
--- /dev/null
+++ b/Logic/LevelSet/SnakeParametersPreviewPipeline.h
@@ -0,0 +1,230 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: SnakeParametersPreviewPipeline.h,v $
+  Language:  C++
+  Date:      $Date: 2009/01/23 20:09:38 $
+  Version:   $Revision: 1.4 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#ifndef __SnakeParametersPreviewPipeline_h_
+#define __SnakeParametersPreviewPipeline_h_
+
+#include "itkImage.h"
+#include "itkRGBAPixel.h"
+#include "itkCovariantVector.h"
+#include "itkUnaryFunctorImageFilter.h"
+#include "SnakeParameters.h"
+#include "ColorMap.h"
+#include "ImageWrapperTraits.h"
+
+template<class TInputImage, class TOutputImage> class SignedDistanceFilter;
+template <class TSpeedImageType, class TImageType> class SNAPLevelSetFunction;
+template<class TFilter> class LevelSetExtensionFilter;
+
+class vtkImageImport;
+class vtkContourFilter;
+class LevelSetPreviewPipeline2D;
+class GlobalState;
+
+namespace itk {
+  template<class TInputImage, class TOutputImage> 
+    class ParallelSparseFieldLevelSetImageFilter;
+};
+
+class LevelSetPreview2d;
+
+// #define SNAKE_PREVIEW_ADVANCED 1
+
+/** 
+ * \class SnakeParametersPreviewPipeline
+ * \brief A pipeline used to preview snake parameters.
+ * 
+ * Given a set of control points an image, and some snake parameters, this
+ * class computes a b-spline curve based on those control points, creates a
+ * level set embedding of the curve, and computes various level set evolution
+ * forces acting on the curve.
+ */
+class SnakeParametersPreviewPipeline
+{
+public:
+  SnakeParametersPreviewPipeline(GlobalState *state);
+  virtual ~SnakeParametersPreviewPipeline();
+
+  // Images used by this class (internally and externally)
+  typedef itk::Image<unsigned char, 2> CharImageType;
+  typedef itk::Image<float, 2> FloatImageType;
+  typedef itk::Image<short, 2> ShortImageType;
+
+  // Define a color image for display
+  typedef itk::RGBAPixel<unsigned char> DisplayPixelType;
+  typedef itk::Image<DisplayPixelType,2> DisplayImageType;
+
+  // Index type used to refer to pixels
+  typedef FloatImageType::IndexType IndexType;
+
+  // Force types
+  enum ForceType {CURVATURE=0, ADVECTION, PROPAGATION, TOTAL };
+  
+  // A sample from the curve
+  struct SampledPoint {
+    // The geometry of the point
+    double t;
+    Vector2d x;
+    Vector2d n;
+    double kappa;
+    
+    // The forces acting on the point
+    double PropagationForce;
+    double CurvatureForce;
+    double AdvectionForce;
+    
+    double operator[](unsigned int i) const
+      { return x[i]; } 
+  };
+
+  // Various list types
+  typedef std::vector<Vector2d> ControlPointList;
+  typedef std::vector<Vector2d> LevelSetContourType;
+  typedef std::vector<SampledPoint> SampledPointList;  
+
+  /** Set the speed image */
+  void SetSpeedImage(ShortImageType *image);
+
+  /** Set the snake parameters */
+  void SetSnakeParameters(const SnakeParameters &parameters);
+
+  /** Set the control points of the interface curve */
+  void SetControlPoints(const ControlPointList &points);
+
+  /** Change just one control point, with an option of changing it
+   * quickly, ie, not recomputing the level set, only the curve */
+  void ChangeControlPoint(unsigned int index, const Vector2d &point,
+    bool quickUpdate);
+
+  /** Set the number of points sampled for display of the curve */
+  void SetNumberOfSampledPoints(unsigned int number);
+  
+  /** Update the internals of the pipeline and compute the curve and the
+   * force points.  This method requires a GL context because it relies on
+   * GL tesselation code for generating an image from the curve */
+  void Update();
+
+  /** Get the speed image */
+  irisGetMacro(SpeedImage, ShortImageType *);
+  
+  /** Get a reference to the control points of the interface curve */
+  irisGetMacro(ControlPoints,const ControlPointList &);
+
+  /** Get a list of densely interpolated points on the curve (for drawing) */
+  irisGetMacro(SampledPoints,const SampledPointList &);
+
+  /** Get the demo loop contour */
+  std::vector<Vector2d> &GetDemoLoopContour();
+
+  /** Get the color image corresponding to the speed image */
+  DisplayImageType *GetDisplayImage()  
+    { return m_DisplayMapper->GetOutput(); }
+
+  /** Set the idle callback function that FLTK should call in demo mode */
+  void AnimationCallback();
+
+  /** Have the animation restart on the next callback */
+  void AnimationRestart();
+
+private:
+
+  /** The global state */
+  GlobalState *m_GlobalState;
+      
+  /** The speed image */
+  itk::SmartPointer<ShortImageType> m_SpeedImage;
+
+  // Gradient image used by this component
+  typedef itk::CovariantVector<float,2> VectorType;
+  typedef itk::Image<VectorType,2> VectorImageType;
+  typedef itk::SmartPointer<VectorImageType> VectorImagePointer;
+  
+  /** The grandient of the speed image */
+  VectorImagePointer m_GradientImage;
+  
+  /** A set of snake parameters */
+  SnakeParameters m_Parameters;
+    
+  /** A list of control points */
+  ControlPointList m_ControlPoints;
+  
+  /** Number of points to sample from the curve */
+  unsigned int m_NumberOfSampledPoints;
+
+  /** A list of sampled points */
+  SampledPointList m_SampledPoints;
+
+  // Flags indicating which part of the pipeline should be refreshed
+  bool m_ControlsModified;
+  bool m_SpeedModified;
+  bool m_ParametersModified;
+  bool m_QuickUpdate;
+    
+  // Internal components of the Update method
+  void UpdateLevelSetFunction();
+  void UpdateContour();
+  void UpdateLevelSet();
+  void UpdateForces();
+
+  // A filter used to convert the speed image to a color image to display on the screen
+  class SimpleColorMapFunctor
+  {
+  public:
+    ColorMap::RGBAType operator()(short in)
+      {
+      float t = (in - m_SpeedMin) / (m_SpeedMax - m_SpeedMin);
+      return m_ColorMap->MapIndexToRGBA(t);
+      }
+    SimpleColorMapFunctor()
+    {
+      m_ColorMap = ColorMap::New();
+      m_ColorMap->SetToSystemPreset(ColorMap::COLORMAP_SPEED);
+      SpeedImageWrapperTraits::GetFixedIntensityRange(m_SpeedMin, m_SpeedMax);
+    }
+  private:
+    SmartPtr<ColorMap> m_ColorMap;
+    float m_SpeedMin, m_SpeedMax;
+  };
+
+  typedef itk::UnaryFunctorImageFilter<
+    ShortImageType,DisplayImageType,SimpleColorMapFunctor> IntensityFilterType;
+  typedef itk::SmartPointer<IntensityFilterType> IntensityFilterPointer;
+  IntensityFilterPointer m_DisplayMapper;
+
+  // Demo loop object
+  LevelSetPreview2d *m_DemoLoop;
+};
+
+
+#endif // __SnakeParametersPreviewPipeline_h_
diff --git a/Logic/Mesh/GuidedMeshIO.cxx b/Logic/Mesh/GuidedMeshIO.cxx
index 5786091..ffa61b8 100644
--- a/Logic/Mesh/GuidedMeshIO.cxx
+++ b/Logic/Mesh/GuidedMeshIO.cxx
@@ -11,6 +11,7 @@ GuidedMeshIO
   m_EnumFileFormat.AddPair(FORMAT_VTK, "VTK Mesh");
   m_EnumFileFormat.AddPair(FORMAT_BYU, "BYU Mesh");
   m_EnumFileFormat.AddPair(FORMAT_STL, "STL Mesh"); 
+  m_EnumFileFormat.AddPair(FORMAT_VRML, "VRML Scene");
   m_EnumFileFormat.AddPair(FORMAT_COUNT, "INVALID FORMAT");
 }
 
@@ -39,7 +40,7 @@ GuidedMeshIO
   if(format == FORMAT_VTK)
     {
     vtkPolyDataWriter *writer = vtkPolyDataWriter::New();
-    writer->SetInput(mesh);
+    writer->SetInputData(mesh);
     writer->SetFileName(FileName);
     writer->Update();
     writer->Delete();
@@ -48,8 +49,8 @@ GuidedMeshIO
     {
     vtkTriangleFilter *tri = vtkTriangleFilter::New();
     vtkSTLWriter *writer = vtkSTLWriter::New();
-    tri->SetInput(mesh);
-    writer->SetInput(tri->GetOutput());
+    tri->SetInputData(mesh);
+    writer->SetInputConnection(tri->GetOutputPort());
     writer->SetFileName(FileName);
     writer->Update();
     writer->Delete();
@@ -59,9 +60,9 @@ GuidedMeshIO
     {
     vtkTriangleFilter *tri = vtkTriangleFilter::New();
     vtkBYUWriter *writer = vtkBYUWriter::New();
-    tri->SetInput(mesh);
-    writer->SetInput(tri->GetOutput());
-    writer->SetFileName(FileName);
+    tri->SetInputData(mesh);
+    writer->SetInputConnection(tri->GetOutputPort());
+    writer->SetGeometryFileName(FileName);
     writer->Update();
     writer->Delete();
     tri->Delete();
diff --git a/Logic/Mesh/GuidedMeshIO.h b/Logic/Mesh/GuidedMeshIO.h
index a471dd3..e2d9247 100644
--- a/Logic/Mesh/GuidedMeshIO.h
+++ b/Logic/Mesh/GuidedMeshIO.h
@@ -58,7 +58,7 @@ public:
   virtual ~GuidedMeshIO() { /*To avoid compiler warning.*/ }
   
   enum FileFormat {
-    FORMAT_VTK=0, FORMAT_STL, FORMAT_BYU, FORMAT_COUNT };
+    FORMAT_VTK=0, FORMAT_STL, FORMAT_BYU, FORMAT_VRML, FORMAT_COUNT };
 
   /** Default constructor */
   GuidedMeshIO();
diff --git a/Logic/Mesh/IRISMeshPipeline.cxx b/Logic/Mesh/IRISMeshPipeline.cxx
deleted file mode 100644
index 6516259..0000000
--- a/Logic/Mesh/IRISMeshPipeline.cxx
+++ /dev/null
@@ -1,211 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: IRISMeshPipeline.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/06/28 18:45:08 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-// Borland compiler is very lazy so we need to instantiate the template
-//  by hand 
-#if defined(__BORLANDC__)
-#include "SNAPBorlandDummyTypes.h"
-#endif
-
-#include "IRISMeshPipeline.h"
-
-// SNAP includes
-#include "IRISVectorTypesToITKConversion.h"
-#include "VTKMeshPipeline.h"
-
-// ITK includes
-#include "itkRegionOfInterestImageFilter.h"
-#include "itkBinaryThresholdImageFilter.h"
-#include "itkImageRegionConstIteratorWithIndex.h"
-
-using namespace std;
-
-IRISMeshPipeline
-::IRISMeshPipeline()
-{
-  // Initialize the region of interest filter
-  m_ROIFilter = ROIFilter::New();
-  m_ROIFilter->ReleaseDataFlagOn();
-
-  // Define the binary thresholding filter that will map the image onto the 
-  // range -1 to 1
-  m_ThrehsoldFilter = ThresholdFilter::New();
-  m_ThrehsoldFilter->SetInput(m_ROIFilter->GetOutput());
-  m_ThrehsoldFilter->ReleaseDataFlagOn();
-  m_ThrehsoldFilter->SetInsideValue(1.0f);
-  m_ThrehsoldFilter->SetOutsideValue(-1.0f);
-
-  // Initialize the VTK Processing Pipeline
-  m_VTKPipeline = new VTKMeshPipeline();
-  m_VTKPipeline->SetImage(m_ThrehsoldFilter->GetOutput());
-}
-
-IRISMeshPipeline
-::~IRISMeshPipeline()
-{
-  delete m_VTKPipeline;
-}
-
-void
-IRISMeshPipeline
-::SetMeshOptions(const MeshOptions &options)
-{
-  // Store the options
-  m_MeshOptions = options;
-
-  // Apply the options to the internal pipeline
-  m_VTKPipeline->SetMeshOptions(m_MeshOptions);
-}
-
-unsigned long
-IRISMeshPipeline
-::ComputeBoundingBoxes()
-{
-  unsigned int i;
-  unsigned long nTotalVoxels = 0;
-
-  // Get the dimensions of the image
-  InputImageType::SizeType size = 
-    m_InputImage->GetLargestPossibleRegion().GetSize();
-
-  // These vectors represent the extents of the image.  
-  Vector3l extLower(0l);
-  Vector3l extUpper = 
-    Vector3l(reinterpret_cast<const long *>(size.GetSize())) - Vector3l(1l);
-
-  // For each intensity present in the image, we will compute a bounding
-  // box.  Intialize a list of bounding boxes with 'inverted' boxes
-  Vector3l bbMin[MAX_COLOR_LABELS];
-  Vector3l bbMax[MAX_COLOR_LABELS];
-
-  // Initialize the histogram and bounding boxes
-  for(i=1;i<MAX_COLOR_LABELS;i++)
-    {
-    m_Histogram[i] = 0l;
-    bbMin[i] = extUpper;
-    bbMax[i] = extLower;
-    }
-
-  // Create an iterator for parsing the image
-  typedef itk::ImageRegionConstIteratorWithIndex<InputImageType> InputIterator;
-  InputIterator it(m_InputImage,m_InputImage->GetLargestPossibleRegion());
-
-  // Parse through the image using an iterator and compute the bounding boxes
-  for(it.GoToBegin();!it.IsAtEnd();++it)
-    {
-    // Get the intensity at current pixel
-    LabelType label = it.Value();
-
-    // For non-zero labels, compute the bounding box
-    if(label != 0)
-      {
-      // Increment the histogram
-      m_Histogram[label]++;
-
-      // Get the current image index
-      Vector3l point(it.GetIndex().GetIndex());
-
-      // Update the bounding box extents
-      bbMin[label] = vector_min(bbMin[label],point);
-      bbMax[label] = vector_max(bbMax[label],point);        
-      }
-    }
-
-  // Convert the bounding box to a region
-  for(i=1;i<MAX_COLOR_LABELS;i++)
-    {
-    Vector3l bbSize = Vector3l(1l) + bbMax[i] - bbMin[i];
-    m_BoundingBox[i].SetSize(to_itkSize(bbSize));
-    m_BoundingBox[i].SetIndex(to_itkIndex(bbMin[i]));
-    nTotalVoxels += m_BoundingBox[i].GetNumberOfPixels();
-    }  
-
-  return nTotalVoxels;
-}
-
-unsigned long
-IRISMeshPipeline
-::GetVoxelsInBoundingBox(LabelType label) const
-{
-  return m_BoundingBox[label].GetNumberOfPixels();
-}
-
-AllPurposeProgressAccumulator *
-IRISMeshPipeline
-::GetProgressAccumulator()
-{
-  return m_VTKPipeline->GetProgressAccumulator();
-}
-  
-
-#include <ctime>
-
-bool
-IRISMeshPipeline
-::ComputeMesh(LabelType label, vtkPolyData *outMesh)
-{
-  // The label must be present in the image
-  if(m_Histogram[label] == 0)
-    return false;
-
-  // TODO: make this more elegant
-  InputImageType::RegionType bbWiderRegion = m_BoundingBox[label];
-  bbWiderRegion.PadByRadius(5);
-  bbWiderRegion.Crop(m_InputImage->GetLargestPossibleRegion()); 
-
-  // Pass the region to the ROI filter and propagate the filter
-  m_ROIFilter->SetInput(m_InputImage);
-  m_ROIFilter->SetRegionOfInterest(bbWiderRegion);
-  m_ROIFilter->Update();
-  
-  // Set the parameters for the thresholding filter
-  m_ThrehsoldFilter->SetLowerThreshold(label);
-  m_ThrehsoldFilter->SetUpperThreshold(label);
-  m_ThrehsoldFilter->UpdateLargestPossibleRegion();
-
-  // Graft the polydata to the last filter in the pipeline
-  m_VTKPipeline->SetImage(m_ThrehsoldFilter->GetOutput());
-  m_VTKPipeline->ComputeMesh(outMesh);
-
-  // Done
-  return true;
-}
-
-void 
-IRISMeshPipeline
-::SetImage(IRISMeshPipeline::InputImageType *image)
-{
-  m_InputImage = image;
-}
-
diff --git a/Logic/Mesh/IRISMeshPipeline.h b/Logic/Mesh/IRISMeshPipeline.h
deleted file mode 100644
index cf885ed..0000000
--- a/Logic/Mesh/IRISMeshPipeline.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: IRISMeshPipeline.h,v $
-  Language:  C++
-  Date:      $Date: 2009/01/23 20:09:38 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __IRISMeshPipeline_h_
-#define __IRISMeshPipeline_h_
-
-#include "SNAPCommon.h"
-#include "itkImageRegion.h"
-#include "itkSmartPointer.h"
-#include "MeshOptions.h"
-
-// Forward reference to itk classes
-namespace itk {
-  template <class TPixel,unsigned int VDimension> class OrientedImage;
-  template <class TInputImage, class TOutputImage> class RegionOfInterestImageFilter;
-  template <class TInputImage, class TOutputImage> class BinaryThresholdImageFilter;
-}
-
-// Forward references
-class VTKMeshPipeline;
-class vtkPolyData;
-class AllPurposeProgressAccumulator;
-
-/**
- * \class IRISMeshPipeline
- * \brief A small pipeline used to convert a segmentation image to a mesh in IRIS.
- *
- * This pipeline preprocesses each label in the segmentation image by blurring it.
- */
-class IRISMeshPipeline 
-{
-public:
-  /** Input image type */
-  typedef itk::OrientedImage<LabelType,3> InputImageType;
-  typedef itk::SmartPointer<InputImageType> InputImagePointer;
-  
-  /** Set the input segmentation image */
-  void SetImage(InputImageType *input);
-
-  /** Compute the bounding boxes for different regions.  Prerequisite for 
-   * calling ComputeMesh(). Returns the total number of voxels in all boxes */
-  unsigned long ComputeBoundingBoxes();
-
-  unsigned long GetVoxelsInBoundingBox(LabelType label) const;
-
-  /** Set the mesh options for this filter */
-  void SetMeshOptions(const MeshOptions &options);
-
-  /** Can we compute a mesh for this label? */
-  bool CanComputeMesh(LabelType label)
-  {
-    return m_Histogram[label] > 0l;
-  }
-
-  /** Compute a mesh for a particular color label.  Returns true if 
-   * the color label is not present in the image */
-  bool ComputeMesh(LabelType label, vtkPolyData *outData);
-  
-  /** Constructor, which builds the pipeline */
-  IRISMeshPipeline();
-
-  /** Deallocate the pipeline filters */
-  ~IRISMeshPipeline();
-
-  /** Get the progress accumulator from the VTK mesh pipeline */
-  AllPurposeProgressAccumulator *GetProgressAccumulator();
-
-private:
-  // Type definitions for the various filters used by this object
-  typedef itk::OrientedImage<float,3>                InternalImageType;
-  typedef itk::SmartPointer<InternalImageType>       InternalImagePointer;
-  
-  typedef itk::RegionOfInterestImageFilter<
-    InputImageType,InputImageType>                   ROIFilter;
-  typedef itk::SmartPointer<ROIFilter>               ROIFilterPointer;
-  
-  typedef itk::BinaryThresholdImageFilter<
-    InputImageType,InternalImageType>                ThresholdFilter;
-  typedef itk::SmartPointer<ThresholdFilter>         ThresholdFilterPointer;
-  
-  // Current set of mesh options
-  MeshOptions                 m_MeshOptions;
-
-  // The input image
-  InputImagePointer           m_InputImage;
-
-  // The ROI extraction filter used for constructing a bounding box
-  ROIFilterPointer            m_ROIFilter;
-
-  // The thresholding filter used to map intensity in the bounding box to
-  // standardized range
-  ThresholdFilterPointer      m_ThrehsoldFilter;
-
-  // Set of bounding boxes
-  itk::ImageRegion<3>         m_BoundingBox[MAX_COLOR_LABELS];
-
-  // Histogram of the image
-  long                        m_Histogram[MAX_COLOR_LABELS];
-
-  // The VTK pipeline
-  VTKMeshPipeline *           m_VTKPipeline;
-};
-
-#endif
diff --git a/Logic/Mesh/LevelSetMeshPipeline.cxx b/Logic/Mesh/LevelSetMeshPipeline.cxx
index a517270..13af092 100644
--- a/Logic/Mesh/LevelSetMeshPipeline.cxx
+++ b/Logic/Mesh/LevelSetMeshPipeline.cxx
@@ -40,6 +40,7 @@
 
 #include "LevelSetMeshPipeline.h"
 #include "VTKMeshPipeline.h"
+#include "MeshOptions.h"
 
 LevelSetMeshPipeline
 ::LevelSetMeshPipeline()
@@ -47,8 +48,10 @@ LevelSetMeshPipeline
   // Initialize the VTK Exporter
   m_VTKPipeline = new VTKMeshPipeline();
 
-  // Initialize the options
-  SetMeshOptions(m_MeshOptions);
+  // Create the mesh options
+  m_MeshOptions = MeshOptions::New();
+  m_MeshOptions->SetUseGaussianSmoothing(false);
+  m_VTKPipeline->SetMeshOptions(m_MeshOptions);
 }
 
 LevelSetMeshPipeline
@@ -59,24 +62,37 @@ LevelSetMeshPipeline
 
 void
 LevelSetMeshPipeline
-::SetMeshOptions(const MeshOptions &options)
+::SetMeshOptions(const MeshOptions *options)
 {
-  // Store the options
-  m_MeshOptions = options;
+  if(*m_MeshOptions != *options)
+    {
+    // Copy the options
+    m_MeshOptions->DeepCopy(options);
 
-  // Turn of the Gaussian smoothing
-  m_MeshOptions.SetUseGaussianSmoothing(false);
+    // Turn of the Gaussian smoothing
+    m_MeshOptions->SetUseGaussianSmoothing(false);
 
-  // Apply the options to the internal pipeline
-  m_VTKPipeline->SetMeshOptions(m_MeshOptions);
+    // Apply the options to the internal pipeline
+    m_VTKPipeline->SetMeshOptions(m_MeshOptions);
+    }
 }
 
 void
 LevelSetMeshPipeline
-::ComputeMesh(vtkPolyData *outMesh)
+::UpdateMesh(itk::FastMutexLock *lock)
 {
+  // We need to generate a new mesh object. Otherwise, if there is concurrent
+  // rendering and mesh computation, the mesh would be accessed by two threads
+  // at the same time, which is a problem.
+  m_Mesh = vtkSmartPointer<vtkPolyData>::New();
+
   // Run the pipeline
-  m_VTKPipeline->ComputeMesh(outMesh);
+  m_VTKPipeline->ComputeMesh(m_Mesh, lock);
+}
+
+vtkPolyData *LevelSetMeshPipeline::GetMesh()
+{
+  return m_Mesh;
 }
 
 void 
diff --git a/Logic/Mesh/LevelSetMeshPipeline.h b/Logic/Mesh/LevelSetMeshPipeline.h
index 1c3fcc9..a25abb2 100644
--- a/Logic/Mesh/LevelSetMeshPipeline.h
+++ b/Logic/Mesh/LevelSetMeshPipeline.h
@@ -37,14 +37,18 @@
 
 #include "SNAPCommon.h"
 #include "itkSmartPointer.h"
-#include "MeshOptions.h"
+#include "vtkSmartPointer.h"
+#include "itkObject.h"
+#include "itkObjectFactory.h"
 
 // Forward reference to itk classes
 namespace itk {
-  template <class TPixel,unsigned int VDimension> class OrientedImage;
+  template <class TPixel,unsigned int VDimension> class Image;
+  class FastMutexLock;
 }
 
 // Forward reference to our own VTK pipeline
+class MeshOptions;
 class VTKMeshPipeline;
 class vtkPolyData;
 
@@ -55,21 +59,32 @@ class vtkPolyData;
  * This pipeline takes a floating point image computed by the level
  * set filter and uses a contour algorithm to get a triangular mesh
  */
-class LevelSetMeshPipeline
+class LevelSetMeshPipeline : public itk::Object
 {
 public:  
+
+  irisITKObjectMacro(LevelSetMeshPipeline, itk::Object)
+
   /** Input image type */
-  typedef itk::OrientedImage<float,3> InputImageType;
+  typedef itk::Image<float,3> InputImageType;
   typedef itk::SmartPointer<InputImageType> InputImagePointer;
 
   /** Set the input segmentation image */
   void SetImage(InputImageType *input);
 
   /** Set the mesh options for this filter */
-  void SetMeshOptions(const MeshOptions &options);
+  void SetMeshOptions(const MeshOptions *options);
+
+  /** Compute the mesh for the segmentation level set. An optional pointer
+      to a mutex lock can be provided. If passed in, the portion of the code
+      where the image data is accessed will be locked. This is to prevent mesh
+      update clashing with level set evolution iteration. */
+  void UpdateMesh(itk::FastMutexLock *lock = NULL);
 
-  /** Compute the mesh for the segmentation level set */
-  void ComputeMesh(vtkPolyData *outData);
+  /** Get the stored mesh */
+  vtkPolyData *GetMesh();
+
+protected:
   
   /** Constructor, which builds the pipeline */
   LevelSetMeshPipeline();
@@ -83,13 +98,16 @@ private:
   typedef itk::SmartPointer<InternalImageType> InternalImagePointer;
   
   // Current set of mesh options
-  MeshOptions m_MeshOptions;
+  SmartPtr<MeshOptions> m_MeshOptions;
 
   // The input image
   InputImagePointer m_InputImage;
 
   // The VTK pipeline
   VTKMeshPipeline *m_VTKPipeline;
+
+  // The output mesh
+  vtkSmartPointer<vtkPolyData> m_Mesh;
 };
 
 #endif //__LevelSetMeshPipeline_h_
diff --git a/UserInterface/MeshIOWizard/MeshExportSettings.h b/Logic/Mesh/MeshExportSettings.h
similarity index 100%
rename from UserInterface/MeshIOWizard/MeshExportSettings.h
rename to Logic/Mesh/MeshExportSettings.h
diff --git a/Logic/Mesh/MeshManager.cxx b/Logic/Mesh/MeshManager.cxx
new file mode 100644
index 0000000..3bbf847
--- /dev/null
+++ b/Logic/Mesh/MeshManager.cxx
@@ -0,0 +1,443 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: MeshManager.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/06/28 18:45:08 $
+  Version:   $Revision: 1.4 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+// Borland compiler is very lazy so we need to instantiate the template
+//  by hand 
+#if defined(__BORLANDC__)
+#include "SNAPBorlandDummyTypes.h"
+#endif
+#include "MeshManager.h"
+
+#include "SNAPOpenGL.h"
+
+// SNAP Includes
+#include "ColorLabel.h"
+#include "GlobalState.h"
+#include "ImageWrapper.h"
+#include "IRISException.h"
+#include "IRISApplication.h"
+#include "MultiLabelMeshPipeline.h"
+#include "LevelSetMeshPipeline.h"
+#include "IRISVectorTypesToITKConversion.h"
+#include "IRISImageData.h"
+#include "SNAPImageData.h"
+#include "AllPurposeProgressAccumulator.h"
+#include "MeshOptions.h"
+
+// ITK includes
+#include "itkRegionOfInterestImageFilter.h"
+#include "itkBinaryThresholdImageFilter.h"
+#include "itkDiscreteGaussianImageFilter.h"
+#include "itkImageRegionConstIteratorWithIndex.h"
+#include "itkRecursiveGaussianImageFilter.h"
+#include "itkVTKImageExport.h"
+
+// VTK includes
+#include <vtkCellArray.h>
+#include <vtkDecimatePro.h>
+#include <vtkImageData.h>
+#include <vtkImageImport.h>
+#include <vtkImageGaussianSmooth.h>
+#include <vtkContourFilter.h>
+#include <vtkImageThreshold.h>
+#include <vtkImageToStructuredPoints.h>
+#include <vtkPointData.h>
+#include <vtkPolyData.h>
+#include <vtkSmoothPolyDataFilter.h>
+#include <vtkStripper.h>
+
+// System includes
+#include <cstdlib>
+
+using namespace std;
+
+MeshManager
+::MeshManager()
+{
+  m_Progress = AllPurposeProgressAccumulator::New();
+  m_BuildTime = 0;
+}
+
+MeshManager
+::~MeshManager()
+{
+}
+
+void 
+MeshManager
+::Initialize(IRISApplication *driver)
+{
+  m_Driver = driver;
+  m_GlobalState = m_Driver->GetGlobalState();  
+}
+
+void 
+MeshManager
+::UpdateVTKMeshes(itk::Command *command)
+{
+  if(!m_Driver->GetCurrentImageData()->IsSegmentationLoaded())
+    return;
+
+  // The mesh is constructed differently depending on whether there is an
+  // actively evolving level set or not SNAP mode or in IRIS mode
+  if (m_Driver->IsSnakeModeLevelSetActive())
+    {    
+    // Get the mesh pipeline associated with the level set image wrapper
+    LevelSetImageWrapper *wrapper = m_Driver->GetSNAPImageData()->GetSnake();
+    SmartPtr<LevelSetMeshPipeline> pipeline =
+        static_cast<LevelSetMeshPipeline *>(wrapper->GetUserData("MeshPipeline"));
+
+    // TODO: this feels kind of awkward here
+    if(!wrapper->GetImage() || !Is3DProper(wrapper->GetImage()))
+      return;
+
+    // If the pipeline does not exist, create it
+    if(!pipeline)
+      {
+      pipeline = LevelSetMeshPipeline::New();
+      wrapper->SetUserData("MeshPipeline", pipeline);
+      }
+
+    // Make sure the pipeline has the right image
+    pipeline->SetImage(wrapper->GetImage());
+
+    // Make sure the pipeline has the right options
+    pipeline->SetMeshOptions(m_GlobalState->GetMeshOptions());
+
+    // Compute the mesh only for the current segmentation color
+    pipeline->UpdateMesh(m_Driver->GetSNAPImageData()->GetLevelSetPipelineMutexLock());
+    }
+  else
+    {
+    // Get the mesh pipeline associated with the level set image wrapper
+    LabelImageWrapper *wrapper = m_Driver->GetCurrentImageData()->GetSegmentation();
+    SmartPtr<MultiLabelMeshPipeline> pipeline =
+        static_cast<MultiLabelMeshPipeline *>(wrapper->GetUserData("MeshPipeline"));
+
+    // TODO: this feels kind of awkward here
+    if(!wrapper->GetImage() || !Is3DProper(wrapper->GetImage()))
+      return;
+
+    // If the pipeline does not exist, create it
+    if(!pipeline)
+      {
+      pipeline = MultiLabelMeshPipeline::New();
+      wrapper->SetUserData("MeshPipeline", pipeline);
+      }
+
+    // Make sure the pipeline has the right image
+    pipeline->SetImage(wrapper->GetImage());
+
+      // Pass the options to the pipeline
+    pipeline->SetMeshOptions(m_GlobalState->GetMeshOptions());
+
+    // Update the meshes
+    pipeline->UpdateMeshes(command);
+    }
+
+  // Invoke a modified event (?)
+  this->Modified();
+
+  // Record the time that the mesh was built
+  m_BuildTime = this->GetMTime();
+}
+
+MeshManager::MeshCollection MeshManager::GetMeshes()
+{
+  MeshCollection meshes;
+
+  if (m_Driver->IsSnakeModeLevelSetActive())
+    {
+    // Get the mesh pipeline associated with the level set image wrapper
+    LevelSetImageWrapper *wrapper = m_Driver->GetSNAPImageData()->GetSnake();
+    SmartPtr<LevelSetMeshPipeline> pipeline =
+        static_cast<LevelSetMeshPipeline *>(wrapper->GetUserData("MeshPipeline"));
+
+    // TODO: this feels kind of awkward here
+    if(!wrapper->GetImage() || !Is3DProper(wrapper->GetImage()))
+      return meshes;
+
+    if(pipeline)
+      {
+      meshes[m_Driver->GetGlobalState()->GetDrawingColorLabel()] = pipeline->GetMesh();
+      return meshes;
+      }
+    }
+  else if(m_Driver->GetCurrentImageData()->IsSegmentationLoaded())
+    {
+    // Get the mesh pipeline associated with the level set image wrapper
+    LabelImageWrapper *wrapper = m_Driver->GetCurrentImageData()->GetSegmentation();
+    SmartPtr<MultiLabelMeshPipeline> pipeline =
+        static_cast<MultiLabelMeshPipeline *>(wrapper->GetUserData("MeshPipeline"));
+
+    // TODO: this feels kind of awkward here
+    if(!wrapper->GetImage() || !Is3DProper(wrapper->GetImage()))
+      return meshes;
+
+    if(pipeline)
+      {
+      return pipeline->GetMeshCollection();
+      }
+    }
+
+  return meshes;
+}
+
+bool MeshManager::IsMeshDirty()
+{
+  // If there is no image loaded, the mesh is not considered dirty
+  if(!m_Driver->IsMainImageLoaded())
+    return false;
+
+  // Image base
+  itk::ImageBase<3> *image = NULL;
+
+  // Get the appropriate source image
+  if(m_Driver->IsSnakeModeLevelSetActive())
+    {
+    // We are in SNAP.  Use one of SNAP's images
+    SNAPImageData *snapData = m_Driver->GetSNAPImageData();
+    image = snapData->GetSnake()->GetImage();
+    }
+  else
+    {
+    image = m_Driver->GetCurrentImageData()->GetSegmentation()->GetImageBase();
+    }
+
+  // Compare the timestamps
+  if(image->GetMTime() > this->m_BuildTime)
+    return true;
+
+  // Also check if the mesh options have been modified since
+  if(m_Driver->GetGlobalState()->GetMeshOptions()->GetMTime() > this->m_BuildTime)
+    return true;
+
+  return false;
+}
+
+
+/*
+ *  Apply color label, a shorthand
+ */
+bool 
+MeshManager
+::ApplyColorLabel(const ColorLabel &label) 
+{
+  if (label.IsVisible() && label.IsVisibleIn3D()) 
+    {
+    // Adjust the label color to reduce the saturation. This in necessary
+    // in order to see the highlights on the object
+    double r = 0.75 * (label.GetRGB(0) / 255.0);
+    double g = 0.75 * (label.GetRGB(1) / 255.0);
+    double b = 0.75 * (label.GetRGB(2) / 255.0);
+    double a = label.GetAlpha() / 255.0;
+
+    if (label.IsOpaque()) glColor3d(r, g, b); 
+    else glColor4d(r, g, b, a);
+  
+    return true;
+    }
+  return false;
+}
+
+
+bool MeshManager
+::Is3DProper(const itk::ImageBase<3> * apImage) const {
+    
+    const itk::ImageBase<3>::RegionType region = apImage->GetLargestPossibleRegion();
+    itk::ImageBase<3>::SizeType size = region.GetSize();
+    if((size[0] <= 1) || (size[0] <= 1) || (size[2] <= 1))
+        return(false);
+    return(true);
+}
+
+/*
+ *$Log: MeshManager.cxx,v $
+ *Revision 1.4  2010/06/28 18:45:08  pyushkevich
+ *Patch from Michael Hanke to allow ITK 3.18 builds
+ *
+ *Revision 1.3  2007/12/30 04:05:15  pyushkevich
+ *GPL License
+ *
+ *Revision 1.2  2007/05/10 20:19:50  pyushkevich
+ *Added VTK mesh export code and GUI
+ *
+ *Revision 1.1  2006/12/02 04:22:14  pyushkevich
+ *Initial sf checkin
+ *
+ *Revision 1.1.1.1  2006/09/26 23:56:18  pauly2
+ *Import
+ *
+ *Revision 1.19  2005/12/08 18:20:45  hjohnson
+ *COMP:  Removed compiler warnings from SGI/linux/MacOSX compilers.
+ *
+ *Revision 1.18  2005/11/23 14:32:15  ibanez
+ *BUG: 2404. Patch provided by Paul Yushkevish.
+ *
+ *Revision 1.17  2005/10/29 14:00:14  pauly
+ *ENH: SNAP enhacements like color maps and progress bar for 3D rendering
+ *
+ *Revision 1.16  2005/04/21 14:46:29  pauly
+ *ENH: Improved management and editing of color labels in SNAP
+ *
+ *Revision 1.15  2004/09/14 14:11:09  pauly
+ *ENH: Added an activation manager to main UI class, improved snake code, various UI fixes and additions
+ *
+ *Revision 1.14  2004/08/26 19:43:23  pauly
+ *ENH: Moved the Borland code into Common folder
+ *
+ *Revision 1.13  2004/08/03 23:26:32  ibanez
+ *ENH: Modification for building in multple platforms. By Julien Jomier.
+ *
+ *Revision 1.12  2004/07/29 14:01:56  pauly
+ *ENH: An interface for changing SNAP appearance settings
+ *
+ *Revision 1.11  2004/01/27 17:34:00  pauly
+ *FIX: Compiling on Mac OSX, issue with GLU include file
+ *
+ *Revision 1.10  2004/01/20 00:17:42  pauly
+ *FIX: VTK float compatibility
+ *
+ *Revision 1.9  2004/01/17 18:39:07  lorensen
+ *ENH: changes to accomodate VTK api changes.
+ *
+ *Revision 1.8  2003/10/09 22:45:13  pauly
+ *EMH: Improvements in 3D functionality and snake parameter preview
+ *
+ *Revision 1.7  2003/10/02 14:54:53  pauly
+ *ENH: Development during the September code freeze
+ *
+ *Revision 1.1  2003/09/11 13:50:29  pauly
+ *FIX: Enabled loading of images with different orientations
+ *ENH: Implemented image save and load operations
+ *
+ *Revision 1.5  2003/08/28 14:37:09  pauly
+ *FIX: Clean 'unused parameter' and 'static keyword' warnings in gcc.
+ *FIX: Label editor repaired
+ *
+ *Revision 1.4  2003/08/27 14:03:21  pauly
+ *FIX: Made sure that -Wall option in gcc generates 0 warnings.
+ *FIX: Removed 'comment within comment' problem in the cvs log.
+ *
+ *Revision 1.3  2003/08/27 04:57:46  pauly
+ *FIX: A large number of bugs has been fixed for 1.4 release
+ *
+ *Revision 1.2  2003/08/14 13:37:07  pauly
+ *FIX: Error with using int instead of vtkIdType in calling vtkCellArray::GetNextCell
+ *
+ *Revision 1.1  2003/07/12 04:52:25  pauly
+ *Initial checkin of SNAP application  to the InsightApplications tree
+ *
+ *Revision 1.2  2003/07/12 01:34:18  pauly
+ *More final changes before ITK checkin
+ *
+ *Revision 1.1  2003/07/11 23:29:17  pauly
+ **** empty log message ***
+ *
+ *Revision 1.10  2003/07/11 21:25:12  pauly
+ *Code cleanup for ITK checkin
+ *
+ *Revision 1.9  2003/07/10 14:30:26  pauly
+ *Integrated ITK into SNAP level set segmentation
+ *
+ *Revision 1.8  2003/06/08 16:11:42  pauly
+ *User interface changes
+ *Automatic mesh updating in SNAP mode
+ *
+ *Revision 1.7  2003/05/12 02:51:10  pauly
+ *Got code to compile on UNIX
+ *
+ *Revision 1.6  2003/05/05 12:30:18  pauly
+ **** empty log message ***
+ *
+ *Revision 1.5  2003/04/29 14:01:42  pauly
+ *Charlotte Trip
+ *
+ *Revision 1.4  2003/04/23 20:36:23  pauly
+ **** empty log message ***
+ *
+ *Revision 1.3  2003/04/23 06:05:18  pauly
+ **** empty log message ***
+ *
+ *Revision 1.2  2003/04/18 17:32:18  pauly
+ **** empty log message ***
+ *
+ *Revision 1.1  2003/03/07 19:29:47  pauly
+ *Initial checkin
+ *
+ *Revision 1.2  2002/12/16 16:40:19  pauly
+ **** empty log message ***
+ *
+ *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
+ *Started the project repository
+ *
+ *
+ *Revision 1.11  2002/05/08 17:34:18  moon
+ *Fixed bug of using the voxel snake image, instead of hte float snake state,
+ *for the marching cubes. Now the snake looks smooth instead of voxelized.
+ *
+ *Revision 1.10  2002/04/27 18:30:22  moon
+ *Finished commenting
+ *
+ *Revision 1.9  2002/04/27 17:49:00  bobkov
+ *Added comments
+ *
+ *Revision 1.8  2002/04/24 17:12:48  bobkov
+ *modified display() method so that when num_lists is zero
+ *the 3D window does not show anything
+ *
+ *Revision 1.7  2002/04/23 19:30:10  bobkov
+ *modified display method so that the current color label is
+ *used in the snake 3d window
+ *
+ *Revision 1.6  2002/04/13 17:45:32  moon
+ *I put code in to check if a label exists in the seg image in GenerateMesh,
+ *so that the vtk pipeline (SLOW!) wouldn't have to get executed on empty images.
+ *(i.e. all 6 or whatever labels that are initialized at the start are "rendered"
+ *even if only one label has actually been used)
+ *
+ *Revision 1.5  2002/04/10 21:20:42  moon
+ *fixed bug when update mesh is pressed with no seg data
+ *
+ *Revision 1.4  2002/04/10 20:20:36  moon
+ *fixed small problem with snake 3d window mesh generation with Konstantin
+ *It was using full_data, and we switched it to use only roi_data.
+ *
+ *Revision 1.3  2002/04/09 22:00:23  bobkov
+ *
+ *Modified GenerateMesh method to display 3d snake segmentation
+ *
+ *Revision 1.2  2002/03/08 14:06:29  moon
+ *Added Header and Log tags to all files
+ **/
diff --git a/Logic/Mesh/MeshManager.h b/Logic/Mesh/MeshManager.h
new file mode 100644
index 0000000..aa15c2c
--- /dev/null
+++ b/Logic/Mesh/MeshManager.h
@@ -0,0 +1,206 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: MeshManager.h,v $
+  Language:  C++
+  Date:      $Date: 2007/12/30 04:05:15 $
+  Version:   $Revision: 1.3 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#ifndef __MeshManager_h_
+#define __MeshManager_h_
+
+// Forward references
+class IRISApplication;
+class GlobalState;
+class IRISImageData;
+class ColorLabel;
+class AllPurposeProgressAccumulator;
+class vtkPolyData;
+class MultiLabelMeshPipeline;
+class LevelSetMeshPipeline;
+
+
+#include "SNAPCommon.h"
+#include "AllPurposeProgressAccumulator.h"
+#include <vector>
+#include "itkObject.h"
+#include "vtkSmartPointer.h"
+
+namespace itk {
+    template<unsigned int VImageDimension>
+        class ImageBase;
+}
+
+/**
+ * \class MeshManager
+ * \brief A class representing a mesh generated from a segmentation.
+ *
+ * This class wraps around MultiLabelMeshPipeline and LevelSetMeshPipeline.  It's a very
+ * high level class that generates a correct mesh based on the current state of the 
+ * application.
+ */
+class MeshManager : public itk::Object
+{
+public:
+  irisITKObjectMacro(MeshManager, itk::Object)
+
+  /**
+   * Initialize the object with an IRISApplication pointer
+   */
+  void Initialize(IRISApplication *driver);
+
+  /**
+   * Generate VTK meshes from input data.
+   */
+  void UpdateVTKMeshes(itk::Command *command);
+
+  /**
+   * Get the mapping of labels to vtk mesh pointers. This method has a
+   * slight overhead of copying the data
+   */
+  typedef std::map<LabelType, vtkSmartPointer<vtkPolyData> > MeshCollection;
+  MeshCollection GetMeshes();
+
+  /**
+   * Does the mesh need updating?
+   */
+  bool IsMeshDirty();
+
+  /**
+    Get the time that the mesh was built
+    */
+  irisGetMacro(BuildTime, unsigned long)
+
+protected:
+
+  MeshManager();
+  virtual ~MeshManager();
+
+  /** 
+   * This method applies the settings in a color label if color label 
+   * is displayable
+   */
+  bool ApplyColorLabel(const ColorLabel &label);
+
+  // Back pointer to the application object
+  IRISApplication *m_Driver;
+
+  // Pointer to the global state object
+  GlobalState *m_GlobalState;
+
+  // Progress accumulator for multi-object rendering
+  itk::SmartPointer<AllPurposeProgressAccumulator> m_Progress;
+
+  // Time when the mesh was last build
+  unsigned long m_BuildTime;
+
+  //Check if apImage is a proper 3D, i.e. the third dimension is
+  //different than 1
+  bool Is3DProper(const itk::ImageBase<3> * apImage) const;
+
+};
+
+#endif // __MeshManager_h_
+
+/*
+ *$Log: MeshManager.h,v $
+ *Revision 1.3  2007/12/30 04:05:15  pyushkevich
+ *GPL License
+ *
+ *Revision 1.2  2007/05/10 20:19:50  pyushkevich
+ *Added VTK mesh export code and GUI
+ *
+ *Revision 1.1  2006/12/02 04:22:15  pyushkevich
+ *Initial sf checkin
+ *
+ *Revision 1.1.1.1  2006/09/26 23:56:18  pauly2
+ *Import
+ *
+ *Revision 1.8  2005/10/29 14:00:14  pauly
+ *ENH: SNAP enhacements like color maps and progress bar for 3D rendering
+ *
+ *Revision 1.7  2003/10/09 22:45:13  pauly
+ *EMH: Improvements in 3D functionality and snake parameter preview
+ *
+ *Revision 1.6  2003/10/02 14:54:53  pauly
+ *ENH: Development during the September code freeze
+ *
+ *Revision 1.1  2003/09/11 13:50:29  pauly
+ *FIX: Enabled loading of images with different orientations
+ *ENH: Implemented image save and load operations
+ *
+ *Revision 1.4  2003/08/28 14:37:09  pauly
+ *FIX: Clean 'unused parameter' and 'static keyword' warnings in gcc.
+ *FIX: Label editor repaired
+ *
+ *Revision 1.3  2003/08/27 14:03:21  pauly
+ *FIX: Made sure that -Wall option in gcc generates 0 warnings.
+ *FIX: Removed 'comment within comment' problem in the cvs log.
+ *
+ *Revision 1.2  2003/08/27 04:57:46  pauly
+ *FIX: A large number of bugs has been fixed for 1.4 release
+ *
+ *Revision 1.1  2003/07/12 04:52:25  pauly
+ *Initial checkin of SNAP application  to the InsightApplications tree
+ *
+ *Revision 1.7  2003/07/12 01:34:18  pauly
+ *More final changes before ITK checkin
+ *
+ *Revision 1.6  2003/07/11 23:29:17  pauly
+ **** empty log message ***
+ *
+ *Revision 1.5  2003/07/11 21:25:12  pauly
+ *Code cleanup for ITK checkin
+ *
+ *Revision 1.4  2003/06/08 16:11:42  pauly
+ *User interface changes
+ *Automatic mesh updating in SNAP mode
+ *
+ *Revision 1.3  2003/05/05 12:30:18  pauly
+ **** empty log message ***
+ *
+ *Revision 1.2  2003/04/18 17:32:18  pauly
+ **** empty log message ***
+ *
+ *Revision 1.1  2003/03/07 19:29:47  pauly
+ *Initial checkin
+ *
+ *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
+ *Started the project repository
+ *
+ *
+ *Revision 1.4  2002/04/27 17:49:00  bobkov
+ *Added comments
+ *
+ *Revision 1.3  2002/04/11 23:09:15  bobkov
+ *Commented GenerateMesh() method
+ *
+ *Revision 1.2  2002/03/08 14:06:29  moon
+ *Added Header and Log tags to all files
+ **/
diff --git a/Logic/Mesh/MeshObject.cxx b/Logic/Mesh/MeshObject.cxx
deleted file mode 100644
index 9a83707..0000000
--- a/Logic/Mesh/MeshObject.cxx
+++ /dev/null
@@ -1,741 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: MeshObject.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/06/28 18:45:08 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-// Borland compiler is very lazy so we need to instantiate the template
-//  by hand 
-#if defined(__BORLANDC__)
-#include "SNAPBorlandDummyTypes.h"
-#endif
-#include "MeshObject.h"
-
-#include "SNAPOpenGL.h"
-
-// SNAP Includes
-#include "ColorLabel.h"
-#include "GlobalState.h"
-#include "ImageWrapper.h"
-#include "IRISApplication.h"
-#include "IRISMeshPipeline.h"
-#include "LevelSetMeshPipeline.h"
-#include "IRISVectorTypesToITKConversion.h"
-#include "IRISImageData.h"
-#include "SNAPImageData.h"
-#include "AllPurposeProgressAccumulator.h"
-
-// ITK includes
-#include "itkRegionOfInterestImageFilter.h"
-#include "itkBinaryThresholdImageFilter.h"
-#include "itkDiscreteGaussianImageFilter.h"
-#include "itkImageRegionConstIteratorWithIndex.h"
-#include "itkRecursiveGaussianImageFilter.h"
-#include "itkVTKImageExport.h"
-
-// VTK includes
-#include <vtkCellArray.h>
-#include <vtkDecimatePro.h>
-#include <vtkImageData.h>
-#include <vtkImageImport.h>
-#include <vtkImageGaussianSmooth.h>
-#include <vtkContourFilter.h>
-#include <vtkImageThreshold.h>
-#include <vtkImageToStructuredPoints.h>
-#include <vtkPointData.h>
-#include <vtkPolyData.h>
-#include <vtkSmoothPolyDataFilter.h>
-#include <vtkStripper.h>
-
-// System includes
-#include <cstdlib>
-
-using namespace std;
-
-MeshObject
-::MeshObject() 
-{
-  m_DisplayListNumber = 0;
-  m_DisplayListIndex = 0;
-  m_Progress = AllPurposeProgressAccumulator::New();
-}
-
-MeshObject
-::~MeshObject()
-{
-}
-
-void 
-MeshObject
-::Initialize(IRISApplication *driver)
-{
-  m_Driver = driver;
-  m_GlobalState = m_Driver->GetGlobalState();
-}
-
-// Call this when segmentation data is no longer valid
-void 
-MeshObject
-::Reset() 
-{
-  if (m_DisplayListNumber > 0) 
-    {
-    glDeleteLists(m_DisplayListIndex, m_DisplayListNumber);
-    m_DisplayListNumber = 0;
-    }
-  m_Labels.clear();
-}
-
-void 
-MeshObject
-::GenerateVTKMeshes(itk::Command *command)
-{
-  unsigned int i;
-
-  // The mesh array should be empty
-  assert(m_Meshes.size() == 0);
-
-  // Reset the label array and the display list index
-  Reset();
-
-  // The mesh is constructed differently depending on whether there is an
-  // actively evolving level set or not SNAP mode or in IRIS mode
-  if (m_GlobalState->GetSnakeActive() && 
-      m_Driver->GetSNAPImageData()->IsSnakeLoaded()) 
-    {
-    
-    // We are in SNAP.  Use one of SNAP's images
-    SNAPImageData *snapData = m_Driver->GetSNAPImageData();
-
-    // Create a pipeline for mesh generation
-    LevelSetMeshPipeline *meshPipeline = new LevelSetMeshPipeline();
-
-    // Get the float distance transform from the level set mechanism
-    meshPipeline->SetImage(snapData->GetLevelSetImage());
-    
-    // Compute the mesh only for the current segmentation color
-    vtkPolyData *mesh = vtkPolyData::New();
-    meshPipeline->ComputeMesh(mesh);
-    m_Meshes.push_back(mesh);
-    
-    // Deallocate the filter
-    delete meshPipeline;
-  }
-  else    
-    {
-    // Create a pipeline for mesh generation
-    IRISMeshPipeline *meshPipeline = new IRISMeshPipeline();
-  
-    // Initialize the pipeline with the correct image
-    if(!m_GlobalState->GetSnakeActive())
-      {
-      // We are not currently in SNAP.  Use the segmentation image with its
-      // different colors
-      meshPipeline->SetImage(
-        m_Driver->GetCurrentImageData()->GetSegmentation()->GetImage());    
-  
-      }
-    else
-      {
-      // We are in SNAP.  Use one of SNAP's images
-      SNAPImageData *snapData = m_Driver->GetSNAPImageData();
-      meshPipeline->SetImage(snapData->GetSegmentation()->GetImage());
-      }
-  
-    // Pass the settings on to the pipeline
-    meshPipeline->SetMeshOptions(m_GlobalState->GetMeshOptions());
-  
-    // Run the first step in this pipeline
-    meshPipeline->ComputeBoundingBoxes();
-
-    // Add the listener to the progress accumulator
-    unsigned long xObserverTag = 
-      m_Progress->AddObserver(itk::ProgressEvent(), command);
-
-    // Initialize the progress meter
-    for(i = 1; i < MAX_COLOR_LABELS; i++)
-      {
-      ColorLabel cl = m_Driver->GetColorLabelTable()->GetColorLabel(i);
-      if(cl.IsVisibleIn3D() && meshPipeline->CanComputeMesh(i))
-        { 
-        m_Progress->RegisterSource(
-          meshPipeline->GetProgressAccumulator(),
-          1.0 * meshPipeline->GetVoxelsInBoundingBox(i));
-        }
-      }
-
-    // Compute a list of meshes in the filter
-    for(i = 1; i < MAX_COLOR_LABELS; i++) 
-      {
-      ColorLabel cl = m_Driver->GetColorLabelTable()->GetColorLabel(i);
-      if(cl.IsVisibleIn3D() && meshPipeline->CanComputeMesh(i))
-        {
-        vtkPolyData *mesh = vtkPolyData::New();
-        meshPipeline->ComputeMesh(i,mesh);
-        m_Meshes.push_back(mesh);
-        m_Labels.push_back(i);
-
-        // Advance the progress accumulator
-        m_Progress->StartNextRun(meshPipeline->GetProgressAccumulator());
-        }
-      }
-
-    // Remove all the progress sources
-    m_Progress->UnregisterAllSources();
-
-    // Remove progress observer
-    m_Progress->RemoveObserver(xObserverTag);
-    
-    // Deallocate the filter
-    delete meshPipeline;
-    }
-}
-
-void 
-MeshObject
-::GenerateDisplayLists()
-{
-  // Generate an array of display lists
-  m_DisplayListNumber = m_Meshes.size();
-  m_DisplayListIndex = glGenLists(m_DisplayListNumber);
-  
-  // Create a display list for each of the objects in the pipeline
-  for(unsigned int dl=0;dl<m_DisplayListNumber;dl++)
-    {
-    // Get the triangle strip information.
-    vtkCellArray *triStrips = m_Meshes[dl]->GetStrips();
-
-    // Get the vertex information.
-    vtkPoints *verts = m_Meshes[dl]->GetPoints();
-
-    // Get the normal information.
-    vtkDataArray *norms = m_Meshes[dl]->GetPointData()->GetNormals();
-    
-    // Build display list
-    glNewList(m_DisplayListIndex + dl,GL_COMPILE);
-
-    vtkIdType ntris = 0;
-    vtkIdType npts;
-    vtkIdType *pts;
-    for ( triStrips->InitTraversal(); triStrips->GetNextCell(npts,pts); ) 
-      {
-      ntris += npts-2;
-      glBegin( GL_TRIANGLE_STRIP );
-      for (vtkIdType j = 0; j < npts; j++) 
-        {
-        // Some ugly code to ensure VTK version compatibility
-        double vx = verts->GetPoint(pts[j])[0];
-        double vy = verts->GetPoint(pts[j])[1];
-        double vz = verts->GetPoint(pts[j])[2];
-        double nx = norms->GetTuple(pts[j])[0];
-        double ny = norms->GetTuple(pts[j])[1];
-        double nz = norms->GetTuple(pts[j])[2];
-        
-        // Specify normal.
-        glNormal3d(nx, ny, nz);
-
-        // Specify vertex.
-        glVertex3d(vx, vy, vz);
-        }
-      glEnd();
-      }
-    glEndList();    
-    }
-}
-
-
-void 
-MeshObject
-::DiscardVTKMeshes()
-{
-  for(size_t i = 0; i < m_Meshes.size(); i++)
-    {  
-    // Delete the mesh
-    m_Meshes[i]->Delete();    
-    }
-
-  m_Meshes.clear();
-}
-
-size_t 
-MeshObject
-::GetNumberOfVTKMeshes() const
-{
-  return m_Meshes.size();
-}
-
-vtkPolyData *
-MeshObject
-::GetVTKMesh(size_t iMesh) const
-{
-  return m_Meshes[iMesh];
-}
-
-LabelType
-MeshObject
-::GetVTKMeshLabel(size_t iMesh) const
-{
-  return m_Labels[iMesh];
-}
-
-void 
-MeshObject
-::GenerateMesh(itk::Command *command)
-{
-  GenerateVTKMeshes(command);
-  GenerateDisplayLists();
-  DiscardVTKMeshes();
-}
-
-/*
-void 
-MeshObject
-::GenerateMesh(itk::Command *command)
-{
-  unsigned int i; 
-
-  // Reset the label array and the display list index
-  Reset();
-
-  // An array of meshes to be generated
-  vector<vtkPolyData *> meshes;
-
-  // The mesh is constructed differently depending on whether there is an
-  // actively evolving level set or not
-  // SNAP mode or in IRIS mode
-  if (m_GlobalState->GetSnakeActive() && 
-      m_Driver->GetSNAPImageData()->IsSnakeLoaded()) 
-    {
-    
-    // We are in SNAP.  Use one of SNAP's images
-    SNAPImageData *snapData = m_Driver->GetSNAPImageData();
-
-    // Create a pipeline for mesh generation
-    LevelSetMeshPipeline *meshPipeline = new LevelSetMeshPipeline();
-
-    // Get the float distance transform from the level set mechanism
-    meshPipeline->SetImage(snapData->GetLevelSetImage());
-    
-    // Compute the mesh only for the current segmentation color
-    vtkPolyData *mesh = vtkPolyData::New();
-    meshPipeline->ComputeMesh(mesh);
-    meshes.push_back(mesh);
-    
-    // Deallocate the filter
-    delete meshPipeline;
-  }
-  else    
-    {
-    // Create a pipeline for mesh generation
-    IRISMeshPipeline *meshPipeline = new IRISMeshPipeline();
-  
-    // Initialize the pipeline with the correct image
-    if(!m_GlobalState->GetSnakeActive())
-      {
-      // We are not currently in SNAP.  Use the segmentation image with its
-      // different colors
-      meshPipeline->SetImage(
-        m_Driver->GetCurrentImageData()->GetSegmentation()->GetImage());    
-  
-      }
-    else
-      {
-      // We are in SNAP.  Use one of SNAP's images
-      SNAPImageData *snapData = m_Driver->GetSNAPImageData();
-      meshPipeline->SetImage(snapData->GetSegmentation()->GetImage());
-      }
-  
-    // Pass the settings on to the pipeline
-    meshPipeline->SetMeshOptions(m_GlobalState->GetMeshOptions());
-  
-    // Run the first step in this pipeline
-    meshPipeline->ComputeBoundingBoxes();
-
-    // Add the listener to the progress accumulator
-    unsigned long xObserverTag = 
-      m_Progress->AddObserver(itk::ProgressEvent(), command);
-
-    // Initialize the progress meter
-    for(i = 1; i < MAX_COLOR_LABELS; i++)
-      {
-      ColorLabel cl = m_Driver->GetColorLabelTable()->GetColorLabel(i);
-      if(cl.IsVisibleIn3D() && meshPipeline->CanComputeMesh(i))
-        { 
-        m_Progress->RegisterSource(
-          meshPipeline->GetProgressAccumulator(),
-          1.0 * meshPipeline->GetVoxelsInBoundingBox(i));
-        }
-      }
-
-    // Compute a list of meshes in the filter
-    for(i = 1; i < MAX_COLOR_LABELS; i++) 
-      {
-      ColorLabel cl = m_Driver->GetColorLabelTable()->GetColorLabel(i);
-      if(cl.IsVisibleIn3D() && meshPipeline->CanComputeMesh(i))
-        {
-        vtkPolyData *mesh = vtkPolyData::New();
-        meshPipeline->ComputeMesh(i,mesh);
-        meshes.push_back(mesh);
-        m_Labels.push_back(i);
-
-        // Advance the progress accumulator
-        m_Progress->StartNextRun(meshPipeline->GetProgressAccumulator());
-        }
-      }
-
-    // Remove all the progress sources
-    m_Progress->UnregisterAllSources();
-
-    // Remove progress observer
-    m_Progress->RemoveObserver(xObserverTag);
-    
-    // Deallocate the filter
-    delete meshPipeline;
-    }
-
-
-  // Generate an array of display lists
-  m_DisplayListNumber = meshes.size();
-  m_DisplayListIndex = glGenLists(m_DisplayListNumber);
-  
-  // Create a display list for each of the objects in the pipeline
-  for(unsigned int dl=0;dl<m_DisplayListNumber;dl++)
-    {
-    // Get the triangle strip information.
-    vtkCellArray *triStrips = meshes[dl]->GetStrips();
-
-    // Get the vertex information.
-    vtkPoints *verts = meshes[dl]->GetPoints();
-
-    // Get the normal information.
-    vtkDataArray *norms = meshes[dl]->GetPointData()->GetNormals();
-    
-    // Build display list
-    glNewList(m_DisplayListIndex + dl,GL_COMPILE);
-
-    vtkIdType ntris = 0;
-    vtkIdType npts;
-    vtkIdType *pts;
-    for ( triStrips->InitTraversal(); triStrips->GetNextCell(npts,pts); ) 
-      {
-      ntris += npts-2;
-      glBegin( GL_TRIANGLE_STRIP );
-      for (vtkIdType j = 0; j < npts; j++) 
-        {
-        // Some ugly code to ensure VTK version compatibility
-        double vx = verts->GetPoint(pts[j])[0];
-        double vy = verts->GetPoint(pts[j])[1];
-        double vz = verts->GetPoint(pts[j])[2];
-        double nx = norms->GetTuple(pts[j])[0];
-        double ny = norms->GetTuple(pts[j])[1];
-        double nz = norms->GetTuple(pts[j])[2];
-        
-        // Specify normal.
-        glNormal3d(nx, ny, nz);
-
-        // Specify vertex.
-        glVertex3d(vx, vy, vz);
-      }
-      glEnd();
-    }
-    glEndList();
-
-    // Delete the mesh
-    meshes[dl]->Delete();    
-    }
-}
-*/
-
-/*
- *  Apply color label, a shorthand
- */
-bool 
-MeshObject
-::ApplyColorLabel(const ColorLabel &label) 
-{
-  if (label.IsVisible() && label.IsVisibleIn3D()) 
-    {
-    // Adjust the label color to reduce the saturation. This in necessary
-    // in order to see the highlights on the object
-    double r = 0.75 * (label.GetRGB(0) / 255.0);
-    double g = 0.75 * (label.GetRGB(1) / 255.0);
-    double b = 0.75 * (label.GetRGB(2) / 255.0);
-    double a = label.GetAlpha() / 255.0;
-
-    if (label.IsOpaque()) glColor3d(r, g, b); 
-    else glColor4d(r, g, b, a);
-  
-    return true;
-    }
-  return false;
-}
-
-void 
-MeshObject
-::Display() 
-{
-  unsigned int i;
-
-  // Define a shorthand pointer to the image data
-  //IRISImageData *irisData = m_Driver->GetCurrentImageData();
-
-  // check if the snake is not active
-  // if yes it means we are in IRIS 
-  // so we render all segmentations
-  if (!m_GlobalState->GetSnakeActive()) 
-    {
-    
-    // First render all the fully opaque objects
-    for (i=0; i < m_DisplayListNumber; i++) 
-      {
-      const ColorLabel &cl = 
-        m_Driver->GetColorLabelTable()->GetColorLabel(m_Labels[i]);
-      if (cl.IsOpaque() && ApplyColorLabel(cl)) 
-      {
-        glCallList(m_DisplayListIndex + i);
-      }
-    }
-
-    // Now render all the translucent objects, with depth buffer read-only
-    // Ideally we should sort polygons from back to front
-    // TODO: Utilize VTK!
-    glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
-    
-    glEnable(GL_BLEND);     
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);     
-    glDepthMask(GL_FALSE); 
-    
-    for (i=0; i < m_DisplayListNumber; i++) 
-      {
-      const ColorLabel &cl = 
-        m_Driver->GetColorLabelTable()->GetColorLabel(m_Labels[i]);
-      if (!cl.IsOpaque() && ApplyColorLabel(cl)) 
-      {
-        glCallList(m_DisplayListIndex + i); 
-      }
-    }
-
-    glPopAttrib();
-  }
-
-  // if the snake is active render only the current segmentation
-  // added by Konstantin Bobkov
-  else if(m_DisplayListNumber > 0) 
-  {
-    // get current label
-    int currentcolor =  m_GlobalState->GetDrawingColorLabel();
-
-    // first check if the segmentation is fully opaque
-    // and render it
-    const ColorLabel &cl = 
-      m_Driver->GetColorLabelTable()->GetColorLabel(currentcolor);
-    if (cl.IsOpaque() && ApplyColorLabel(cl)) 
-    {
-      glCallList(m_DisplayListIndex);
-    }
-
-    // now check if the segmentation is translucent 
-    // and render it with depth buffer read-only
-    glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glDepthMask(GL_FALSE);
-
-    if (!cl.IsOpaque() && ApplyColorLabel(cl)) 
-    {
-      glCallList(m_DisplayListIndex);  
-    }
-
-    glPopAttrib();
-    
-  }
-}
-
-/*
- *$Log: MeshObject.cxx,v $
- *Revision 1.4  2010/06/28 18:45:08  pyushkevich
- *Patch from Michael Hanke to allow ITK 3.18 builds
- *
- *Revision 1.3  2007/12/30 04:05:15  pyushkevich
- *GPL License
- *
- *Revision 1.2  2007/05/10 20:19:50  pyushkevich
- *Added VTK mesh export code and GUI
- *
- *Revision 1.1  2006/12/02 04:22:14  pyushkevich
- *Initial sf checkin
- *
- *Revision 1.1.1.1  2006/09/26 23:56:18  pauly2
- *Import
- *
- *Revision 1.19  2005/12/08 18:20:45  hjohnson
- *COMP:  Removed compiler warnings from SGI/linux/MacOSX compilers.
- *
- *Revision 1.18  2005/11/23 14:32:15  ibanez
- *BUG: 2404. Patch provided by Paul Yushkevish.
- *
- *Revision 1.17  2005/10/29 14:00:14  pauly
- *ENH: SNAP enhacements like color maps and progress bar for 3D rendering
- *
- *Revision 1.16  2005/04/21 14:46:29  pauly
- *ENH: Improved management and editing of color labels in SNAP
- *
- *Revision 1.15  2004/09/14 14:11:09  pauly
- *ENH: Added an activation manager to main UI class, improved snake code, various UI fixes and additions
- *
- *Revision 1.14  2004/08/26 19:43:23  pauly
- *ENH: Moved the Borland code into Common folder
- *
- *Revision 1.13  2004/08/03 23:26:32  ibanez
- *ENH: Modification for building in multple platforms. By Julien Jomier.
- *
- *Revision 1.12  2004/07/29 14:01:56  pauly
- *ENH: An interface for changing SNAP appearance settings
- *
- *Revision 1.11  2004/01/27 17:34:00  pauly
- *FIX: Compiling on Mac OSX, issue with GLU include file
- *
- *Revision 1.10  2004/01/20 00:17:42  pauly
- *FIX: VTK float compatibility
- *
- *Revision 1.9  2004/01/17 18:39:07  lorensen
- *ENH: changes to accomodate VTK api changes.
- *
- *Revision 1.8  2003/10/09 22:45:13  pauly
- *EMH: Improvements in 3D functionality and snake parameter preview
- *
- *Revision 1.7  2003/10/02 14:54:53  pauly
- *ENH: Development during the September code freeze
- *
- *Revision 1.1  2003/09/11 13:50:29  pauly
- *FIX: Enabled loading of images with different orientations
- *ENH: Implemented image save and load operations
- *
- *Revision 1.5  2003/08/28 14:37:09  pauly
- *FIX: Clean 'unused parameter' and 'static keyword' warnings in gcc.
- *FIX: Label editor repaired
- *
- *Revision 1.4  2003/08/27 14:03:21  pauly
- *FIX: Made sure that -Wall option in gcc generates 0 warnings.
- *FIX: Removed 'comment within comment' problem in the cvs log.
- *
- *Revision 1.3  2003/08/27 04:57:46  pauly
- *FIX: A large number of bugs has been fixed for 1.4 release
- *
- *Revision 1.2  2003/08/14 13:37:07  pauly
- *FIX: Error with using int instead of vtkIdType in calling vtkCellArray::GetNextCell
- *
- *Revision 1.1  2003/07/12 04:52:25  pauly
- *Initial checkin of SNAP application  to the InsightApplications tree
- *
- *Revision 1.2  2003/07/12 01:34:18  pauly
- *More final changes before ITK checkin
- *
- *Revision 1.1  2003/07/11 23:29:17  pauly
- **** empty log message ***
- *
- *Revision 1.10  2003/07/11 21:25:12  pauly
- *Code cleanup for ITK checkin
- *
- *Revision 1.9  2003/07/10 14:30:26  pauly
- *Integrated ITK into SNAP level set segmentation
- *
- *Revision 1.8  2003/06/08 16:11:42  pauly
- *User interface changes
- *Automatic mesh updating in SNAP mode
- *
- *Revision 1.7  2003/05/12 02:51:10  pauly
- *Got code to compile on UNIX
- *
- *Revision 1.6  2003/05/05 12:30:18  pauly
- **** empty log message ***
- *
- *Revision 1.5  2003/04/29 14:01:42  pauly
- *Charlotte Trip
- *
- *Revision 1.4  2003/04/23 20:36:23  pauly
- **** empty log message ***
- *
- *Revision 1.3  2003/04/23 06:05:18  pauly
- **** empty log message ***
- *
- *Revision 1.2  2003/04/18 17:32:18  pauly
- **** empty log message ***
- *
- *Revision 1.1  2003/03/07 19:29:47  pauly
- *Initial checkin
- *
- *Revision 1.2  2002/12/16 16:40:19  pauly
- **** empty log message ***
- *
- *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
- *Started the project repository
- *
- *
- *Revision 1.11  2002/05/08 17:34:18  moon
- *Fixed bug of using the voxel snake image, instead of hte float snake state,
- *for the marching cubes. Now the snake looks smooth instead of voxelized.
- *
- *Revision 1.10  2002/04/27 18:30:22  moon
- *Finished commenting
- *
- *Revision 1.9  2002/04/27 17:49:00  bobkov
- *Added comments
- *
- *Revision 1.8  2002/04/24 17:12:48  bobkov
- *modified display() method so that when num_lists is zero
- *the 3D window does not show anything
- *
- *Revision 1.7  2002/04/23 19:30:10  bobkov
- *modified display method so that the current color label is
- *used in the snake 3d window
- *
- *Revision 1.6  2002/04/13 17:45:32  moon
- *I put code in to check if a label exists in the seg image in GenerateMesh,
- *so that the vtk pipeline (SLOW!) wouldn't have to get executed on empty images.
- *(i.e. all 6 or whatever labels that are initialized at the start are "rendered"
- *even if only one label has actually been used)
- *
- *Revision 1.5  2002/04/10 21:20:42  moon
- *fixed bug when update mesh is pressed with no seg data
- *
- *Revision 1.4  2002/04/10 20:20:36  moon
- *fixed small problem with snake 3d window mesh generation with Konstantin
- *It was using full_data, and we switched it to use only roi_data.
- *
- *Revision 1.3  2002/04/09 22:00:23  bobkov
- *
- *Modified GenerateMesh method to display 3d snake segmentation
- *
- *Revision 1.2  2002/03/08 14:06:29  moon
- *Added Header and Log tags to all files
- **/
diff --git a/Logic/Mesh/MeshObject.h b/Logic/Mesh/MeshObject.h
deleted file mode 100644
index 5b36613..0000000
--- a/Logic/Mesh/MeshObject.h
+++ /dev/null
@@ -1,265 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: MeshObject.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:15 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __MeshObject_h_
-#define __MeshObject_h_
-
-// Forward references
-class IRISApplication;
-class GlobalState;
-class IRISImageData;
-class ColorLabel;
-class AllPurposeProgressAccumulator;
-class vtkPolyData;
-
-namespace itk {
-  class Command;
-}
-
-#include "SNAPCommon.h"
-#include "AllPurposeProgressAccumulator.h"
-#include <vector>
-
-/**
- * \class MeshObject
- * \brief A class representing a mesh generated from a segmentation.
- *
- * This class wraps around IRISMeshPipeline and LevelSetMeshPipeline.  It's a very
- * high level class that generates a correct mesh based on the current state of the 
- * application.
- */
-class MeshObject  {
-private:
-  // The number of allocated display lists
-  unsigned int m_DisplayListNumber;
-
-  // The starting display list number
-  unsigned int m_DisplayListIndex;
-
-  // The labels associated with the allocated display lists
-  std::vector<LabelType> m_Labels;
-
-  // The VTK meshes (optionally available)
-  std::vector<vtkPolyData *> m_Meshes;
-
-  /** 
-   * This method applies the settings in a color label if color label 
-   * is displayable
-   */
-  bool ApplyColorLabel(const ColorLabel &label);
-
-  // Back pointer to the application object
-  IRISApplication *m_Driver;
-
-  // Pointer to the global state object
-  GlobalState *m_GlobalState;
-
-  // Progress accumulator for multi-object rendering
-  itk::SmartPointer<AllPurposeProgressAccumulator> m_Progress;
-
-public:
-  MeshObject();
-  MeshObject( const MeshObject& M ) { *this=M; } 
-  MeshObject& operator= ( const MeshObject& M ) { *this=M; return *this; }
-  ~MeshObject();
-  
-  // Reset the label array and the display list index. 
-  void Reset();
-
-  /**
-   * Initialize the object with an IRISApplication pointer
-   */
-  void Initialize(IRISApplication *driver);
-
-  /* MeshObject::GenerateMesh();
-   *
-   * DESCRIPTION:
-   * This function generates a mesh which represents a 3D 
-   * segmentation. This operation is accomplished by retrieving 
-   * the image data from the IRISImageData structure and then 
-   * invoking a VTK isosurface extraction algorithm. To create 
-   * the surface it performs the following steps (GB, MS, TMR 
-   * are optional): 
-   *   1.Gaussian Blur on the imported image data 
-   *   2.Triangle generation using a contour algorithm 
-   *   3.Mesh Smoothing 
-   *   4.Triangle Mesh Reduction 
-   *   5.Triangle stripping
-   *
-   * Modified by Konstantin Bobkov and Nathan Moon (April 2002)
-   * New modification of this method allows to generate 
-   * trianglemesh for the Snake Voxel Data. In this case the
-   * Gaussian Blur step on the imported SnakeVoxData is not
-   * performed
-   * 
-   * PRECONDITIONS:
-   * - Valid Segmented VoxData or SnakeVoxData
-   *
-   * POSTCONDITIONS:
-   * - A displaylist (points) and a trianglemesh 
-   */
-  void GenerateMesh(itk::Command *command);
-
-  /**
-   * Generate VTK meshes from input data. This method is called by
-   * GenerateMesh internally. But the user of this class can choose
-   * to call this method directly if the meshes are needed for export
-   */
-  void GenerateVTKMeshes(itk::Command *command);
-
-  /** 
-   * Convert VTK meshes to display lists. This method is called inside
-   * GenerateMesh. Normally, you would not use this method.
-   */
-  void GenerateDisplayLists();
-
-  /**
-   * Discard VTK meshes. This method is called by GenerateMesh intenally.
-   * You should call this method after calling GenerateVTKMesh.
-   */
-  void DiscardVTKMeshes();
-
-  /** 
-   * Get the number of VTK meshes available
-   */
-  size_t GetNumberOfVTKMeshes() const;
-
-  /**
-   * Get the i-th VTK mesh
-   */
-  vtkPolyData *GetVTKMesh(size_t iMesh) const;
-
-  /**
-   * Get the label associated with i-th mesh
-   */
-  LabelType GetVTKMeshLabel(size_t iMesh) const;
-
-  /* MeshObject::Display();
-   *
-   * DESCRIPTION:
-   * This function displays the mesh generated by the 
-   * GenerateMesh() method described above
-   *
-   * Modified by Konstantin Bobkov (April 2002)
-   * New modification of this method allows to display the
-   * currently generated trianglemesh for the Snake Voxel Data. 
-   *
-   * 
-   * PRECONDITIONS:
-   * - for each segmented object to be displayed the mesh is valid
-   *
-   * POSTCONDITIONS:
-   * - each object in displaylist is displayed 
-   */
-  void Display();
-};
-
-#endif // __MeshObject_h_
-
-/*
- *$Log: MeshObject.h,v $
- *Revision 1.3  2007/12/30 04:05:15  pyushkevich
- *GPL License
- *
- *Revision 1.2  2007/05/10 20:19:50  pyushkevich
- *Added VTK mesh export code and GUI
- *
- *Revision 1.1  2006/12/02 04:22:15  pyushkevich
- *Initial sf checkin
- *
- *Revision 1.1.1.1  2006/09/26 23:56:18  pauly2
- *Import
- *
- *Revision 1.8  2005/10/29 14:00:14  pauly
- *ENH: SNAP enhacements like color maps and progress bar for 3D rendering
- *
- *Revision 1.7  2003/10/09 22:45:13  pauly
- *EMH: Improvements in 3D functionality and snake parameter preview
- *
- *Revision 1.6  2003/10/02 14:54:53  pauly
- *ENH: Development during the September code freeze
- *
- *Revision 1.1  2003/09/11 13:50:29  pauly
- *FIX: Enabled loading of images with different orientations
- *ENH: Implemented image save and load operations
- *
- *Revision 1.4  2003/08/28 14:37:09  pauly
- *FIX: Clean 'unused parameter' and 'static keyword' warnings in gcc.
- *FIX: Label editor repaired
- *
- *Revision 1.3  2003/08/27 14:03:21  pauly
- *FIX: Made sure that -Wall option in gcc generates 0 warnings.
- *FIX: Removed 'comment within comment' problem in the cvs log.
- *
- *Revision 1.2  2003/08/27 04:57:46  pauly
- *FIX: A large number of bugs has been fixed for 1.4 release
- *
- *Revision 1.1  2003/07/12 04:52:25  pauly
- *Initial checkin of SNAP application  to the InsightApplications tree
- *
- *Revision 1.7  2003/07/12 01:34:18  pauly
- *More final changes before ITK checkin
- *
- *Revision 1.6  2003/07/11 23:29:17  pauly
- **** empty log message ***
- *
- *Revision 1.5  2003/07/11 21:25:12  pauly
- *Code cleanup for ITK checkin
- *
- *Revision 1.4  2003/06/08 16:11:42  pauly
- *User interface changes
- *Automatic mesh updating in SNAP mode
- *
- *Revision 1.3  2003/05/05 12:30:18  pauly
- **** empty log message ***
- *
- *Revision 1.2  2003/04/18 17:32:18  pauly
- **** empty log message ***
- *
- *Revision 1.1  2003/03/07 19:29:47  pauly
- *Initial checkin
- *
- *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
- *Started the project repository
- *
- *
- *Revision 1.4  2002/04/27 17:49:00  bobkov
- *Added comments
- *
- *Revision 1.3  2002/04/11 23:09:15  bobkov
- *Commented GenerateMesh() method
- *
- *Revision 1.2  2002/03/08 14:06:29  moon
- *Added Header and Log tags to all files
- **/
diff --git a/Logic/Mesh/MeshOptions.cxx b/Logic/Mesh/MeshOptions.cxx
index 5024840..3d6f29c 100644
--- a/Logic/Mesh/MeshOptions.cxx
+++ b/Logic/Mesh/MeshOptions.cxx
@@ -38,35 +38,42 @@ MeshOptions
 ::MeshOptions()
 {
   // Begin render switches
-  m_UseGaussianSmoothing = true;
-  m_UseDecimation = false;
-  m_UseMeshSmoothing = false;
+  m_UseGaussianSmoothingModel = 
+    NewSimpleProperty("UseGaussianSmoothing", true);
+  m_UseDecimationModel = 
+    NewSimpleProperty("UseDecimation", false);
+  m_UseMeshSmoothingModel = 
+    NewSimpleProperty("UseMeshSmoothing", false);
 
   // Begin gsmooth params
-  m_GaussianStandardDeviation = 0.8f;
-  m_GaussianError = 0.03f;
+  m_GaussianStandardDeviationModel = 
+    NewRangedProperty("GaussianStandardDeviation", 0.8f,0.0f,3.0f,0.1f);
+  m_GaussianErrorModel = 
+    NewRangedProperty("GaussianError", 0.03f,0.001f,0.1f,0.001f);
 
   // Begin decimate params
-  m_DecimateTargetReduction = 0.95f;
-  m_DecimateInitialError = 0.002f;
-  m_DecimateAspectRatio = 20.0f;
-  m_DecimateErrorIncrement = 0.002f;
-  m_DecimateMaximumIterations = 1;
-  m_DecimateFeatureAngle = 45;
-  m_DecimatePreserveTopology = true;
+  m_DecimateTargetReductionModel = 
+    NewRangedProperty("DecimateTargetReduction", 0.95f,0.5f,0.99f,0.01f);
+  m_DecimateMaximumErrorModel = 
+    NewRangedProperty("DecimateMaximumError", 0.002f,0.0f,1.0f,0.001f);
+  m_DecimateFeatureAngleModel = 
+    NewRangedProperty("DecimateFeatureAngle", 45.0f,0.0f,90.0f,1.0f);
+  m_DecimatePreserveTopologyModel = 
+    NewSimpleProperty("DecimatePreserveTopology", true);
    
   // Begin msmooth params
-  m_MeshSmoothingIterations = 1;
-  m_MeshSmoothingRelaxationFactor = 0.01f;
-  m_MeshSmoothingFeatureAngle = 45;
-  m_MeshSmoothingConvergence = 0;
-  m_MeshSmoothingFeatureEdgeSmoothing = false;
-  m_MeshSmoothingBoundarySmoothing = false;
-}
-
-MeshOptions
-::~MeshOptions()
-{
+  m_MeshSmoothingIterationsModel = 
+    NewRangedProperty("MeshSmoothingIterations", 20u,0u,10000u,1u);
+  m_MeshSmoothingRelaxationFactorModel = 
+    NewRangedProperty("MeshSmoothingRelaxationFactor", 0.01f,0.0f,0.1f,0.001f);
+  m_MeshSmoothingFeatureAngleModel = 
+    NewRangedProperty("MeshSmoothingFeatureAngle", 45.0f,0.0f,90.0f,1.0f);
+  m_MeshSmoothingConvergenceModel = 
+    NewRangedProperty("MeshSmoothingConvergence", 0.0f,0.0f,1.0f,0.001f);
+  m_MeshSmoothingFeatureEdgeSmoothingModel = 
+    NewSimpleProperty("MeshSmoothingFeatureEdgeSmoothing", false);
+  m_MeshSmoothingBoundarySmoothingModel = 
+    NewSimpleProperty("MeshSmoothingBoundarySmoothing", false);
 }
 
 /*
@@ -128,3 +135,5 @@ MeshOptions
  *Revision 1.2  2002/03/08 14:06:30  moon
  *Added Header and Log tags to all files
  **/
+
+
diff --git a/Logic/Mesh/MeshOptions.h b/Logic/Mesh/MeshOptions.h
index b65af16..48ddefe 100644
--- a/Logic/Mesh/MeshOptions.h
+++ b/Logic/Mesh/MeshOptions.h
@@ -36,153 +36,67 @@
 #define __MeshOptions_h_
 
 #include "SNAPCommon.h"
+#include "AbstractPropertyContainerModel.h"
 
 /**
  * \class MeshOptions
  * \brief A set of options for mesh display in IRIS.
  */
-class MeshOptions  
+class MeshOptions : public AbstractPropertyContainerModel
 {
 public:
-  MeshOptions();
-  virtual ~MeshOptions();
-
-  irisGetMacro(UseGaussianSmoothing,bool);
-  irisSetMacro(UseGaussianSmoothing,bool);
-    
-  irisGetMacro(UseDecimation,bool);
-  irisSetMacro(UseDecimation,bool);
-
-  irisGetMacro(UseMeshSmoothing,bool);
-  irisSetMacro(UseMeshSmoothing,bool);
-
-  irisGetMacro(GaussianStandardDeviation,float);
-  irisSetMacro(GaussianStandardDeviation,float);
-
-  irisGetMacro(GaussianError,float);
-  irisSetMacro(GaussianError,float);
-
-  irisGetMacro(DecimateTargetReduction,float);
-  irisSetMacro(DecimateTargetReduction,float);
-
-  irisGetMacro(DecimateInitialError,float);
-  irisSetMacro(DecimateInitialError,float);
-
-  irisGetMacro(DecimateAspectRatio,float);
-  irisSetMacro(DecimateAspectRatio,float);
-
-  irisGetMacro(DecimateFeatureAngle,float);
-  irisSetMacro(DecimateFeatureAngle,float);
-
-  irisGetMacro(DecimateErrorIncrement,float);
-  irisSetMacro(DecimateErrorIncrement,float);
-
-  irisGetMacro(DecimateMaximumIterations,unsigned int);
-  irisSetMacro(DecimateMaximumIterations,unsigned int);
-
-  irisGetMacro(DecimatePreserveTopology,bool);
-  irisSetMacro(DecimatePreserveTopology,bool);
-
-  irisGetMacro(MeshSmoothingRelaxationFactor,float);
-  irisSetMacro(MeshSmoothingRelaxationFactor,float);
-
-  irisGetMacro(MeshSmoothingIterations,unsigned int);
-  irisSetMacro(MeshSmoothingIterations,unsigned int);
-
-  irisGetMacro(MeshSmoothingConvergence,float);
-  irisSetMacro(MeshSmoothingConvergence,float);
-
-  irisGetMacro(MeshSmoothingFeatureAngle,float);
-  irisSetMacro(MeshSmoothingFeatureAngle,float);
-
-  irisGetMacro(MeshSmoothingFeatureEdgeSmoothing,bool);
-  irisSetMacro(MeshSmoothingFeatureEdgeSmoothing,bool);
-
-  irisGetMacro(MeshSmoothingBoundarySmoothing,bool);
-  irisSetMacro(MeshSmoothingBoundarySmoothing,bool);
 
+  irisITKObjectMacro(MeshOptions, AbstractModel)
+
+  // Gaussian smoothing properties
+  irisSimplePropertyAccessMacro(UseGaussianSmoothing,bool)
+  irisRangedPropertyAccessMacro(GaussianStandardDeviation,float)
+  irisRangedPropertyAccessMacro(GaussianError,float)
+  irisSimplePropertyAccessMacro(UseDecimation,bool)
+
+  // Decimation properties
+  irisRangedPropertyAccessMacro(DecimateTargetReduction,float)
+  irisRangedPropertyAccessMacro(DecimateMaximumError,float)
+  irisRangedPropertyAccessMacro(DecimateFeatureAngle,float)
+  irisSimplePropertyAccessMacro(DecimatePreserveTopology,bool)
+
+  // Mesh smoothing properties
+  irisSimplePropertyAccessMacro(UseMeshSmoothing,bool)
+  irisRangedPropertyAccessMacro(MeshSmoothingRelaxationFactor,float)
+  irisRangedPropertyAccessMacro(MeshSmoothingIterations,unsigned int)
+  irisRangedPropertyAccessMacro(MeshSmoothingConvergence,float)
+  irisRangedPropertyAccessMacro(MeshSmoothingFeatureAngle,float)
+  irisSimplePropertyAccessMacro(MeshSmoothingFeatureEdgeSmoothing,bool)
+  irisSimplePropertyAccessMacro(MeshSmoothingBoundarySmoothing,bool)
+
+protected:
+  MeshOptions();
 
 private:
   // Begin render switches
-  bool m_UseGaussianSmoothing;
-  bool m_UseDecimation;
-  bool m_UseMeshSmoothing;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_UseGaussianSmoothingModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_UseDecimationModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_UseMeshSmoothingModel;
   
   // Begin gsmooth params
-  float m_GaussianStandardDeviation;
-  float m_GaussianError;
+  SmartPtr<ConcreteRangedFloatProperty> m_GaussianStandardDeviationModel;
+  SmartPtr<ConcreteRangedFloatProperty> m_GaussianErrorModel;
   
   // Begin decimate parameters
-  float m_DecimateTargetReduction;
-  float m_DecimateInitialError;
-  float m_DecimateAspectRatio;
-  float m_DecimateFeatureAngle;
-  float m_DecimateErrorIncrement;
-  unsigned int m_DecimateMaximumIterations;
-  bool m_DecimatePreserveTopology;
+  SmartPtr<ConcreteRangedFloatProperty> m_DecimateTargetReductionModel;
+  SmartPtr<ConcreteRangedFloatProperty> m_DecimateMaximumErrorModel;
+  SmartPtr<ConcreteRangedFloatProperty> m_DecimateFeatureAngleModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_DecimatePreserveTopologyModel;
   
   // Begin msmooth params
-  float m_MeshSmoothingRelaxationFactor;
-  unsigned int m_MeshSmoothingIterations;
-  float m_MeshSmoothingConvergence;
-  float m_MeshSmoothingFeatureAngle;
-  bool m_MeshSmoothingFeatureEdgeSmoothing;
-  bool m_MeshSmoothingBoundarySmoothing;
+  SmartPtr<ConcreteRangedFloatProperty> m_MeshSmoothingRelaxationFactorModel;
+  SmartPtr<ConcreteRangedUIntProperty> m_MeshSmoothingIterationsModel;
+  SmartPtr<ConcreteRangedFloatProperty> m_MeshSmoothingConvergenceModel;
+  SmartPtr<ConcreteRangedFloatProperty> m_MeshSmoothingFeatureAngleModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_MeshSmoothingFeatureEdgeSmoothingModel;
+  SmartPtr<ConcreteSimpleBooleanProperty> m_MeshSmoothingBoundarySmoothingModel;
 };
 
 #endif // __MeshOptions_h_
 
-/*
- *$Log: MeshOptions.h,v $
- *Revision 1.2  2007/12/30 04:05:15  pyushkevich
- *GPL License
- *
- *Revision 1.1  2006/12/02 04:22:15  pyushkevich
- *Initial sf checkin
- *
- *Revision 1.1.1.1  2006/09/26 23:56:18  pauly2
- *Import
- *
- *Revision 1.5  2003/10/09 22:45:13  pauly
- *EMH: Improvements in 3D functionality and snake parameter preview
- *
- *Revision 1.4  2003/10/02 14:54:53  pauly
- *ENH: Development during the September code freeze
- *
- *Revision 1.1  2003/09/11 13:50:29  pauly
- *FIX: Enabled loading of images with different orientations
- *ENH: Implemented image save and load operations
- *
- *Revision 1.3  2003/08/27 14:03:21  pauly
- *FIX: Made sure that -Wall option in gcc generates 0 warnings.
- *FIX: Removed 'comment within comment' problem in the cvs log.
- *
- *Revision 1.2  2003/08/27 04:57:46  pauly
- *FIX: A large number of bugs has been fixed for 1.4 release
- *
- *Revision 1.1  2003/07/12 04:52:25  pauly
- *Initial checkin of SNAP application  to the InsightApplications tree
- *
- *Revision 1.5  2003/07/12 01:34:18  pauly
- *More final changes before ITK checkin
- *
- *Revision 1.4  2003/07/11 23:29:17  pauly
- **** empty log message ***
- *
- *Revision 1.3  2003/07/11 21:25:12  pauly
- *Code cleanup for ITK checkin
- *
- *Revision 1.2  2003/06/08 16:11:42  pauly
- *User interface changes
- *Automatic mesh updating in SNAP mode
- *
- *Revision 1.1  2003/03/07 19:29:47  pauly
- *Initial checkin
- *
- *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
- *Started the project repository
- *
- *
- *Revision 1.2  2002/03/08 14:06:30  moon
- *Added Header and Log tags to all files
- **/
+
diff --git a/Logic/Mesh/MultiLabelMeshPipeline.cxx b/Logic/Mesh/MultiLabelMeshPipeline.cxx
new file mode 100644
index 0000000..f8689c7
--- /dev/null
+++ b/Logic/Mesh/MultiLabelMeshPipeline.cxx
@@ -0,0 +1,392 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: MultiLabelMeshPipeline.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/06/28 18:45:08 $
+  Version:   $Revision: 1.4 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+// Borland compiler is very lazy so we need to instantiate the template
+//  by hand 
+#if defined(__BORLANDC__)
+#include "SNAPBorlandDummyTypes.h"
+#endif
+
+#include "MultiLabelMeshPipeline.h"
+
+// SNAP includes
+#include "IRISVectorTypesToITKConversion.h"
+#include "VTKMeshPipeline.h"
+#include "MeshOptions.h"
+
+// ITK includes
+#include "itkRegionOfInterestImageFilter.h"
+#include "itkBinaryThresholdImageFilter.h"
+#include "itkImageRegionConstIteratorWithIndex.h"
+
+using namespace std;
+
+MultiLabelMeshPipeline
+::MultiLabelMeshPipeline()
+{
+  // Initialize the region of interest filter
+  m_ROIFilter = ROIFilter::New();
+  m_ROIFilter->ReleaseDataFlagOn();
+
+  // Define the binary thresholding filter that will map the image onto the 
+  // range -1 to 1
+  m_ThrehsoldFilter = ThresholdFilter::New();
+  m_ThrehsoldFilter->SetInput(m_ROIFilter->GetOutput());
+  m_ThrehsoldFilter->ReleaseDataFlagOn();
+  m_ThrehsoldFilter->SetInsideValue(1.0f);
+  m_ThrehsoldFilter->SetOutsideValue(-1.0f);
+
+  // Initialize the VTK Processing Pipeline
+  m_VTKPipeline = new VTKMeshPipeline();
+  m_VTKPipeline->SetImage(m_ThrehsoldFilter->GetOutput());
+
+  // Set the initial mesh options
+  m_MeshOptions = MeshOptions::New();
+  m_VTKPipeline->SetMeshOptions(m_MeshOptions);
+}
+
+MultiLabelMeshPipeline
+::~MultiLabelMeshPipeline()
+{
+  delete m_VTKPipeline;
+}
+
+void
+MultiLabelMeshPipeline
+::SetMeshOptions(const MeshOptions *options)
+{
+  // Store the options
+  if(*m_MeshOptions != *options)
+    {
+    // Save the options
+    m_MeshOptions->DeepCopy(options);
+
+    // Apply the options to the internal pipeline
+    m_VTKPipeline->SetMeshOptions(m_MeshOptions);
+
+    // Clear the cached stuff
+    m_MeshInfo.clear();
+    }
+}
+
+unsigned long
+MultiLabelMeshPipeline
+::GetVoxelsInBoundingBox(LabelType label) const
+{
+  return m_BoundingBox[label].GetNumberOfPixels();
+}
+
+AllPurposeProgressAccumulator *
+MultiLabelMeshPipeline
+::GetProgressAccumulator()
+{
+  return m_VTKPipeline->GetProgressAccumulator();
+}
+  
+
+#include <ctime>
+
+bool
+MultiLabelMeshPipeline
+::ComputeMesh(LabelType label, vtkPolyData *outMesh)
+{
+  // The label must be present in the image
+  if(m_Histogram[label] == 0)
+    return false;
+
+  // TODO: make this more elegant
+  InputImageType::RegionType bbWiderRegion = m_BoundingBox[label];
+  bbWiderRegion.PadByRadius(5);
+  bbWiderRegion.Crop(m_InputImage->GetLargestPossibleRegion()); 
+
+  // Pass the region to the ROI filter and propagate the filter
+  m_ROIFilter->SetInput(m_InputImage);
+  m_ROIFilter->SetRegionOfInterest(bbWiderRegion);
+  m_ROIFilter->Update();
+  
+  // Set the parameters for the thresholding filter
+  m_ThrehsoldFilter->SetLowerThreshold(label);
+  m_ThrehsoldFilter->SetUpperThreshold(label);
+  m_ThrehsoldFilter->UpdateLargestPossibleRegion();
+
+  // Graft the polydata to the last filter in the pipeline
+  m_VTKPipeline->SetImage(m_ThrehsoldFilter->GetOutput());
+  m_VTKPipeline->ComputeMesh(outMesh);
+
+  // Done
+  return true;
+}
+
+#include "itkImageLinearConstIteratorWithIndex.h"
+#include "itk_zlib.h"
+
+inline unsigned long rotl(unsigned long value, int shift)
+{
+  return (value << shift) | (value >> (32 - shift));
+}
+
+void MultiLabelMeshPipeline::UpdateMeshInfoHelper(
+    MultiLabelMeshPipeline::MeshInfo *current_meshinfo,
+    const itk::Index<3> &run_start,
+    itk::ImageLinearConstIteratorWithIndex<MultiLabelMeshPipeline::InputImageType> &it,
+    unsigned long pos)
+{
+  // The end of the run, i.e., the last voxel that matched the label of run_start
+  itk::Index<3> run_end = run_start; run_end[0] = pos - 1;
+
+  // Append the start index to the checksum
+  for(int d = 0; d < 3; d++)
+    {
+    long p_start = run_start[d], p_end = run_end[d];
+    current_meshinfo->CheckSum =
+        adler32(current_meshinfo->CheckSum,
+                (unsigned char *) &p_start,
+                sizeof(itk::Index<3>::IndexValueType));
+
+    current_meshinfo->CheckSum =
+        adler32(current_meshinfo->CheckSum,
+                (unsigned char *) &p_end,
+                sizeof(itk::Index<3>::IndexValueType));
+    }
+
+  // Update the extents
+  unsigned long run_length = pos - run_start[0];
+  if(current_meshinfo->Count == 0)
+    {
+    current_meshinfo->BoundingBox[0] = run_start;
+    current_meshinfo->BoundingBox[1] = run_end;
+    }
+  else
+    {
+    for(int d = 0; d < 3; d++)
+      {
+      if(run_start[d] < current_meshinfo->BoundingBox[0][d])
+        current_meshinfo->BoundingBox[0][d] = run_start[d];
+      if(run_end[d] > current_meshinfo->BoundingBox[1][d])
+        current_meshinfo->BoundingBox[1][d] = run_end[d];
+      }
+    }
+
+  // Add the number of pixels traversed to the index
+  current_meshinfo->Count += run_length;
+}
+
+void MultiLabelMeshPipeline::UpdateMeshes(itk::Command *progressCommand)
+{
+  // Create a temporary table of mesh info
+  MeshInfoMap meshmap;
+
+  // Current label and current mesh map
+  LabelType current_label = 0;
+  MeshInfo *current_meshinfo = NULL;
+  itk::Index<3> run_start;
+
+  // The length of a line
+  unsigned long line_length = m_InputImage->GetLargestPossibleRegion().GetSize()[0];
+
+  // Iterate through the image updating the mesh map. This code takes advantage
+  // of the organization of label data. Rather than updating the extents after
+  // each pixel read, the code collects runs of pixels of the same label and
+  // updates once the run ends (a pixel of another label is found or the end
+  // of a line of pixels is reached). This makes for much more efficient code.
+  typedef itk::ImageLinearConstIteratorWithIndex<InputImageType> InputIterator;
+  InputIterator it(m_InputImage, m_InputImage->GetLargestPossibleRegion());
+  while( !it.IsAtEnd() )
+    {
+    // When starting a new line, we must record the pass through the
+    // last line and reset the current objects
+    if(current_label)
+      UpdateMeshInfoHelper(current_meshinfo, run_start, it, line_length);
+
+    // Reset the current objects
+    current_label = it.Get();
+    if(current_label)
+      {
+      current_meshinfo = &meshmap[current_label];
+      run_start = it.GetIndex();
+      }
+
+    // Take one step forward
+    ++it;
+
+    // Iterate through the line
+    while(!it.IsAtEndOfLine())
+      {
+      // The the current label
+      LabelType label = it.Get();
+
+      // If the label does not match the current label, do the same deal
+      if(label != current_label)
+        {
+        // Update the current mesh info
+        if(current_label)
+          UpdateMeshInfoHelper(current_meshinfo, run_start, it, it.GetIndex()[0]);
+
+        // Reset the current objects
+        current_label = it.Get();
+        if(current_label)
+          {
+          current_meshinfo = &meshmap[current_label];
+          run_start = it.GetIndex();
+          }
+        }
+
+      // Go to the next voxel
+      ++it;
+      }
+
+    // Go to the next line
+    it.NextLine();
+    }
+
+  // At the end of the iteration, one more update!
+  if(current_label)
+    UpdateMeshInfoHelper(current_meshinfo, run_start, it, line_length);
+
+  // At this point, meshmap has the number of voxels for every label, as well
+  // as the checksum for every label and the extent for every label. Now we
+  // can determine which meshes actually need to be updated
+
+  // First we go through the stored mesh map and delete all meshes that are no
+  // longer present in the image
+  for(MeshInfoMap::iterator it = m_MeshInfo.begin(); it != m_MeshInfo.end();)
+    {
+    if(meshmap.find(it->first) == meshmap.end())
+      m_MeshInfo.erase(it++);
+    else
+      it++;
+    }
+
+
+  // Deal with progress accumulation
+  SmartPtr<AllPurposeProgressAccumulator> progress = AllPurposeProgressAccumulator::New();
+  progress->AddObserver(itk::ProgressEvent(), progressCommand);
+
+  // Next we check which meshes are new or updated and mark them as needing to
+  // be recomputed
+  for(MeshInfoMap::const_iterator it = meshmap.begin(); it != meshmap.end(); ++it)
+    {
+    // Get the cached mesh info for this label
+    MeshInfo &info = m_MeshInfo[it->first];
+
+    // Compare the values
+    if(info.Count != it->second.Count || info.CheckSum != it->second.CheckSum)
+      {
+      // Cache the current information
+      info.CheckSum = it->second.CheckSum;
+      info.Count = it->second.Count;
+      info.BoundingBox[0] = it->second.BoundingBox[0];
+      info.BoundingBox[1] = it->second.BoundingBox[1];
+      info.Mesh = NULL;
+
+      // Capture progress from this mesh
+      progress->RegisterSource(m_VTKPipeline->GetProgressAccumulator(), info.Count);
+      }
+    }
+
+  // Now compute the meshes
+  for(MeshInfoMap::iterator it = m_MeshInfo.begin(); it != m_MeshInfo.end(); it++)
+    {
+    if(it->second.Mesh == NULL)
+      {
+      // Create the mesh
+      MeshInfo &mi = it->second;
+      mi.Mesh = vtkSmartPointer<vtkPolyData>::New();
+
+      // TODO: make this more elegant
+      InputImageType::RegionType bbWiderRegion;
+      for(int d = 0; d < 3; d++)
+        {
+        unsigned long len =
+            (unsigned long) (1 + mi.BoundingBox[1][d] - mi.BoundingBox[0][d]);
+        bbWiderRegion.SetIndex(d, mi.BoundingBox[0][d]);
+        bbWiderRegion.SetSize(d, len);
+        }
+      bbWiderRegion.PadByRadius(5);
+      bbWiderRegion.Crop(m_InputImage->GetLargestPossibleRegion());
+
+      // Pass the region to the ROI filter and propagate the filter
+      m_ROIFilter->SetInput(m_InputImage);
+      m_ROIFilter->SetRegionOfInterest(bbWiderRegion);
+      m_ROIFilter->Update();
+
+      // Set the parameters for the thresholding filter
+      m_ThrehsoldFilter->SetLowerThreshold(it->first);
+      m_ThrehsoldFilter->SetUpperThreshold(it->first);
+      m_ThrehsoldFilter->UpdateLargestPossibleRegion();
+
+      // Graft the polydata to the last filter in the pipeline
+      m_VTKPipeline->SetImage(m_ThrehsoldFilter->GetOutput());
+      m_VTKPipeline->ComputeMesh(it->second.Mesh);
+
+      // Update progress
+      progress->StartNextRun(m_VTKPipeline->GetProgressAccumulator());
+      }
+    }
+
+  // Clean up the progress
+  progress->UnregisterAllSources();
+}
+
+void 
+MultiLabelMeshPipeline
+::SetImage(MultiLabelMeshPipeline::InputImageType *image)
+{
+  if(m_InputImage != image)
+    {
+    m_InputImage = image;
+    m_MeshInfo.clear();
+    }
+}
+
+
+MultiLabelMeshPipeline::MeshInfo::MeshInfo()
+{
+  this->Mesh = NULL;
+  this->Count = 0;
+  this->CheckSum = adler32(0L, NULL, 0);
+}
+
+MultiLabelMeshPipeline::MeshInfo::~MeshInfo()
+{
+}
+
+
+std::map<LabelType, vtkSmartPointer<vtkPolyData> > MultiLabelMeshPipeline::GetMeshCollection()
+{
+  std::map<LabelType, vtkSmartPointer<vtkPolyData> > meshes;
+  for(MeshInfoMap::iterator it = m_MeshInfo.begin(); it != m_MeshInfo.end(); ++it)
+    meshes[it->first] = it->second.Mesh;
+  return meshes;
+}
diff --git a/Logic/Mesh/MultiLabelMeshPipeline.h b/Logic/Mesh/MultiLabelMeshPipeline.h
new file mode 100644
index 0000000..fde734a
--- /dev/null
+++ b/Logic/Mesh/MultiLabelMeshPipeline.h
@@ -0,0 +1,187 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: MultiLabelMeshPipeline.h,v $
+  Language:  C++
+  Date:      $Date: 2009/01/23 20:09:38 $
+  Version:   $Revision: 1.3 $
+  Copyright (c) 2007 Paul A. Yushkevich
+  
+  This file is part of ITK-SNAP 
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information. 
+
+=========================================================================*/
+#ifndef __MultiLabelMeshPipeline_h_
+#define __MultiLabelMeshPipeline_h_
+
+#include "SNAPCommon.h"
+#include "itkImageRegion.h"
+#include "itkSmartPointer.h"
+#include "vtkSmartPointer.h"
+#include "itksys/MD5.h"
+#include "itkObjectFactory.h"
+
+// Forward reference to itk classes
+namespace itk {
+  template <class TPixel,unsigned int VDimension> class Image;
+  template <class TInputImage, class TOutputImage> class RegionOfInterestImageFilter;
+  template <class TInputImage, class TOutputImage> class BinaryThresholdImageFilter;
+  template <class TImage> class ImageLinearConstIteratorWithIndex;
+}
+
+
+// Forward references
+class MeshOptions;
+class VTKMeshPipeline;
+class vtkPolyData;
+class AllPurposeProgressAccumulator;
+
+
+/**
+ * \class MultiLabelMeshPipeline
+ * \brief A small pipeline used to convert a multi-label segmentation image to
+ * a collection of VTK meshes.
+ *
+ * For each label, the pipeline uses the checksum mechanism to keep track of
+ * whether it has been updated relative to the corresponding mesh. This makes
+ * it possible for selective mesh recomputation, leading to fast mesh computation
+ * even for big segmentations.
+ */
+class MultiLabelMeshPipeline : public itk::Object
+{
+public:
+
+  irisITKObjectMacro(MultiLabelMeshPipeline, itk::Object)
+
+  /** Input image type */
+  typedef itk::Image<LabelType,3> InputImageType;
+  typedef itk::SmartPointer<InputImageType> InputImagePointer;
+  
+  /** Set the input segmentation image */
+  void SetImage(InputImageType *input);
+
+  /** Compute the bounding boxes for different regions.  Prerequisite for 
+   * calling ComputeMesh(). Returns the total number of voxels in all boxes */
+  unsigned long ComputeBoundingBoxes();
+
+  unsigned long GetVoxelsInBoundingBox(LabelType label) const;
+
+  /** Set the mesh options for this filter */
+  void SetMeshOptions(const MeshOptions *options);
+
+  /** Can we compute a mesh for this label? */
+  bool CanComputeMesh(LabelType label)
+  {
+    return m_Histogram[label] > 0l;
+  }
+
+  /** Compute a mesh for a particular color label.  Returns true if 
+   * the color label is not present in the image */
+  bool ComputeMesh(LabelType label, vtkPolyData *outData);
+
+  /** Update the meshes */
+  void UpdateMeshes(itk::Command *progressCommand);
+
+  /** Get the collection of computed meshes */
+  std::map<LabelType, vtkSmartPointer<vtkPolyData> > GetMeshCollection();
+
+  
+  /** Get the progress accumulator from the VTK mesh pipeline */
+  AllPurposeProgressAccumulator *GetProgressAccumulator();
+
+protected:
+
+  /** Constructor, which builds the pipeline */
+  MultiLabelMeshPipeline();
+
+  /** Deallocate the pipeline filters */
+  ~MultiLabelMeshPipeline();
+
+private:
+  // Type definitions for the various filters used by this object
+  typedef itk::Image<float,3>                InternalImageType;
+  typedef itk::SmartPointer<InternalImageType>       InternalImagePointer;
+  
+  typedef itk::RegionOfInterestImageFilter<
+    InputImageType,InputImageType>                   ROIFilter;
+  typedef itk::SmartPointer<ROIFilter>               ROIFilterPointer;
+  
+  typedef itk::BinaryThresholdImageFilter<
+    InputImageType,InternalImageType>                ThresholdFilter;
+  typedef itk::SmartPointer<ThresholdFilter>         ThresholdFilterPointer;
+  
+  // Current set of mesh options
+  SmartPtr<MeshOptions>       m_MeshOptions;
+
+  // The input image
+  InputImagePointer           m_InputImage;
+
+  // The ROI extraction filter used for constructing a bounding box
+  ROIFilterPointer            m_ROIFilter;
+
+  // The thresholding filter used to map intensity in the bounding box to
+  // standardized range
+  ThresholdFilterPointer      m_ThrehsoldFilter;
+
+  // Cached information about a VTK mesh
+  struct MeshInfo
+  {
+    // The pointer to the mesh
+    vtkSmartPointer<vtkPolyData> Mesh;
+
+    // The checksum for the mesh
+    unsigned long CheckSum;
+
+    // The extents of the bounding box
+    Vector3i BoundingBox[2];
+
+    // The number of voxels
+    unsigned long Count;
+
+    MeshInfo();
+    ~MeshInfo();
+  };
+
+  // Collection of mesh data for labels present in the image
+  typedef std::map<LabelType, MeshInfo> MeshInfoMap;
+  MeshInfoMap m_MeshInfo;
+
+  // Set of bounding boxes
+  itk::ImageRegion<3>         m_BoundingBox[MAX_COLOR_LABELS];
+
+  // Histogram of the image
+  long                        m_Histogram[MAX_COLOR_LABELS];
+
+  // The VTK pipeline
+  VTKMeshPipeline *           m_VTKPipeline;
+
+  // Helper routine for the update command
+  void UpdateMeshInfoHelper(
+      MeshInfo *current_meshinfo,
+      const itk::Index<3> &run_start,
+      itk::ImageLinearConstIteratorWithIndex<InputImageType> &it,
+      unsigned long pos);
+};
+
+#endif
diff --git a/Logic/Mesh/VTKMeshPipeline.cxx b/Logic/Mesh/VTKMeshPipeline.cxx
index bcdae0b..2e906aa 100644
--- a/Logic/Mesh/VTKMeshPipeline.cxx
+++ b/Logic/Mesh/VTKMeshPipeline.cxx
@@ -35,6 +35,7 @@
 #include "VTKMeshPipeline.h"
 #include "AllPurposeProgressAccumulator.h"
 #include "ImageWrapper.h"
+#include "MeshOptions.h"
 #include <map>
 
 using namespace std;
@@ -46,6 +47,9 @@ VTKMeshPipeline
   // Initialize the progress tracker
   m_Progress = AllPurposeProgressAccumulator::New();
 
+  // Initialize the options
+  m_MeshOptions = MeshOptions::New();
+
   // Initialize all the filters involved in the transaction, but do not
   // pipe the inputs and outputs between these filters. The piping is quite
   // complicated and depends on the set of options that the user wishes to 
@@ -134,7 +138,7 @@ VTKMeshPipeline
 
 void
 VTKMeshPipeline
-::SetMeshOptions(const MeshOptions &options)
+::SetMeshOptions(MeshOptions *options)
 {
   // Store the options
   m_MeshOptions = options;
@@ -143,106 +147,106 @@ VTKMeshPipeline
   m_Progress->UnregisterAllSources();
 
   // Define the current pipeline end-point
-  vtkImageData *pipeImageTail = m_VTKImporter->GetOutput();
-  vtkPolyData *pipePolyTail = NULL;
+  vtkAlgorithmOutput *pipeImageTail = m_VTKImporter->GetOutputPort();
+  vtkAlgorithmOutput *pipePolyTail = NULL;
 
   // Route the pipeline according to the settings
   // 1. Check if Gaussian smoothing will be used
 
-  if(options.GetUseGaussianSmoothing()) 
+  if(options->GetUseGaussianSmoothing())
     {    
     // The Gaussian filter is enabled
-    m_VTKGaussianFilter->SetInput(pipeImageTail);
+    m_VTKGaussianFilter->SetInputConnection(pipeImageTail);
     m_Progress->RegisterSource(m_VTKGaussianFilter, 10.0f);
-    pipeImageTail = m_VTKGaussianFilter->GetOutput();
+    pipeImageTail = m_VTKGaussianFilter->GetOutputPort();
 
     // Apply parameters to the Gaussian filter
-    float sigma = options.GetGaussianStandardDeviation();
+    float sigma = options->GetGaussianStandardDeviation();
 
     // Sigma is in millimeters
-    const double *spacing = m_InputImage->GetSpacing().GetDataPointer();
-    m_VTKGaussianFilter->SetStandardDeviation(
-      sigma / spacing[0], sigma / spacing[1], sigma / spacing[2]);
-    m_VTKGaussianFilter->SetRadiusFactors(
-      3 * sigma / spacing[0], 3 * sigma / spacing[1], 3 * sigma / spacing[2]);
+    m_VTKGaussianFilter->SetStandardDeviation(sigma, sigma, sigma);
+
+    // TODO: we are ignoring the maximum error parameter!
+    m_VTKGaussianFilter->SetRadiusFactors(1.5, 1.5, 1.5);
     }
 
   // 2. Set input to the appropriate contour filter
 
   // Marching cubes gets the tail
-  m_MarchingCubesFilter->SetInput(pipeImageTail);
+  m_MarchingCubesFilter->SetInputConnection(pipeImageTail);
   m_Progress->RegisterSource(m_MarchingCubesFilter, 10.0f);
-  pipePolyTail = m_MarchingCubesFilter->GetOutput();
+  pipePolyTail = m_MarchingCubesFilter->GetOutputPort();
 
   // 2.5 Pipe marching cubes output to the transform
-  m_TransformFilter->SetInput(pipePolyTail);
+  m_TransformFilter->SetInputConnection(pipePolyTail);
   m_Progress->RegisterSource(m_TransformFilter, 1.0f);
-  pipePolyTail = m_TransformFilter->GetOutput();
+  pipePolyTail = m_TransformFilter->GetOutputPort();
 
   // 3. Check if decimation is required
-  if(options.GetUseDecimation())
+  if(options->GetUseDecimation())
     {
 
     // Decimate filter gets the pipe tail
-    m_DecimateFilter->SetInput(pipePolyTail);
+    m_DecimateFilter->SetInputConnection(pipePolyTail);
     m_Progress->RegisterSource(m_DecimateFilter, 5.0);
-    pipePolyTail = m_DecimateFilter->GetOutput();
+    pipePolyTail = m_DecimateFilter->GetOutputPort();
 
     // Apply parameters to the decimation filter
     m_DecimateFilter->SetTargetReduction(
-      options.GetDecimateTargetReduction());
+      options->GetDecimateTargetReduction());
 
     m_DecimateFilter->SetMaximumError(
-      options.GetDecimateInitialError());
+      options->GetDecimateMaximumError());
 
     m_DecimateFilter->SetFeatureAngle(
-      options.GetDecimateFeatureAngle());
+      options->GetDecimateFeatureAngle());
 
     m_DecimateFilter->SetPreserveTopology(
-      options.GetDecimatePreserveTopology());
+      options->GetDecimatePreserveTopology());
 
     } // If decimate enabled
 
   // 4. Compute the normals (non-patented only)
 
   // 5. Include/exclude mesh smoothing filter
-  if(options.GetUseMeshSmoothing())
+  if(options->GetUseMeshSmoothing())
     {
     // Pipe smoothed output into the pipeline
-    m_PolygonSmoothingFilter->SetInput(pipePolyTail);
+    m_PolygonSmoothingFilter->SetInputConnection(pipePolyTail);
     m_Progress->RegisterSource(m_PolygonSmoothingFilter, 3.0);
-    pipePolyTail = m_PolygonSmoothingFilter->GetOutput();
+    pipePolyTail = m_PolygonSmoothingFilter->GetOutputPort();
 
     // Apply parameters to the mesh smoothing filter
     m_PolygonSmoothingFilter->SetNumberOfIterations(
-      options.GetMeshSmoothingIterations());
+      options->GetMeshSmoothingIterations());
 
     m_PolygonSmoothingFilter->SetRelaxationFactor(
-      options.GetMeshSmoothingRelaxationFactor()); 
+      options->GetMeshSmoothingRelaxationFactor());
 
     m_PolygonSmoothingFilter->SetFeatureAngle(
-      options.GetMeshSmoothingFeatureAngle());
+      options->GetMeshSmoothingFeatureAngle());
 
     m_PolygonSmoothingFilter->SetFeatureEdgeSmoothing(
-      options.GetMeshSmoothingFeatureEdgeSmoothing());
+      options->GetMeshSmoothingFeatureEdgeSmoothing());
 
     m_PolygonSmoothingFilter->SetBoundarySmoothing(
-      options.GetMeshSmoothingBoundarySmoothing());
+      options->GetMeshSmoothingBoundarySmoothing());
 
     m_PolygonSmoothingFilter->SetConvergence(
-      options.GetMeshSmoothingConvergence());
+      options->GetMeshSmoothingConvergence());
     }
 
   // 6. Pipe in the final output into the stripper
-  m_StripperFilter->SetInput(pipePolyTail);
+  m_StripperFilter->SetInputConnection(pipePolyTail);
   m_Progress->RegisterSource(m_StripperFilter, 2.0);
 }
 
 #include <ctime>
+#include "itkImageFileWriter.h"
 
 void
 VTKMeshPipeline
-::ComputeMesh(vtkPolyData *outMesh)
+::ComputeMesh(vtkPolyData *outMesh, itk::FastMutexLock *lock)
 {
   // Reset the progress meter
   m_Progress->ResetProgress();
@@ -258,13 +262,12 @@ VTKMeshPipeline
   m_VTKExporter->SetInput(m_InputImage);
   m_VTKImporter->Modified();
 
-  // Update the pipeline
-  // m_StripperFilter->Update();
+  // Update the importer
+  if(lock) lock->Lock();
+  m_VTKImporter->Update();
+  if(lock) lock->Unlock();
 
-  // Set the source of outMesh to null
-  // outMesh->UpdateInformation();
-  // outMesh->Update();
-  // m_StripperFilter->UnRegister(m_StripperFilter->GetOutput());
+  // Update the pipeline
   m_StripperFilter->Update();
 
   // In the case that the jacobian of the transform is negative,
@@ -278,6 +281,9 @@ VTKMeshPipeline
         nrm->SetComponent(i,j,-nrm->GetComponent(i,j));
     nrm->Modified();
     }
+
+  // Disconnect pipeline
+  m_StripperFilter->SetOutput(NULL);
 }
 
 void
@@ -289,7 +295,7 @@ VTKMeshPipeline
 
   // Compute the transform from VTK coordinates to NIFTI/RAS coordinates
   vnl_matrix_fixed<double, 4, 4> vtk2nii = 
-    ImageWrapper<float>::ConstructVTKtoNiftiTransform(
+    ImageWrapperBase::ConstructVTKtoNiftiTransform(
       image->GetDirection().GetVnlMatrix(),
       image->GetOrigin().GetVnlVector(),
       image->GetSpacing().GetVnlVector());
diff --git a/Logic/Mesh/VTKMeshPipeline.h b/Logic/Mesh/VTKMeshPipeline.h
index b5c66b0..1596f68 100644
--- a/Logic/Mesh/VTKMeshPipeline.h
+++ b/Logic/Mesh/VTKMeshPipeline.h
@@ -36,12 +36,11 @@
 #define __VTKMeshPipeline_h_
 
 #include "SNAPCommon.h"
-#include "MeshOptions.h"
 #include "AllPurposeProgressAccumulator.h"
 
 // ITK includes (this file is not widely included in SNAP, so it's OK
 // to include a bunch of headers here).
-#include <itkOrientedImage.h>
+#include <itkImage.h>
 #include <itkVTKImageExport.h>
 
 // VTK includes
@@ -66,6 +65,7 @@
 typedef float vtkFloatingPointType;
 #endif
 
+class MeshOptions;
 class VTKProgressAccumulator;
 
 /**
@@ -77,17 +77,17 @@ class VTKMeshPipeline
 {
 public:
   /** Input image type */
-  typedef itk::OrientedImage<float,3> ImageType;
+  typedef itk::Image<float,3> ImageType;
   typedef itk::SmartPointer<ImageType> ImagePointer;
   
   /** Set the input segmentation image */
   void SetImage(ImageType *input);
 
   /** Set the mesh options for this filter */
-  void SetMeshOptions(const MeshOptions &options);
+  void SetMeshOptions(MeshOptions *options);
 
   /** Compute a mesh for a particular color label */
-  void ComputeMesh(vtkPolyData *outData);
+  void ComputeMesh(vtkPolyData *outData, itk::FastMutexLock *lock = NULL);
 
   /** Get the progress accumulator */
   AllPurposeProgressAccumulator *GetProgressAccumulator()
@@ -106,7 +106,7 @@ private:
   typedef itk::SmartPointer<VTKExportType> VTKExportPointer;
   
   // Current set of mesh options
-  MeshOptions m_MeshOptions;
+  SmartPtr<MeshOptions> m_MeshOptions;
 
   // The input image
   ImagePointer m_InputImage;
diff --git a/Logic/Preprocessing/EdgePreprocessingImageFilter.h b/Logic/Preprocessing/EdgePreprocessingImageFilter.h
index 037c3ce..e04117c 100644
--- a/Logic/Preprocessing/EdgePreprocessingImageFilter.h
+++ b/Logic/Preprocessing/EdgePreprocessingImageFilter.h
@@ -36,26 +36,33 @@
 #define __EdgePreprocessingFilter_h_
 
 #include "itkCommand.h"
-#include "itkCastImageFilter.h"
-#include "itkOrientedImage.h"
-#include "itkDiscreteGaussianImageFilter.h"
-#include "itkGradientMagnitudeImageFilter.h"
-#include "itkImageAdaptor.h"
-#include "itkMinimumMaximumImageCalculator.h"
-#include "itkProgressAccumulator.h"
-#include "itkRescaleIntensityImageFilter.h"
-#include "itkUnaryFunctorImageFilter.h"
+#include "itkImageToImageFilter.h"
 #include "EdgePreprocessingSettings.h"
 
+#include "GPUSettings.h"
+#ifdef SNAP_USE_GPU
+#include "CPUImageToGPUImageFilter.h"
+#include <itkGPUDiscreteGaussianImageFilter.h>
+#endif
+
+namespace itk {
+  template <class TIn, class TOut> class DiscreteGaussianImageFilter;
+  template <class TIn, class TOut> class GradientMagnitudeImageFilter;
+  template <class TIn, class TOut, class Fun> class UnaryFunctorImageFilter;
+  template <class TIn, class TOut> class StreamingImageFilter;
+  template <class TIn, class TOut> class CastImageFilter;
+}
+
+
 /**
  * The g() function that remaps the gradient magnitude image to the 
  * range 0 to 1.  
  */
-template<class TInput, class TOutput>
+template<class TInput>
 class EdgeRemappingFunctor
   {
 public:
-  typedef EdgeRemappingFunctor<TInput, TOutput> Self;
+  typedef EdgeRemappingFunctor<TInput> Self;
 
   void SetParameters(float intensityMin, float intensityMax,
                      float exponent, float kappa)
@@ -66,11 +73,12 @@ public:
     m_IntensityScale = 1.0f / (intensityMax - intensityMin);
   }
 
-  inline TOutput operator()(const TInput &x)
+  // This operator maps the input value into the range of short integers
+  inline short operator()(const TInput &x)
   {
     float xNorm = (static_cast<float>(x)-m_IntensityBase)*m_IntensityScale;
     float y = 1.0 / (1.0 + pow(xNorm * m_KappaFactor,m_Exponent));
-    return static_cast<TOutput> (y);
+    return static_cast<short> (y * 0x7fff);
   }
 
   bool operator ==(const Self &z)
@@ -100,7 +108,7 @@ private:
  * This functor implements a Gaussian blur, followed by a gradient magnitude
  * operator, followed by a 'contrast enhancement' intensity remapping filter.
  */
-template <typename TInputImage,typename TOutputImage = TInputImage>
+template <typename TInputImage,typename TOutputImage>
 class EdgePreprocessingImageFilter: 
   public itk::ImageToImageFilter<TInputImage,TOutputImage>
 {
@@ -119,16 +127,24 @@ public:
 
   /** Pixel Type of the output image */
   typedef TOutputImage                                  OutputImageType;
-  typedef typename OutputImageType::PixelType           OutputPixelType;
   typedef itk::SmartPointer<OutputImageType>         OutputImagePointer;
+  typedef typename Superclass::OutputImageRegionType
+                                                  OutputImageRegionType;
 
   /** Type used for internal calculations */
   typedef float                                                RealType;
-  typedef itk::OrientedImage<RealType,3>              InternalImageType;
+  typedef itk::Image<RealType,3>                      InternalImageType;
   typedef itk::SmartPointer<InternalImageType>     InternalImagePointer;
 
+#ifdef SNAP_USE_GPU
+  typedef typename itk::GPUTraits<InternalImageType>::Type
+                                                   GPUInternalImageType;
+  typedef itk::SmartPointer<GPUInternalImageType> 
+                                                GPUInternalImagePointer;
+#endif
+
   /** Functor type used for thresholding */
-  typedef EdgeRemappingFunctor<RealType,OutputPixelType>    FunctorType;
+  typedef EdgeRemappingFunctor<RealType>                    FunctorType;
 
   /** Method for creation through the object factory. */
   itkNewMacro(Self)
@@ -138,16 +154,24 @@ public:
                       TInputImage::ImageDimension);
 
   /** Assign new edge processing settings */
-  void SetEdgePreprocessingSettings(const EdgePreprocessingSettings &settings);
+  void SetParameters(EdgePreprocessingSettings *parameters);
+
+  /** Set the maximum possible value of the gradient magnitude of the input
+    image. This should be computed by applying a gradient magnitude filter
+    to the input image. Must be provided for the filter to work. */
+  itkSetMacro(InputImageMaximumGradientMagnitude, double)
+
+  /** Get the parameters pointer */
+  EdgePreprocessingSettings *GetParameters();
 
 protected:
 
   EdgePreprocessingImageFilter();
-  virtual ~EdgePreprocessingImageFilter() {};
+  virtual ~EdgePreprocessingImageFilter() {}
   void PrintSelf(std::ostream& os, itk::Indent indent) const;
   
   /** Generate Data */
-  void GenerateData( void );
+  void GenerateData();
 
   /** 
    * This method maps an input region to an output region.  It's necessary to
@@ -157,50 +181,37 @@ protected:
 
 private:
 
-  /** The unary functor filter type used for remapping */
-  typedef itk::UnaryFunctorImageFilter<
-    InternalImageType,TOutputImage,FunctorType>      RemappingFilterType;
-  typedef typename RemappingFilterType::Pointer   RemappingFilterPointer;
-  
-  /** The min / max calculator used to compute gradient range */
-  typedef itk::MinimumMaximumImageCalculator<
-    InternalImageType>                                    CalculatorType;
-  typedef typename CalculatorType::Pointer             CalculatorPointer;
-
-  /** Adaptor used to cast to float */
-  typedef itk::CastImageFilter<
-    InputImageType,InternalImageType>                     CastFilterType;
-  typedef typename CastFilterType::Pointer             CastFilterPointer;
-  
-  /** Gaussian smoothing filter */
-  typedef itk::DiscreteGaussianImageFilter<
-    InternalImageType,InternalImageType>              GaussianFilterType;
-  typedef typename GaussianFilterType::Pointer     GaussianFilterPointer;
-  
-  /** Gradient magnitude filter */
-  typedef itk::GradientMagnitudeImageFilter<
-    InternalImageType,InternalImageType>              GradientFilterType;
-  typedef typename GradientFilterType::Pointer     GradientFilterPointer;
-
-  /** Intensity rescaling filter */
-  typedef itk::RescaleIntensityImageFilter<
-    InternalImageType,InternalImageType>               RescaleFilterType;
-  typedef typename RescaleFilterType::Pointer       RescaleFilterPointer;
-  
-  /** Progress accumulator object */
-  typedef itk::ProgressAccumulator::Pointer           AccumulatorPointer;
-
-  CastFilterPointer         m_CastFilter;
-  RemappingFilterPointer    m_RemappingFilter;
-  GaussianFilterPointer     m_GaussianFilter;
-  GradientFilterPointer     m_GradientFilter;
-  CalculatorPointer         m_Calculator;
-  RescaleFilterPointer      m_RescaleFilter;
-
-  EdgePreprocessingSettings m_EdgePreprocessingSettings;
-
-  /** Progress tracking object */
-  AccumulatorPointer        m_ProgressAccumulator;
+  double m_InputImageMaximumGradientMagnitude;
+
+  typedef itk::CastImageFilter<InputImageType, InternalImageType>   CastFilter;
+
+  typedef itk::DiscreteGaussianImageFilter<InternalImageType,
+                                           InternalImageType>       BlurFilter;
+
+#ifdef SNAP_USE_GPU
+  typedef CPUImageToGPUImageFilter<GPUInternalImageType>        GPUImageSource;
+  typedef itk::GPUDiscreteGaussianImageFilter<GPUInternalImageType,
+                                              GPUInternalImageType>
+                                                                 GPUBlurFilter;
+#endif
+
+  typedef itk::GradientMagnitudeImageFilter<InternalImageType,
+                                            InternalImageType>   GradMagFilter;
+
+  typedef itk::UnaryFunctorImageFilter<InternalImageType,
+                                       OutputImageType,
+                                       FunctorType>                RemapFilter;
+
+  SmartPtr<CastFilter> m_CastFilter;
+  SmartPtr<BlurFilter> m_BlurFilter;
+  SmartPtr<GradMagFilter> m_GradMagFilter;
+  SmartPtr<RemapFilter> m_RemapFilter;
+
+#ifdef SNAP_USE_GPU
+  SmartPtr<GPUImageSource> m_GPUImageSource;
+  SmartPtr<GPUBlurFilter>  m_GPUBlurFilter;
+#endif
+
 };
 
 #ifndef ITK_MANUAL_INSTANTIATION
diff --git a/Logic/Preprocessing/EdgePreprocessingImageFilter.txx b/Logic/Preprocessing/EdgePreprocessingImageFilter.txx
index 9a7d440..de11e0f 100644
--- a/Logic/Preprocessing/EdgePreprocessingImageFilter.txx
+++ b/Logic/Preprocessing/EdgePreprocessingImageFilter.txx
@@ -33,48 +33,65 @@
 
 =========================================================================*/
 
+#include <EdgePreprocessingSettings.h>
+#include <itkProgressAccumulator.h>
+
+#include <itkCastImageFilter.h>
+#include <itkDiscreteGaussianImageFilter.h>
+#include <itkGradientMagnitudeImageFilter.h>
+#include <itkUnaryFunctorImageFilter.h>
+#include <IRISException.h>
+
 template<typename TInputImage,typename TOutputImage>
 EdgePreprocessingImageFilter<TInputImage,TOutputImage>
 ::EdgePreprocessingImageFilter()
 {  
-  // Construct the adaptor
-  m_CastFilter = CastFilterType::New();
+  // Set the number of inputs to two (second is the parameters)
+  this->SetNumberOfIndexedInputs(2);
+
+  // Set the gradient magnitude to default value
+  m_InputImageMaximumGradientMagnitude = 0.0;
+
+  // Initialize the mini-pipeline
+  m_CastFilter = CastFilter::New();
   m_CastFilter->ReleaseDataFlagOn();
-  m_CastFilter->SetInput(this->GetInput()); 
-  
-  // Construct the Gaussian filter
-  m_GaussianFilter = GaussianFilterType::New();
-  m_GaussianFilter->SetUseImageSpacing(false);
-  m_GaussianFilter->ReleaseDataFlagOn();
-  m_GaussianFilter->SetInput(m_CastFilter->GetOutput());
-
-  // The gradient magnitude filter
-  m_GradientFilter = GradientFilterType::New();
-  m_GradientFilter->ReleaseDataFlagOn();
-  m_GradientFilter->SetInput(m_GaussianFilter->GetOutput());  
-
-  // The normalization filter
-  m_RescaleFilter = RescaleFilterType::New();
-  m_RescaleFilter->ReleaseDataFlagOn();
-  m_RescaleFilter->SetOutputMinimum(0.0f);
-  m_RescaleFilter->SetOutputMaximum(1.0f);
-  m_RescaleFilter->SetInput(m_GradientFilter->GetOutput());
-  
-  // Construct the Remapping filter
-  m_RemappingFilter = RemappingFilterType::New();
-  m_RemappingFilter->ReleaseDataFlagOn();
-  m_RemappingFilter->SetInput(m_RescaleFilter->GetOutput());
-
-  // Create the progress accumulator
-  m_ProgressAccumulator = itk::ProgressAccumulator::New();
-  m_ProgressAccumulator->SetMiniPipelineFilter(this);
-
-  // Register the filters with the progress accumulator
-  m_ProgressAccumulator->RegisterInternalFilter(m_CastFilter,0.1f);
-  m_ProgressAccumulator->RegisterInternalFilter(m_GaussianFilter,0.6f);
-  m_ProgressAccumulator->RegisterInternalFilter(m_GradientFilter,0.1f);
-  m_ProgressAccumulator->RegisterInternalFilter(m_RescaleFilter,0.1f);
-  m_ProgressAccumulator->RegisterInternalFilter(m_RemappingFilter,0.1f);
+
+#ifndef SNAP_USE_GPU
+  m_BlurFilter = BlurFilter::New();
+  m_BlurFilter->SetInput(m_CastFilter->GetOutput());
+  m_BlurFilter->ReleaseDataFlagOn();
+
+  // Prevent streaming inside the Gaussian filter because we will be streaming
+  // anyway. Too much streaming increases execution time unnecessarilty
+  m_BlurFilter->SetInternalNumberOfStreamDivisions(1);
+  m_BlurFilter->SetMaximumError(0.1);
+
+  m_GradMagFilter = GradMagFilter::New();
+  m_GradMagFilter->SetInput(m_BlurFilter->GetOutput());
+  m_GradMagFilter->ReleaseDataFlagOn();
+#else
+  m_GPUImageSource = GPUImageSource::New();
+  m_GPUImageSource->SetInput(m_CastFilter->GetOutput());
+
+  m_GPUBlurFilter = GPUBlurFilter::New();
+  m_GPUBlurFilter->SetInput(m_GPUImageSource->GetOutput());
+  m_GPUBlurFilter->ReleaseDataFlagOn();
+
+  // Prevent streaming inside the Gaussian filter because we will be streaming
+  // anyway. Too much streaming increases execution time unnecessarilty
+  m_GPUBlurFilter->SetInternalNumberOfStreamDivisions(1);
+  m_GPUBlurFilter->SetMaximumError(0.1);
+  //m_ROIFilter = ROIFilter::New();
+  //m_ROIFilter->SetInput(m_GPUBlurFilter->GetOutput());
+
+  m_GradMagFilter = GradMagFilter::New();
+  m_GradMagFilter->SetInput(m_GPUBlurFilter->GetOutput());
+  //m_GradMagFilter->SetInput(m_ROIFilter->GetOutput());
+  m_GradMagFilter->ReleaseDataFlagOn();
+#endif
+
+  m_RemapFilter = RemapFilter::New();
+  m_RemapFilter->SetInput(m_GradMagFilter->GetOutput());
 }
 
 template<typename TInputImage,typename TOutputImage>
@@ -86,39 +103,52 @@ EdgePreprocessingImageFilter<TInputImage,TOutputImage>
   const typename InputImageType::ConstPointer inputImage = this->GetInput();
   typename OutputImageType::Pointer outputImage = this->GetOutput();
 
-  // Initialize the progress counter
-  m_ProgressAccumulator->ResetProgress();
+  // Get the settings
+  EdgePreprocessingSettings *settings = this->GetParameters();
+
+  // Settings must be set!
+  if(!settings)
+    throw IRISException("Parameters not set in EdgePreprocessingImageFilter");
+
+  itk::ProgressAccumulator::Pointer pac = itk::ProgressAccumulator::New();
+  pac->SetMiniPipelineFilter(this);
 
-  // Allocate the output image
-  outputImage->SetBufferedRegion(outputImage->GetRequestedRegion());
-  outputImage->Allocate();
+#ifndef SNAP_USE_GPU
+  pac->RegisterInternalFilter(m_BlurFilter, 0.8);
+#else
+  pac->RegisterInternalFilter(m_GPUBlurFilter, 0.8);
+#endif
 
-  // Pipe in the input image
+    pac->RegisterInternalFilter(m_RemapFilter, 0.2);
+
+  // Configure the pipeline
   m_CastFilter->SetInput(inputImage);
 
-  // Set the variance
-  Vector3f variance(
-    m_EdgePreprocessingSettings.GetGaussianBlurScale() * 
-    m_EdgePreprocessingSettings.GetGaussianBlurScale());
-  m_GaussianFilter->SetVariance(variance.data_block());
+  // Configure the Gaussian
+#ifndef SNAP_USE_GPU
+  m_BlurFilter->SetUseImageSpacingOff();
+  m_BlurFilter->SetVariance(
+        settings->GetGaussianBlurScale() * settings->GetGaussianBlurScale());
+#else
+  m_GPUBlurFilter->SetUseImageSpacingOff();
+  m_GPUBlurFilter->SetVariance(
+        settings->GetGaussianBlurScale() * settings->GetGaussianBlurScale());
+#endif
 
   // Construct the functor
+  // TODO: fixme!
   FunctorType functor;
-  functor.SetParameters(0.0f,1.0f,
-                        m_EdgePreprocessingSettings.GetRemappingExponent(),
-                        m_EdgePreprocessingSettings.GetRemappingSteepness());
-
-  // Assign the functor to the filter
-  m_RemappingFilter->SetFunctor(functor);
+  functor.SetParameters(0.0, m_InputImageMaximumGradientMagnitude,
+                        settings->GetRemappingExponent(),
+                        settings->GetRemappingSteepness());
 
-  // Call the filter's GenerateData()
-  m_RemappingFilter->GraftOutput(outputImage);
-  m_RemappingFilter->Update();
-
-  // graft the mini-pipeline output back onto this filter's output.
-  // this is needed to get the appropriate regions passed back.
-  GraftOutput( m_RemappingFilter->GetOutput() );
+  // Configure the remapping filter
+  m_RemapFilter->SetFunctor(functor);
 
+  // Graft outputs and update the filter
+  m_RemapFilter->GraftOutput(outputImage);
+  m_RemapFilter->Update();
+  this->GraftOutput(m_RemapFilter->GetOutput());
 }
 
 template<typename TInputImage,typename TOutputImage>
@@ -132,15 +162,28 @@ EdgePreprocessingImageFilter<TInputImage,TOutputImage>
 template<typename TInputImage,typename TOutputImage>
 void 
 EdgePreprocessingImageFilter<TInputImage,TOutputImage>
-::SetEdgePreprocessingSettings(const EdgePreprocessingSettings &settings)
+::SetParameters(EdgePreprocessingSettings *settings)
+{
+  if(settings != GetParameters())
+    {
+    this->SetNthInput(1, settings);
+    }
+}
+
+template<typename TInputImage,typename TOutputImage>
+EdgePreprocessingSettings *
+EdgePreprocessingImageFilter<TInputImage,TOutputImage>
+::GetParameters()
 {
-  if(!(settings == m_EdgePreprocessingSettings))
+  if(this->GetNumberOfInputs() > 1)
     {
-    m_EdgePreprocessingSettings = settings;    
-    this->Modified();
+    return static_cast<EdgePreprocessingSettings *>(
+          this->GetInputs()[1].GetPointer());
     }
+  else return NULL;
 }
 
+
 template<typename TInputImage,typename TOutputImage>
 void 
 EdgePreprocessingImageFilter<TInputImage,TOutputImage>
@@ -156,5 +199,6 @@ EdgePreprocessingImageFilter<TInputImage,TOutputImage>
 
   // Use the largest possible region (hack)
   inputPtr->SetRequestedRegion(
-    inputPtr->GetLargestPossibleRegion());
+        inputPtr->GetLargestPossibleRegion());
 }
+
diff --git a/Logic/Preprocessing/EdgePreprocessingSettings.cxx b/Logic/Preprocessing/EdgePreprocessingSettings.cxx
index a264c82..85e824b 100644
--- a/Logic/Preprocessing/EdgePreprocessingSettings.cxx
+++ b/Logic/Preprocessing/EdgePreprocessingSettings.cxx
@@ -33,28 +33,50 @@
 
 =========================================================================*/
 #include "EdgePreprocessingSettings.h"
+#include "ScalarImageWrapper.h"
+#include "Registry.h"
 
 bool 
 EdgePreprocessingSettings
 ::operator == (const EdgePreprocessingSettings &other) const
 {
-  return memcmp(this,&other,sizeof(EdgePreprocessingSettings)) == 0;
+  return (m_GaussianBlurScale == other.m_GaussianBlurScale &&
+          m_RemappingSteepness == other.m_RemappingSteepness &&
+          m_RemappingExponent == other.m_RemappingExponent);
 }
 
 EdgePreprocessingSettings::
-EdgePreprocessingSettings()
+EdgePreprocessingSettings():
+        m_GaussianBlurScale(1.0f), 
+        m_RemappingSteepness(0.04f),  
+        m_RemappingExponent(3.0f) 
 {
-  SetGaussianBlurScale(1.0f);
-  SetRemappingSteepness(0.1f);
-  SetRemappingExponent(2.0f);
+  this->InitializeToDefaults();
 }
-EdgePreprocessingSettings::
-~EdgePreprocessingSettings() { /*Needs to be defined to avoid compiler warning about needing a virtual destructor*/};
 
+void
 EdgePreprocessingSettings
+::InitializeToDefaults()
+{
+  // These seem to be pretty reliable settings
+  SetGaussianBlurScale(1.0f);
+  SetRemappingSteepness(0.04f);
+  SetRemappingExponent(3.0f);
+}
+
+void
 EdgePreprocessingSettings
-::MakeDefaultSettings()
+::ReadFromRegistry(Registry &registry)
+{
+  m_GaussianBlurScale = registry["GaussianBlurScale"][m_GaussianBlurScale];
+  m_RemappingSteepness = registry["RemappingSteepness"][m_RemappingSteepness];
+  m_RemappingExponent = registry["RemappingExponent"][m_RemappingExponent];
+}
+
+void EdgePreprocessingSettings
+::WriteToRegistry(Registry &registry)
 {
-  EdgePreprocessingSettings settings;
-  return settings;
+  registry["GaussianBlurScale"] << m_GaussianBlurScale;
+  registry["RemappingSteepness"] << m_RemappingSteepness;
+  registry["RemappingExponent"] << m_RemappingExponent;
 }
diff --git a/Logic/Preprocessing/EdgePreprocessingSettings.h b/Logic/Preprocessing/EdgePreprocessingSettings.h
index 40b302a..1fd3250 100644
--- a/Logic/Preprocessing/EdgePreprocessingSettings.h
+++ b/Logic/Preprocessing/EdgePreprocessingSettings.h
@@ -36,25 +36,29 @@
 #define __EdgePreprocessingSettings_h_
 
 #include "SNAPCommon.h"
+#include "itkDataObject.h"
+#include "itkObjectFactory.h"
 
-// Forward references
-class GreyImageWrapper;
+class Registry;
 
 /**
  * This class encapsulates the thresholding settings used by the program.
  * for In/Out snake initialization
  */
-class EdgePreprocessingSettings
+class EdgePreprocessingSettings : public itk::DataObject
 {
 public:
-  irisGetMacro(GaussianBlurScale,float);
-  irisSetMacro(GaussianBlurScale,float);
 
-  irisGetMacro(RemappingSteepness,float);
-  irisSetMacro(RemappingSteepness,float);
+  irisITKObjectMacro(EdgePreprocessingSettings, itk::DataObject)
 
-  irisGetMacro(RemappingExponent,float);
-  irisSetMacro(RemappingExponent,float);
+  itkGetConstMacro(GaussianBlurScale,float)
+  itkSetMacro(GaussianBlurScale,float)
+
+  itkGetConstMacro(RemappingSteepness,float)
+  itkSetMacro(RemappingSteepness,float)
+
+  itkGetConstMacro(RemappingExponent,float)
+  itkSetMacro(RemappingExponent,float)
   
   /** Compare two sets of settings */
   bool operator == (const EdgePreprocessingSettings &other) const;
@@ -62,12 +66,21 @@ public:
   /**
    * Create a default instance of the settings based on an image wrapper
    */
-  static EdgePreprocessingSettings MakeDefaultSettings();
+  void InitializeToDefaults();
+
+  /**
+    Read the settings from a registry, given the current grey image. This will
+    check if the settings are valid and abort if they are not
+    */
+  void ReadFromRegistry(Registry &reg);
+
+  /** Write the settings to a registry */
+  void WriteToRegistry(Registry &registry);
+
+protected:
 
-  // Constructor
   EdgePreprocessingSettings();
-  // Destructor
-  virtual ~EdgePreprocessingSettings();
+  virtual ~EdgePreprocessingSettings() {}
 
 private:
   float m_GaussianBlurScale;
diff --git a/Logic/Preprocessing/GMM/EMGaussianMixtures.cxx b/Logic/Preprocessing/GMM/EMGaussianMixtures.cxx
new file mode 100644
index 0000000..de58613
--- /dev/null
+++ b/Logic/Preprocessing/GMM/EMGaussianMixtures.cxx
@@ -0,0 +1,471 @@
+#include "EMGaussianMixtures.h"
+#include <iostream>
+#include <ctime>
+
+EMGaussianMixtures::EMGaussianMixtures(double **x, int dataSize, int dataDim, int numOfClass)
+  :m_x(x), m_numOfData(dataSize), m_dimOfGaussian(dataDim), m_numOfGaussian(numOfClass), m_setPriorFlag(0), m_numOfIteration(0), m_fail(0)
+{
+  m_latent = new double*[dataSize];
+  m_probs = new double[dataSize*numOfClass];
+  for (int i = 0; i < dataSize; i++)
+    {
+    m_latent[i] = &m_probs[i*numOfClass];
+    }
+  m_log_pdf = new double*[dataSize];
+  m_probs2 = new double[dataSize*numOfClass];
+  for (int i = 0; i < dataSize; i++)
+    {
+    m_log_pdf[i] = &m_probs2[i*numOfClass];
+    }
+  m_tmp1 = new double[numOfClass];
+  m_tmp2 = new double[dataDim];
+  m_tmp3 = new double[dataDim*dataDim];
+  m_sum = new double[numOfClass];
+  m_weight = new double[numOfClass];
+
+  m_gmm = GaussianMixtureModel::New();
+  m_gmm->Initialize(dataDim, numOfClass);
+
+  m_maxIteration = 30;
+  m_precision = 1.0e-7;
+  m_logLikelihood = std::numeric_limits<double>::infinity();
+}
+
+EMGaussianMixtures::~EMGaussianMixtures()
+{
+  delete m_probs;
+  delete m_probs2;
+  delete m_latent;
+  delete m_log_pdf;
+  delete m_tmp1;
+  delete m_tmp2;
+  delete m_tmp3;
+  delete m_sum;
+  delete m_weight;
+}
+
+void EMGaussianMixtures::Reset(void)
+{
+  m_numOfIteration = 0;
+  m_fail = 0;
+  m_logLikelihood = std::numeric_limits<double>::infinity();
+  for (int i = 0; i < m_numOfData*m_numOfGaussian; i++)
+    {
+    m_probs[i] = 0;
+    m_probs2[i] = 0;
+    }
+}
+
+void EMGaussianMixtures::SetMaxIteration(int maxIteration)
+{
+  m_maxIteration = maxIteration;
+}
+
+void EMGaussianMixtures::SetPrecision(double precision)
+{
+  m_precision = precision;
+}
+
+void EMGaussianMixtures::SetParameters(int index, const VectorType &mean, const MatrixType &covariance, double weight)
+{
+  m_gmm->SetGaussian(index, mean, covariance);
+  m_gmm->SetWeight(index, weight);
+}
+
+void EMGaussianMixtures::SetGaussianMixtureModel(GaussianMixtureModel *gmm)
+{
+  for (int i = 0; i < m_numOfGaussian; i++)
+    {
+    m_gmm->SetGaussian(i, gmm->GetMean(i), gmm->GetCovariance(i));
+    m_gmm->SetWeight(i, gmm->GetWeight(i));
+    if(gmm->IsForeground(i))
+      m_gmm->SetForeground(i);
+    else
+      m_gmm->SetBackground(i);
+    }
+}
+
+void EMGaussianMixtures::SetPrior(double **prior)
+{
+  m_prior = prior;
+  m_setPriorFlag = 1;
+}
+
+void EMGaussianMixtures::RemovePrior(void)
+{
+  m_prior = 0;
+  m_setPriorFlag = 0;
+}
+
+int EMGaussianMixtures::GetMaxIteration(void)
+{
+  return m_maxIteration;
+}
+
+double ** EMGaussianMixtures::Update(void)
+{
+  double currentLogLikelihood = 0;
+  m_numOfIteration = 0;
+  m_fail = 0;
+  while ((fabs(m_logLikelihood - currentLogLikelihood) > m_precision) && (m_numOfIteration < m_maxIteration))
+    {
+    if (m_logLikelihood < currentLogLikelihood)
+      {
+      m_fail = 1;
+      std::cout << "!!!!!! Log Likelihood increase, EM fails" << std::endl;
+      std::cout << "old=" <<m_logLikelihood << std::endl << "new=" << currentLogLikelihood << std::endl;
+      // break;
+      }
+    ++m_numOfIteration;
+    m_logLikelihood = currentLogLikelihood;
+    EvaluatePDF();
+    currentLogLikelihood = EvaluateLogLikelihood();
+    UpdateLatent();
+    UpdateMean();
+    UpdateCovariance();
+    if (m_setPriorFlag == 0)
+      {
+      UpdateWeight();
+      }
+
+    std::cout << std::endl <<"=====================" << std::endl;
+    std::cout << "After " << m_numOfIteration << " Iteration:" << std::endl;
+    std::cout << "log likelihood:" << std::endl << m_logLikelihood << std::endl;
+    PrintParameters();
+    //getchar();
+    }
+  return m_latent;
+}
+
+double ** EMGaussianMixtures::UpdateOnce(void)
+{
+  long start = 0;
+  long end = 0;
+  start = clock();
+  EvaluatePDF();
+  end = clock();
+  std::cout << "evaluate pdf spending " << (end-start)/1000 << std::endl;
+  start = clock();
+  double currentLogLikelihood = EvaluateLogLikelihood();
+  end = clock();
+  std::cout << "evaluate likelihood spending " << (end-start)/1000 << std::endl;
+  if (m_logLikelihood < currentLogLikelihood)
+    {
+    m_fail = 1;
+    std::cout << "!!!!!! Log Likelihood increase, EM fails" << std::endl;
+    std::cout << "old=" <<m_logLikelihood << std::endl << "new=" << currentLogLikelihood << std::endl;
+    }
+  if (fabs(m_logLikelihood - currentLogLikelihood) <= m_precision)
+    {
+    std::cout << "Log Likelihood converged" << std::endl;
+    }
+  if (m_numOfIteration >= m_maxIteration)
+    {
+    std::cout << "Reach the maximum iteration number" << std::endl;
+    }
+  ++m_numOfIteration;
+  m_logLikelihood = currentLogLikelihood;
+  
+  start = clock();
+  UpdateLatent();
+  end = clock();
+  std::cout << "latent spending " << (end-start)/1000 << std::endl;
+  start = clock();
+  UpdateMean();
+  end = clock();
+  std::cout << "mean spending " << (end-start)/1000 << std::endl;
+  start = clock();
+  UpdateCovariance();
+  end = clock();
+  std::cout << "covariance spending " << (end-start)/1000 << std::endl;
+  if (m_setPriorFlag == 0)
+    {
+    start = clock();
+    UpdateWeight();
+    end = clock();
+    std::cout << "weight spending " << (end-start)/1000 << std::endl;
+    }
+
+  std::cout << std::endl <<"=====================" << std::endl;
+  std::cout << "After " << m_numOfIteration << " Iteration:" << std::endl;
+  std::cout << "log likelihood:" << std::endl << m_logLikelihood << std::endl;
+  PrintParameters();
+  //getchar();
+  return m_latent;
+}
+
+void EMGaussianMixtures::EvaluatePDF(void)
+{
+  for (int i = 0; i < m_numOfData; i++)
+    {
+    for (int j = 0; j < m_numOfGaussian; j++)
+      {
+      m_log_pdf[i][j] = m_gmm->EvaluateLogPDF(j, m_x[i]);
+      }
+    }
+  if (m_setPriorFlag == 0)
+    {
+    for (int j = 0; j < m_numOfGaussian; j++)
+      {
+      m_weight[j] = m_gmm->GetWeight(j);
+      }
+    }
+}
+
+#include <vnl/vnl_math.h>
+
+double EMGaussianMixtures::ComputePosterior(int nGauss, double *log_pdf, double *w, double *log_w, int j)
+{
+  // Instead of directly computing the expression
+  //   latent[i][j] = w[j] * N(x_i; m_j, Sigma_j) / Sum_k[w[k] * N(x_i; m_k, Sigma_k)]
+  // which is equivalently
+  //   latent[i][j] = exp(a_j) / Sum_k[ exp(a_k) ]
+  // where
+  //   a_j = log( w[j] * N(x_i; m_j, Sigma_j) )
+  // we compute
+  //   latent[i][j] = 1 / (1 + Sum_(k!=j)[ exp(a_k - a_j) ])
+  // which is numerically stable
+
+  // If the weight of the class is zero, the posterior is automatically zero
+  if(w[j] == 0)
+    return 0;
+
+  // We are computing m_latent[i][j]
+  double denom = 1.0;
+
+  // The log of w[j] * pdf[j];
+  double exp_j = (log_w[j] + log_pdf[j]);
+  for (int k = 0; k < nGauss; k++)
+    {
+    if(j != k && w[k] > 0)
+      {
+      // The log of (w[k] * pdf[k]) / (w[j] * pdf[j])
+      double exponent = (log_w[k] + log_pdf[k]) - exp_j;
+      if(exponent < -20)
+        {
+        // (w[k] * pdf[k]) / (w[j] * pdf[j]) is effectively zero
+        continue;
+        }
+      else if(exponent > 20)
+        {
+        // latent[i][j] is effectively zero
+        denom = vnl_huge_val(1.0);
+        break;
+        }
+      else
+        {
+        denom += exp(exponent);
+        }
+      }
+    }
+
+  // Now compute 1/denom
+  double post = 1.0 / denom;
+  return post;
+}
+
+void EMGaussianMixtures::UpdateLatent(void)
+{
+  double sum = 0;
+  for (int i = 0; i < m_numOfGaussian; i++)
+    {
+    m_sum[i] = 0;
+    }
+
+  // Compute log of the weights and store in logw
+  vnl_vector<double> logw(m_numOfGaussian);
+  for(int i = 0; i < m_numOfGaussian; i++)
+    logw(i) = log(m_weight[i]);
+  
+  if (m_setPriorFlag == 0)
+    {
+    for (int i = 0; i < m_numOfData; i++)
+      {
+      for (int j = 0; j < m_numOfGaussian; j++)
+        {
+        m_latent[i][j] = ComputePosterior(m_numOfGaussian, m_log_pdf[i], m_weight, logw.data_block(), j);
+        m_sum[j] += m_latent[i][j];
+        }
+
+
+      /*
+      sum = 0;
+      for (int j = 0; j < m_numOfGaussian; j++)
+        {
+        m_tmp1[j] = m_weight[j] * m_pdf[i][j];
+        sum += m_tmp1[j];
+        }
+      if(sum == 0)
+        {
+        for (int j = 0; j < m_numOfGaussian; j++)
+          {
+          m_latent[i][j] = 1.0 / m_numOfGaussian;
+          m_sum[j] += m_latent[i][j];
+          }
+        }
+      else
+        {
+        for (int j = 0; j < m_numOfGaussian; j++)
+          {
+          m_latent[i][j] = m_tmp1[j] / sum;
+          m_sum[j] += m_latent[i][j];
+          }
+        }
+        */
+      }
+    }
+  else
+    {
+    /**= THIS IS NOT USED
+    for (int i = 0; i < m_numOfData; i++)
+      {
+      sum = 0;
+      for (int j = 0; j < m_numOfGaussian; j++)
+        {
+        m_tmp1[j] = m_prior[i][j] * m_pdf[i][j];
+        sum += m_tmp1[j];
+        }
+      for (int j = 0; j < m_numOfGaussian; j++)
+        {
+        m_latent[i][j] = m_tmp1[j] / sum;
+        m_sum[j] += m_latent[i][j];
+        }
+      }
+      */
+    }
+}
+
+void EMGaussianMixtures::UpdateMean(void)
+{
+  for (int i = 0; i < m_numOfGaussian; i++)
+    {
+    for (int j = 0; j < m_dimOfGaussian; j++)
+      {
+      m_tmp2[j] = 0;
+      }
+    
+    for (int j = 0; j < m_numOfData; j++)
+      {
+      for (int k = 0; k < m_dimOfGaussian; k++)
+        {
+        m_tmp2[k] += m_latent[j][i] * m_x[j][k];
+        }
+      }
+
+    // This can lead to a possible divide by zero situation. In case the sum
+    // of latent variables for class i is zero, we set the mean of that class
+    // to infinity
+    if(m_sum[i] > 0)
+      {
+      for (int j = 0; j < m_dimOfGaussian; j++)
+        {
+        m_tmp2[j] = m_tmp2[j] / m_sum[i];
+        }
+      }
+    else
+      {
+      for (int j = 0; j < m_dimOfGaussian; j++)
+        {
+        m_tmp2[j] = - std::numeric_limits<double>::infinity();
+        }
+      }
+
+
+    m_gmm->SetMean(i, VectorType(m_tmp2, m_dimOfGaussian));
+    }
+}
+
+void EMGaussianMixtures::UpdateCovariance(void)
+{
+  for (int i = 0; i < m_numOfGaussian; i++)
+    {
+    const VectorType &current_mean = m_gmm->GetMean(i);
+    
+    for (int j = 0; j < m_dimOfGaussian; j++)
+      {
+      for (int k = 0; k < m_dimOfGaussian; k++)
+        {
+        m_tmp3[j*m_dimOfGaussian+k] = 0;
+        }
+      }
+    
+    for (int j = 0; j < m_numOfData; j++)
+      {
+      for (int k = 0; k < m_dimOfGaussian; k++)
+        {
+        m_tmp2[k] = m_x[j][k] - current_mean[k];
+        }
+      for (int k = 0; k < m_dimOfGaussian; k++)
+        {
+        for (int l = 0; l < m_dimOfGaussian; l++)
+          {
+          m_tmp3[k*m_dimOfGaussian+l] += m_tmp2[k] * m_tmp2[l] * m_latent[j][i];
+          }
+        }
+      }
+
+    if(m_sum[i] > 0)
+      {
+      for (int j = 0; j < m_dimOfGaussian*m_dimOfGaussian; j++)
+        {
+        m_tmp3[j] = m_tmp3[j] / m_sum[i];
+        }
+      }
+    else
+      {
+      for (int j = 0; j < m_dimOfGaussian*m_dimOfGaussian; j++)
+        {
+        m_tmp3[j] = 0.0;
+        }
+      }
+
+
+    m_gmm->SetCovariance(i, MatrixType(m_tmp3, m_dimOfGaussian, m_dimOfGaussian));
+    }
+}
+
+void EMGaussianMixtures::UpdateWeight(void)
+{
+  for (int i = 0; i < m_numOfGaussian; i++)
+    {
+    m_gmm->SetWeight(i, m_sum[i]/m_numOfData);
+    }
+}
+
+double EMGaussianMixtures::EvaluateLogLikelihood(void)
+{
+  double tmp1 = 0;
+  double tmp2 = 0;
+  if (m_setPriorFlag == 0)
+    {
+    for (int i = 0; i < m_numOfData; i++)
+      {
+      tmp1 = 0;
+      for (int j = 0; j < m_numOfGaussian; j++)
+        {
+        if(!m_gmm->GetGaussian(j)->isDeltaFunction())
+          tmp1 += m_weight[j] * exp(m_log_pdf[i][j]);
+        }
+      tmp2 += log(tmp1);
+      }
+    }
+  else
+    {
+    for (int i = 0; i < m_numOfData; i++)
+      {
+      tmp1 = 0;
+      for (int j = 0; j < m_numOfGaussian; j++)
+        {
+        if(!m_gmm->GetGaussian(j)->isDeltaFunction())
+          tmp1 += m_prior[i][j] * exp(m_log_pdf[i][j]);
+        }
+      tmp2 += log(tmp1);
+      }
+    }
+  return tmp1;
+}
+
+void EMGaussianMixtures::PrintParameters(void)
+{
+  m_gmm->PrintParameters();
+}
diff --git a/Logic/Preprocessing/GMM/EMGaussianMixtures.h b/Logic/Preprocessing/GMM/EMGaussianMixtures.h
new file mode 100644
index 0000000..d70d256
--- /dev/null
+++ b/Logic/Preprocessing/GMM/EMGaussianMixtures.h
@@ -0,0 +1,70 @@
+#ifndef EM_GAUSSIAN_MIXTURES_H
+#define EM_GAUSSIAN_MIXTURES_H
+
+#include "GaussianMixtureModel.h"
+#include "SNAPCommon.h"
+
+class EMGaussianMixtures
+{
+public:
+  EMGaussianMixtures(double **x, int dataSize, int dataDim, int numOfClass);
+  ~EMGaussianMixtures();
+
+  typedef Gaussian::MatrixType MatrixType;
+  typedef Gaussian::VectorType VectorType;
+
+  void Reset(void);
+  void SetMaxIteration(int maxIteration);
+  void SetPrecision(double precision);
+  void SetParameters(int index,
+                     const VectorType &mean,
+                     const MatrixType &covariance,
+                     double weight);
+  void SetGaussianMixtureModel(GaussianMixtureModel *gmm);
+  void SetPrior(double **prior);
+  void RemovePrior(void);
+
+  GaussianMixtureModel *GetGaussianMixtureModel() const { return m_gmm; }
+
+  
+  int GetMaxIteration(void);
+
+  double ** Update(void);
+  double ** UpdateOnce(void);
+  double EvaluateLogLikelihood(void);
+  void PrintParameters(void);
+
+  static double ComputePosterior(int nGauss, double *log_pdf, double *w, double *log_w, int j);
+
+private:
+  void EvaluatePDF(void);
+  void UpdateLatent(void);
+  void UpdateMean(void);
+  void UpdateCovariance(void);
+  void UpdateWeight(void);
+  
+  double **m_latent;
+  double **m_log_pdf;
+  double **m_prior;
+  double **m_x;
+  double *m_probs;
+  double *m_probs2;
+  double *m_tmp1;
+  double *m_tmp2;
+  double *m_tmp3;
+  double *m_sum;
+  double *m_weight;
+  double m_logLikelihood;
+  int m_numOfGaussian;
+  int m_dimOfGaussian;
+  int m_maxIteration;
+  int m_numOfIteration;
+  int m_numOfData;
+  int m_setPriorFlag;
+  int m_fail;
+  double m_precision;
+
+  SmartPtr<GaussianMixtureModel> m_gmm;
+};
+
+#endif
diff --git a/Logic/Preprocessing/GMM/Gaussian.cxx b/Logic/Preprocessing/GMM/Gaussian.cxx
new file mode 100644
index 0000000..ee3f1ff
--- /dev/null
+++ b/Logic/Preprocessing/GMM/Gaussian.cxx
@@ -0,0 +1,132 @@
+#include "Gaussian.h"
+#include <iostream>
+#include <vnl/vnl_math.h>
+#include <vnl/vnl_trace.h>
+#include <vnl/algo/vnl_symmetric_eigensystem.h>
+#include <limits>
+
+Gaussian::Gaussian(int dimension)
+  :m_dimension(dimension)
+{
+  // Initialize the scratch buffers
+  m_x_vector = VectorType(dimension);
+}
+
+const Gaussian::VectorType &Gaussian::GetMean() const
+{
+  assert(m_mean_vector.size());
+  return m_mean_vector;
+}
+
+const Gaussian::MatrixType &Gaussian::GetCovariance() const
+{
+  assert(m_covariance_matrix.size());
+  return m_covariance_matrix;
+}
+
+double Gaussian::GetTotalVariance()
+{
+  return vnl_trace(m_covariance_matrix);
+}
+
+void Gaussian::SetMean(const VectorType &mean)
+{
+  assert(mean.size() == m_dimension);
+  m_mean_vector = mean;
+}
+
+void Gaussian::SetCovariance(const MatrixType &cov)
+{
+  // Validate and assign covariance matrix
+  assert(cov.rows() == m_dimension && cov.cols() == m_dimension);
+  m_covariance_matrix = cov;
+
+  // Perform SVD on the covariance matrix
+  vnl_symmetric_eigensystem<double> eig(m_covariance_matrix);
+  m_V = eig.V;
+  m_Vt = eig.V.transpose();
+  m_Lambda = eig.D;
+
+  // Compute the normalization factors for each 1D Gaussian component
+  m_DiagNormFac = VectorType(m_dimension);
+  for(int i = 0; i < m_dimension; i++)
+    m_DiagNormFac[i] = log(2 * vnl_math::pi * m_Lambda[i]);
+}
+
+double Gaussian::EvaluateLogPDF(VectorType &x, VectorType &xscratch)
+{
+  // Subtract the mean from x
+  for(int i = 0; i < m_dimension; i++)
+    xscratch[i] = x[i] - m_mean_vector[i];
+
+  // Compute 2*log(p(z))
+  double logz = 0;
+  for (int i = 0; i < m_dimension; i++)
+    {
+    // Compute z[i], the projection of x on the i-th eigenvector of the covariance
+    // matrix. Then z[i] is a 1D normally distributed variable with variance m_Lambda[i]
+    double zi = 0;
+    for(int j = 0; j < m_dimension; j++)
+      zi += m_Vt(i,j) * xscratch[j];
+
+    // Should there be a tolerance for this conditional and the next?
+    if(m_Lambda[i] == 0)
+      {
+      if(zi != 0)
+        {
+        // Zero variance and z[i] != 0, which means p(x) = 0, log(p(x)) = -inf
+        logz = -std::numeric_limits<double>::infinity();
+        break;
+        }
+      else
+        {
+        // Zero variance and z[i] == 0, which means p(z[i]) = 1, log(p(z[i])) = 0;
+        continue;
+        }
+      }
+    else
+      {
+      // Compute the 1D Gaussian log-probability
+      logz -= m_DiagNormFac[i] + (zi * zi / m_Lambda[i]);
+      }
+    }
+
+  // Final value needs to be divided by two
+  return 0.5 * logz;
+}
+
+double Gaussian::EvaluatePDF(double *x)
+{
+  // We got to exponentiate somewhere, so might as well do it here
+  double logp = this->EvaluateLogPDF(x);
+
+  // According to POSIX definition, exp(-inf) = +0 so this is safe
+  return exp(logp);
+}
+
+// TODO: better to pass in VectorType here
+double Gaussian::EvaluateLogPDF(double *x)
+{
+  VectorType xvec(x, m_dimension);
+  return this->EvaluateLogPDF(xvec, m_x_vector);
+}
+
+void Gaussian::PrintParameters()
+{
+  std::cout << "mean:" << std::endl;
+  if (m_mean_vector.size())
+    std::cout << m_mean_vector << std::endl;
+  else
+    std::cout << "NA" << std::endl;;
+  
+  std::cout << "covariance:" << std::endl;
+  if (m_covariance_matrix.size())
+    std::cout << m_covariance_matrix << std::endl;
+  else
+    std::cout << "NA" << std::endl;;
+}
+
+bool Gaussian::isDeltaFunction()
+{
+  return GetTotalVariance() == 0.0;
+}
diff --git a/Logic/Preprocessing/GMM/Gaussian.h b/Logic/Preprocessing/GMM/Gaussian.h
new file mode 100644
index 0000000..88ec598
--- /dev/null
+++ b/Logic/Preprocessing/GMM/Gaussian.h
@@ -0,0 +1,51 @@
+#ifndef GAUSSIAN_H
+#define GAUSSIAN_H
+
+#include <vnl/vnl_matrix.h>
+#include <vnl/algo/vnl_matrix_inverse.h>
+#include <vnl/algo/vnl_determinant.h>
+
+class Gaussian
+{
+public:
+  typedef vnl_matrix<double> MatrixType;
+  typedef vnl_vector<double> VectorType;
+  
+  Gaussian(int dimension);
+
+  const VectorType &GetMean() const;
+  const MatrixType &GetCovariance() const;
+  double GetTotalVariance();
+
+  void SetMean(const VectorType &mean);
+  void SetCovariance(const MatrixType &cov);
+
+  double EvaluatePDF(double *x);
+  double EvaluateLogPDF(double *x);
+
+  // Evaluate log PDF with user-provided scratch buffer
+  double EvaluateLogPDF(VectorType &x, VectorType &xscratch);
+
+  void PrintParameters();
+
+  // Tests whether the Gaussian is a delta function (i.e., has zero total variance)
+  bool isDeltaFunction();
+
+
+private:
+  int m_dimension;
+
+  MatrixType m_covariance_matrix;
+  VectorType m_mean_vector;
+
+  // SVD of the covariance matrix
+  MatrixType m_V, m_Vt;
+  vnl_diag_matrix<double> m_Lambda;
+  VectorType m_DiagNormFac;
+
+  // Mean-subtracted and rotated x vector; PCA-normalized z-vector
+  // these vectors are used to avoid memory allocation
+  VectorType m_x_vector;
+};
+
+#endif
diff --git a/Logic/Preprocessing/GMM/GaussianMixtureModel.cxx b/Logic/Preprocessing/GMM/GaussianMixtureModel.cxx
new file mode 100644
index 0000000..6ffa5ef
--- /dev/null
+++ b/Logic/Preprocessing/GMM/GaussianMixtureModel.cxx
@@ -0,0 +1,182 @@
+#include "GaussianMixtureModel.h"
+#include <iostream>
+#include <algorithm>
+
+GaussianMixtureModel::GaussianMixtureModel()
+  :m_dimOfGaussian(0), m_numOfGaussian(0)
+{
+}
+
+GaussianMixtureModel::~GaussianMixtureModel()
+{
+  // Delete all of the existing Gaussians
+  for(GaussianVectorIterator iter = m_gaussian.begin(); iter != m_gaussian.end(); ++iter)
+    delete *iter;
+}
+
+void GaussianMixtureModel::Initialize(int dimOfGaussian, int numOfGaussian)
+{
+  m_dimOfGaussian = dimOfGaussian;
+  m_numOfGaussian = numOfGaussian;
+
+  // Delete all of the existing Gaussians
+  for(GaussianVectorIterator iter = m_gaussian.begin(); iter != m_gaussian.end(); ++iter)
+    delete *iter;
+
+  // Allocate the new clusters
+  m_gaussian.resize(numOfGaussian, NULL);
+  m_weight.resize(numOfGaussian, 0);
+  m_foreground_state.resize(numOfGaussian, 0);
+
+  for (int i = 0; i < numOfGaussian; i++)
+    m_gaussian[i] = new Gaussian(dimOfGaussian);
+
+  // Mark the first cluster as foreground
+  if(numOfGaussian > 0)
+    m_foreground_state[0] = 1;
+}
+
+Gaussian * GaussianMixtureModel::GetGaussian(int index)
+{
+  assert(index < m_numOfGaussian);
+  return m_gaussian[index];
+}
+
+const GaussianMixtureModel::VectorType &
+GaussianMixtureModel::GetMean(int index)
+{
+  assert(index < m_numOfGaussian);
+  return m_gaussian[index]->GetMean();
+}
+
+const GaussianMixtureModel::MatrixType &
+GaussianMixtureModel::GetCovariance(int index)
+{
+  assert(index < m_numOfGaussian);
+  return m_gaussian[index]->GetCovariance();
+}
+
+double GaussianMixtureModel::GetWeight(int index)
+{
+  assert(index < m_numOfGaussian);
+  return m_weight[index];
+}
+
+void GaussianMixtureModel::SetGaussian(int index, const VectorType &mean, const MatrixType &cov)
+{
+  assert(index < m_numOfGaussian);
+  m_gaussian[index]->SetMean(mean);
+  m_gaussian[index]->SetCovariance(cov);
+}
+
+void GaussianMixtureModel::SetMean(int index, const VectorType &mean)
+{
+  assert(index < m_numOfGaussian);
+  m_gaussian[index]->SetMean(mean);
+}
+
+void GaussianMixtureModel::SetCovariance(int index, const MatrixType &cov)
+{
+  assert(index < m_numOfGaussian);
+  m_gaussian[index]->SetCovariance(cov);
+}
+
+void GaussianMixtureModel::SetWeight(int index, double weight)
+{
+  assert(index < m_numOfGaussian);
+  m_weight[index] = weight;
+}
+
+void GaussianMixtureModel::SetWeightAndRenormalize(int index, double weight)
+{
+  // Check the range
+  if (index >= m_numOfGaussian)
+    {
+    std::cout << "index out of boundary at " << __FILE__ << " : " << __LINE__  <<std::endl;
+    exit(0);
+    }
+
+  // The weight should be clamped to the range [0 1]
+  double w_curr = m_weight[index];
+  double w_clamp = std::max(std::min(weight, 1.0), 0.0);
+  double w_scale = w_curr == 1.0 ? 0.0 : (1.0 - w_clamp) / (1.0 - w_curr);
+  double w_sum = 0.0;
+
+  // Update all the weights so the sum is still one
+  for(int i = 0; i < m_numOfGaussian; i++)
+    {
+    if(i == index)
+      {
+      m_weight[i] = w_clamp;
+      }
+    else
+      {
+      m_weight[i] *= w_scale;
+      }
+
+    // Keet track of the sum of weights
+    w_sum += m_weight[i];
+    }
+
+  // There is still a possibility that the sum of weights is not 1. In that
+  // case assign the difference to the next cluster
+  if(w_sum < 1.0)
+    m_weight[(index % m_numOfGaussian)] += 1.0 - w_sum;
+}
+
+double GaussianMixtureModel::EvaluatePDF(int index, double *x)
+{
+  if (index < m_numOfGaussian)
+  {
+    return m_gaussian[index]->EvaluatePDF(x);
+  }
+  else
+  {
+    std::cout << "index out of boundary at " << __FILE__ << " : " << __LINE__  <<std::endl;
+    exit(0);
+  }
+}
+
+double GaussianMixtureModel::EvaluateLogPDF(int index, double *x)
+{
+  assert(index < m_numOfGaussian);
+  return m_gaussian[index]->EvaluateLogPDF(x);
+}
+
+
+double GaussianMixtureModel::EvaluateLogPDF(
+    int index, vnl_vector<double> &x, VectorType &xscratch)
+{
+  assert(index < m_numOfGaussian);
+  return m_gaussian[index]->EvaluateLogPDF(x, xscratch);
+}
+
+
+void GaussianMixtureModel::PrintParameters()
+{
+  int i = 0;
+  GaussianVectorIterator gaussianIter;
+  WeightVectorIterator weightIter;
+  for(gaussianIter = m_gaussian.begin(), weightIter = m_weight.begin();
+      gaussianIter != m_gaussian.end(); ++gaussianIter, ++weightIter)
+  {
+    std::cout << std::endl << "Gaussian Component " << ++i << ":" << std::endl;
+    std::cout << "weight:" << std::endl << *weightIter << std::endl;
+    (*gaussianIter)->PrintParameters();
+    }
+}
+
+bool GaussianMixtureModel::IsForeground(int index)
+{
+  return m_foreground_state[index];
+}
+
+void GaussianMixtureModel::SetForeground(int index)
+{
+  m_foreground_state[index] = true;
+}
+
+void GaussianMixtureModel::SetBackground(int index)
+{
+  m_foreground_state[index] = false;
+}
diff --git a/Logic/Preprocessing/GMM/GaussianMixtureModel.h b/Logic/Preprocessing/GMM/GaussianMixtureModel.h
new file mode 100644
index 0000000..88506a3
--- /dev/null
+++ b/Logic/Preprocessing/GMM/GaussianMixtureModel.h
@@ -0,0 +1,67 @@
+#ifndef GAUSSIAN_MIXTURE_MODEL_H
+#define GAUSSIAN_MIXTURE_MODEL_H
+
+#include "SNAPCommon.h"
+#include "itkDataObject.h"
+#include "itkObjectFactory.h"
+#include "Gaussian.h"
+#include <vector>
+
+class GaussianMixtureModel : public itk::DataObject
+{
+public:
+  irisITKObjectMacro(GaussianMixtureModel, itk::DataObject)
+
+  typedef std::vector<Gaussian *> GaussianVector;
+  typedef std::vector<double> WeightVector;
+  typedef std::vector<bool> BoolVector;
+  typedef GaussianVector::iterator GaussianVectorIterator;
+  typedef WeightVector::iterator WeightVectorIterator;
+
+  typedef Gaussian::VectorType VectorType;
+  typedef Gaussian::MatrixType MatrixType;
+
+  void Initialize(int dimOfGaussian, int numOfGaussian);
+  
+  Gaussian * GetGaussian(int index);
+  const VectorType &GetMean(int index);
+  const MatrixType &GetCovariance(int index);
+  double GetWeight(int index);
+
+  void SetGaussian(int index, const VectorType &mean, const MatrixType &cov);
+  void SetMean(int index, const VectorType &mean);
+  void SetCovariance(int index, const MatrixType &cov);
+  void SetWeight(int index, double weight);
+  void SetWeightAndRenormalize(int index, double weight);
+
+  double EvaluateLogPDF(int index, double *x);
+  double EvaluateLogPDF(int index, vnl_vector<double> &x, VectorType &xscratch);
+  double EvaluatePDF(int index, double *x);
+
+
+  void PrintParameters();
+
+  int GetNumberOfGaussians() { return m_numOfGaussian; }
+  int GetNumberOfComponents() { return m_dimOfGaussian; }
+
+  /**
+   * Is the cluster an object or background?
+   */
+  bool IsForeground(int index);
+
+  void SetForeground(int index);
+  void SetBackground(int index);
+  
+protected:
+
+  GaussianMixtureModel();
+  ~GaussianMixtureModel();
+
+  int m_numOfGaussian;
+  int m_dimOfGaussian;
+  GaussianVector m_gaussian;
+  WeightVector m_weight;
+  BoolVector m_foreground_state;
+};
+
+#endif
diff --git a/Logic/Preprocessing/GMM/KMeansPlusPlus.cxx b/Logic/Preprocessing/GMM/KMeansPlusPlus.cxx
new file mode 100644
index 0000000..c597d38
--- /dev/null
+++ b/Logic/Preprocessing/GMM/KMeansPlusPlus.cxx
@@ -0,0 +1,180 @@
+#include "KMeansPlusPlus.h"
+#include "math.h"
+#include "time.h"
+#include "stdlib.h"
+
+KMeansPlusPlus::KMeansPlusPlus(double **x, int dataSize, int dataDim, int numOfClusters)
+  :m_dataSize(dataSize), m_dataDim(dataDim), m_numOfClusters(numOfClusters)
+{
+  m_x = x;
+  m_xCenter = new int[dataSize];
+  m_centers = new int[numOfClusters];
+  m_xCounter = new int[numOfClusters];
+  m_distance = new double[dataSize];
+
+  m_gmm = GaussianMixtureModel::New();
+  m_gmm->Initialize(dataDim, numOfClusters);
+}
+
+KMeansPlusPlus::~KMeansPlusPlus()
+{
+  delete m_centers;
+  delete m_xCenter;
+  delete m_xCounter;
+  delete m_distance;
+}
+
+double KMeansPlusPlus::Distance(const double *x, const double *y)
+{
+  double tmp = 0;
+  for (int i = 0; i < m_dataDim; i++)
+  {
+    tmp += (x[i] - y[i]) * (x[i] - y[i]);
+  }
+  return sqrt(tmp);
+}
+
+void KMeansPlusPlus::Initialize(void)
+{
+  // for (int i = 0; i < numOfClusters; i++)
+  // {
+  //   m_xCounter[i] = 0;
+  // }
+
+  srand(time(0));
+
+  m_centers[0] = (int)(((double) rand() / (double) RAND_MAX) * m_dataSize);
+  double distSum = 0;
+  for (int i = 0; i < m_dataSize; i++)
+    {
+    m_xCenter[i] = m_centers[0];
+    m_distance[i] = Distance(m_x[i], m_x[m_centers[0]]);
+    distSum += m_distance[i];
+    }
+  m_xCounter[0] = m_dataSize;
+
+  double probDist = 0;
+  double currentSum = 0;
+  int idx = 0;
+  for (int i = 1; i < m_numOfClusters; i++)
+    {
+    m_xCounter[i] = 0;
+    probDist = ((double) rand() / (double) RAND_MAX) * distSum;
+    currentSum = 0;
+    for (idx = 0; idx < m_dataSize; idx++)
+      {
+      currentSum += m_distance[idx];
+      if (currentSum >= probDist)
+        {
+        break;
+        }
+      }
+
+    m_centers[i] = idx;
+
+    distSum = 0;
+    for (int j = 0; j < m_dataSize; j++)
+      {
+      if (m_distance[j] > Distance(m_x[j], m_x[m_centers[i]]))
+        {
+        ++m_xCounter[i];
+        for (int k = 0; k < i; k++)
+          {
+          if (m_centers[k] == m_xCenter[j])
+            {
+            --m_xCounter[k];
+            break;
+            }
+          }
+        m_distance[j] = Distance(m_x[j], m_x[m_centers[i]]);
+        m_xCenter[j] = m_centers[i];
+        }
+      distSum += m_distance[j];
+      }
+    }
+
+  Gaussian::VectorType tmpMean(m_dataDim, 0.0);
+  for (int i = 0; i < m_numOfClusters; i++)
+    {
+    m_gmm->SetMean(i, tmpMean);
+    }
+
+  for (int i = 0; i < m_dataSize; i++)
+    {
+    for (int j = 0; j < m_numOfClusters; j++)
+      {
+      if (m_xCenter[i] == m_centers[j])
+        {
+        tmpMean = m_gmm->GetMean(j);
+        for (int k = 0; k < m_dataDim; k++)
+          {
+          tmpMean[k] = tmpMean[k] + m_x[i][k];
+          }
+        m_gmm->SetMean(j, tmpMean);
+        break;
+        }
+      }
+    }
+  // m_gmm->PrintParameters();
+  // getchar();
+  for (int i = 0; i < m_numOfClusters; i++)
+    {
+    tmpMean = m_gmm->GetMean(i);
+
+    if(m_xCounter[i] > 0)
+      {
+      // If this class is not empty, we set its mean
+      tmpMean /= m_xCounter[i];
+      }
+    else
+      {
+      // If it is empty, we set the mean to -infinity (rather than nan)
+      tmpMean.fill(-std::numeric_limits<double>::infinity());
+      }
+
+    m_gmm->SetMean(i, tmpMean);
+    }
+
+  double *radius = new double[m_numOfClusters];
+  for (int i = 0; i < m_numOfClusters; i++)
+    {
+    radius[i] = 0;
+    }
+  for (int i = 0; i < m_dataSize; i++)
+    {
+    for (int j = 0; j < m_numOfClusters; j++)
+      {
+      if (m_xCenter[i] == m_centers[j])
+        {
+        double dist = Distance(m_x[i], m_gmm->GetMean(j).data_block());
+        if (radius[j] < dist)
+          {
+          radius[j] = dist;
+          }
+        break;
+        }
+      }
+    }
+
+  Gaussian::MatrixType tmpcovar(m_dataDim, m_dataDim, 0);
+  for (int i = 0; i < m_numOfClusters; i++)
+    {
+    for (int j = 0; j < m_dataDim; j++)
+      {
+      tmpcovar(j,j) = radius[i];
+      }
+    m_gmm->SetCovariance(i, tmpcovar);
+    }
+
+  delete radius;
+
+  for (int i = 0; i < m_numOfClusters; i++)
+    {
+    m_gmm->SetWeight(i, 1.0/(double) m_numOfClusters);
+    }
+}
+
+GaussianMixtureModel * KMeansPlusPlus::GetGaussianMixtureModel(void)
+{
+  return m_gmm;
+}
diff --git a/Logic/Preprocessing/GMM/KMeansPlusPlus.h b/Logic/Preprocessing/GMM/KMeansPlusPlus.h
new file mode 100644
index 0000000..37fbe10
--- /dev/null
+++ b/Logic/Preprocessing/GMM/KMeansPlusPlus.h
@@ -0,0 +1,28 @@
+#ifndef KMEANS_PLUS_PLUS_H
+#define KMEANS_PLUS_PLUS_H
+
+#include "GaussianMixtureModel.h"
+#include "SNAPCommon.h"
+
+class KMeansPlusPlus
+{
+public:
+  KMeansPlusPlus(double **x, int dataSize, int dataDim, int numOfClusters);
+  ~KMeansPlusPlus();
+
+  double Distance(const double *x, const double *y);
+  void Initialize(void);
+  GaussianMixtureModel * GetGaussianMixtureModel(void);
+private:
+  double **m_x;
+  int *m_xCenter;
+  int *m_centers;
+  int *m_xCounter;
+  double *m_distance;
+  int m_dataSize;
+  int m_dataDim;
+  int m_numOfClusters;
+  SmartPtr<GaussianMixtureModel> m_gmm;
+};
+
+#endif
diff --git a/Logic/Preprocessing/GMM/UnsupervisedClustering.cxx b/Logic/Preprocessing/GMM/UnsupervisedClustering.cxx
new file mode 100644
index 0000000..7752859
--- /dev/null
+++ b/Logic/Preprocessing/GMM/UnsupervisedClustering.cxx
@@ -0,0 +1,263 @@
+#include "UnsupervisedClustering.h"
+#include "KMeansPlusPlus.h"
+#include "EMGaussianMixtures.h"
+#include "GaussianMixtureModel.h"
+#include "SNAPImageData.h"
+#include "ImageWrapper.h"
+#include "ImageWrapperTraits.h"
+
+#include <algorithm>
+
+UnsupervisedClustering::UnsupervisedClustering()
+{
+  m_ClusteringEM = NULL;
+  m_NumberOfClusters = 3;
+  m_DataArray = NULL;
+  m_NumberOfSamples = 0;
+}
+
+UnsupervisedClustering::~UnsupervisedClustering()
+{
+  if(m_ClusteringEM)
+    {
+    delete m_ClusteringEM;
+    delete m_ClusteringInitializer;
+    }
+
+  if(m_DataArray)
+    {
+    // Delete the main data buffer
+    delete m_DataArray[0];
+
+    // Delete the pointers into the buffer
+    delete m_DataArray;
+    }
+
+
+}
+
+
+void UnsupervisedClustering::SetDataSource(SNAPImageData *imageData)
+{
+  if(m_DataSource != imageData)
+    {
+    m_DataSource = imageData;
+    m_SamplesDirty = true;
+
+    int nvox = m_DataSource->GetMain()->GetNumberOfVoxels();
+    m_NumberOfSamples = (nvox > 10000) ? 10000 : nvox;
+    }
+}
+
+void UnsupervisedClustering::SetMixtureModel(GaussianMixtureModel *model)
+{
+  m_ClusteringEM->SetGaussianMixtureModel(model);
+  m_MixtureModel = m_ClusteringEM->GetGaussianMixtureModel();
+}
+
+#include "itkImageRandomConstIteratorWithIndex.hxx"
+
+void UnsupervisedClustering::SampleDataSource()
+{
+  if(m_DataArray)
+    {
+    // Delete the main data buffer
+    delete m_DataArray[0];
+
+    // Delete the pointers into the buffer
+    delete m_DataArray;
+    }
+
+  // Figure out the number of data components
+  unsigned int nComp = 0;
+  for(LayerIterator lit = m_DataSource->GetLayers(
+        MAIN_ROLE | OVERLAY_ROLE);
+      !lit.IsAtEnd(); ++lit)
+    {
+    nComp += lit.GetLayer()->GetNumberOfComponents();
+    }
+
+  // Size the data array
+  int nvox = m_DataSource->GetMain()->GetNumberOfVoxels();
+  int nsam = (m_NumberOfSamples == 0) ? nvox : m_NumberOfSamples;
+
+  // Create data structure for the EM code
+  m_DataArray = new double *[nsam];
+  double *buffer = new double[nsam * nComp];
+  for(int i = 0; i < nsam; i++, buffer+=nComp)
+    m_DataArray[i] = buffer;
+
+  // Create a random walk through the speed image, which should be initialized
+  // at this point. We iterate over the speed image because we can easily access
+  // its internal image (it's always a scalar image)
+  assert(m_DataSource->IsSpeedLoaded());
+  typedef SpeedImageWrapper::ImageType SpeedImage;
+
+  SpeedImage *speed = m_DataSource->GetSpeed()->GetImage();
+  typedef itk::ImageRandomConstIteratorWithIndex<SpeedImage> RandomIter;
+  RandomIter itRand(speed, speed->GetBufferedRegion());
+  itRand.SetNumberOfSamples(nsam);
+
+  // Initialize the 'central' samples list
+  m_CenterSamples.clear();
+  m_CenterSamples.reserve(400);
+
+  // Define the center region
+  itk::ImageRegion<3> rcenter = speed->GetBufferedRegion();
+  rcenter.ShrinkByRadius(to_itkSize(Vector3d(rcenter.GetSize()) * 0.2));
+
+  // Do the random walk
+  int pVoxel = 0;
+  for(; !itRand.IsAtEnd(); ++itRand)
+    {
+    // Go to the next sample location
+    itk::Index<3> idx = itRand.GetIndex();
+
+    // TODO: this is a really slow way to collect samples!
+    int iOffset = 0;
+    for(LayerIterator lit = m_DataSource->GetLayers(MAIN_ROLE | OVERLAY_ROLE);
+        !lit.IsAtEnd(); ++lit)
+      {
+      ImageWrapperBase *iw = lit.GetLayer();
+      iw->GetVoxelAsDouble(idx, m_DataArray[pVoxel] + iOffset);
+      iOffset += iw->GetNumberOfComponents();
+      }
+
+    // Store as a 'central' sample if in the central 60% of the image
+    if(m_CenterSamples.size() < 400 && rcenter.IsInside(idx))
+      {
+      m_CenterSamples.push_back(pVoxel);
+      }
+
+    pVoxel++;
+    }
+
+  m_NumberOfVoxels = nsam;
+
+  m_NumberOfComponents = nComp;
+  m_SamplesDirty = false;
+}
+
+void UnsupervisedClustering::SetNumberOfClusters(int nClusters)
+{
+  if(m_NumberOfClusters != nClusters)
+    {
+    m_NumberOfClusters = nClusters;
+    }
+}
+
+void UnsupervisedClustering::SetNumberOfSamples(int nSamples)
+{
+  if(m_NumberOfSamples != nSamples)
+    {
+    m_NumberOfSamples = nSamples;
+    m_SamplesDirty = true;
+    }
+}
+
+void UnsupervisedClustering::InitializeClusters()
+{
+  this->InitializeEM();
+}
+
+void UnsupervisedClustering::InitializeEM()
+{
+  // Make sure the data source is specified
+  assert(m_DataSource);
+
+  // Make sure samples exist
+  if(m_SamplesDirty || m_DataArray == NULL)
+    this->SampleDataSource();
+
+  if(m_ClusteringEM)
+    {
+    delete m_ClusteringEM;
+    delete m_ClusteringInitializer;
+    }
+
+  // Allocate the EM algorithm
+  m_ClusteringEM = new EMGaussianMixtures(
+        m_DataArray, m_NumberOfVoxels,
+        m_NumberOfComponents, m_NumberOfClusters);
+
+  // Allocate the K means ++
+  m_ClusteringInitializer = new KMeansPlusPlus(
+        m_DataArray, m_NumberOfVoxels,
+        m_NumberOfComponents, m_NumberOfClusters);
+
+  m_ClusteringInitializer->Initialize();
+
+  m_ClusteringEM->SetGaussianMixtureModel(
+        m_ClusteringInitializer->GetGaussianMixtureModel());
+
+  m_ClusteringEM->SetMaxIteration(10);
+
+  // Get the GMM
+  m_MixtureModel = m_ClusteringEM->GetGaussianMixtureModel();
+
+  // Sort the clusters based on center samples
+  SortClustersByRelevance();
+}
+
+void UnsupervisedClustering::SortClustersByRelevance()
+{
+  int ng = m_MixtureModel->GetNumberOfGaussians();
+  vnl_vector<double> log_pdf(ng), log_w(ng), w(ng);
+
+  // the array to sort
+  typedef std::pair<double, int> RelevancePair;
+  std::vector<RelevancePair> rel(ng);
+
+  for(int k = 0; k < ng; k++)
+    {
+    log_w[k] = log(m_MixtureModel->GetWeight(k));
+    w[k] = m_MixtureModel->GetWeight(k);
+    rel[k].first = 0.0;
+    rel[k].second = k;
+    }
+
+  for(int i = 0; i < m_CenterSamples.size(); i++)
+    {
+    int s = m_CenterSamples[i];
+    for(int k = 0; k < ng; k++)
+      {
+      log_pdf[k] = m_MixtureModel->EvaluateLogPDF(k, m_DataArray[s]);
+      }
+
+    for(int k = 0; k < ng; k++)
+      {
+      // Accumulate the posterior
+      rel[k].first -= EMGaussianMixtures::ComputePosterior(
+            ng, log_pdf.data_block(), w.data_block(), log_w.data_block(), k);
+      }
+    }
+
+  // Sort the relevance array
+  std::sort(rel.begin(), rel.end());
+
+  // Create a new mixture model
+  SmartPtr<GaussianMixtureModel> gmmtemp = GaussianMixtureModel::New();
+  gmmtemp->Initialize(m_MixtureModel->GetNumberOfComponents(), ng);
+  for(int k = 0; k < ng; k++)
+    {
+    int j = rel[k].second;
+    gmmtemp->SetWeight(k, m_MixtureModel->GetWeight(j));
+    gmmtemp->SetGaussian(k, m_MixtureModel->GetMean(j), m_MixtureModel->GetCovariance(j));
+    }
+
+  // Assign it to the EM
+  m_ClusteringEM->SetGaussianMixtureModel(gmmtemp);
+  m_MixtureModel = m_ClusteringEM->GetGaussianMixtureModel();
+}
+
+
+void UnsupervisedClustering::Iterate()
+{
+  long start = clock();
+  double **post = m_ClusteringEM->UpdateOnce();
+  m_MixtureModel->PrintParameters();
+  long end = clock();
+  std::cout << "spending " << (end-start)/1000 << std::endl;
+}
+
+
diff --git a/Logic/Preprocessing/GMM/UnsupervisedClustering.h b/Logic/Preprocessing/GMM/UnsupervisedClustering.h
new file mode 100644
index 0000000..df1514c
--- /dev/null
+++ b/Logic/Preprocessing/GMM/UnsupervisedClustering.h
@@ -0,0 +1,65 @@
+#ifndef UNSUPERVISEDCLUSTERING_H
+#define UNSUPERVISEDCLUSTERING_H
+
+#include <itkObject.h>
+#include <itkObjectFactory.h>
+#include <SNAPCommon.h>
+
+class KMeansPlusPlus;
+class EMGaussianMixtures;
+class GaussianMixtureModel;
+class SNAPImageData;
+
+class UnsupervisedClustering : public itk::Object
+{
+public:
+
+  irisITKObjectMacro(UnsupervisedClustering, itk::Object)
+
+  void SetDataSource(SNAPImageData *imageData);
+
+  irisGetMacro(NumberOfClusters, int)
+
+  irisGetMacro(NumberOfSamples, int)
+
+  irisGetMacro(MixtureModel, GaussianMixtureModel *)
+
+  void SetMixtureModel(GaussianMixtureModel *model);
+
+  void SetNumberOfClusters(int nClusters);
+
+  void SetNumberOfSamples(int nSamples);
+
+  void InitializeClusters();
+
+  void Iterate();
+
+
+protected:
+
+  UnsupervisedClustering();
+  virtual ~UnsupervisedClustering();
+
+
+  void InitializeEM();
+  void SampleDataSource();
+  void SortClustersByRelevance();
+
+  EMGaussianMixtures *m_ClusteringEM;
+  KMeansPlusPlus *m_ClusteringInitializer;
+  GaussianMixtureModel *m_MixtureModel;
+  SNAPImageData *m_DataSource;
+
+  int m_NumberOfClusters, m_NumberOfComponents, m_NumberOfVoxels, m_NumberOfSamples;
+
+  bool m_SamplesDirty;
+
+  // TODO: probably double is larger than we need
+  double **m_DataArray;
+
+  // A set of samples located near the center of the image, used to sort
+  // initial clusters in terms of relevance to the user
+  std::vector<int> m_CenterSamples;
+};
+
+#endif // UNSUPERVISEDCLUSTERING_H
diff --git a/Logic/Preprocessing/GMMClassifyImageFilter.h b/Logic/Preprocessing/GMMClassifyImageFilter.h
new file mode 100644
index 0000000..b8439ac
--- /dev/null
+++ b/Logic/Preprocessing/GMMClassifyImageFilter.h
@@ -0,0 +1,75 @@
+#ifndef GMMCLASSIFYIMAGEFILTER_H
+#define GMMCLASSIFYIMAGEFILTER_H
+
+#include "itkImageToImageFilter.h"
+#include "GaussianMixtureModel.h"
+
+/**
+ * @brief A class that takes multiple multi-component images and uses a
+ * Gaussian mixture model to combine them into a single probability map.
+ */
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+class GMMClassifyImageFilter :
+    public itk::ImageToImageFilter<TInputImage, TOutputImage>
+{
+public:
+
+  /** Pixel Type of the input image */
+  typedef TInputImage                                    InputImageType;
+  typedef typename InputImageType::PixelType             InputPixelType;
+  typedef typename InputImageType::InternalPixelType InputComponentType;
+  typedef typename InputImageType::RegionType      InputImageRegionType;
+
+  /** Define the corresponding vector image */
+  typedef TInputVectorImage                        InputVectorImageType;
+
+  /** Pixel Type of the output image */
+  typedef TOutputImage                                  OutputImageType;
+  typedef typename OutputImageType::PixelType           OutputPixelType;
+  typedef typename OutputImageType::RegionType    OutputImageRegionType;
+  typedef typename OutputImageType::Pointer          OutputImagePointer;
+
+  /** Standard class typedefs. */
+  typedef GMMClassifyImageFilter                                   Self;
+  typedef itk::ImageSource<OutputImageType>                  Superclass;
+  typedef itk::SmartPointer<Self>                               Pointer;
+  typedef itk::SmartPointer<const Self>                    ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self)
+
+  /** Image dimension. */
+  itkStaticConstMacro(ImageDimension, unsigned int,
+                      TInputImage::ImageDimension);
+
+  /** Add a scalar input image */
+  void AddScalarImage(InputImageType *image);
+
+  /** Add a vector (multi-component) input image */
+  void AddVectorImage(InputVectorImageType *image);
+
+  /** Set the mixture model */
+  void SetMixtureModel(GaussianMixtureModel *model);
+
+  /** We need to override this method because of multiple input types */
+  void GenerateInputRequestedRegion();
+
+protected:
+
+  GMMClassifyImageFilter();
+  virtual ~GMMClassifyImageFilter();
+
+  void PrintSelf(std::ostream& os, itk::Indent indent) const;
+
+  void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread,
+                            itk::ThreadIdType threadId);
+
+  GaussianMixtureModel *m_MixtureModel;
+};
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "GMMClassifyImageFilter.txx"
+#endif
+
+
+#endif // GMMCLASSIFYIMAGEFILTER_H
diff --git a/Logic/Preprocessing/GMMClassifyImageFilter.txx b/Logic/Preprocessing/GMMClassifyImageFilter.txx
new file mode 100644
index 0000000..0261963
--- /dev/null
+++ b/Logic/Preprocessing/GMMClassifyImageFilter.txx
@@ -0,0 +1,161 @@
+#ifndef GMMCLASSIFYIMAGEFILTER_TXX
+#define GMMCLASSIFYIMAGEFILTER_TXX
+
+#include "GMMClassifyImageFilter.h"
+#include "itkImageRegionConstIterator.h"
+#include "EMGaussianMixtures.h"
+#include "ImageCollectionToImageFilter.h"
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+GMMClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::GMMClassifyImageFilter()
+{
+  m_MixtureModel = NULL;
+}
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+GMMClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::~GMMClassifyImageFilter()
+{
+}
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+GMMClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::SetMixtureModel(GaussianMixtureModel *model)
+{
+  m_MixtureModel = model;
+  this->Modified();
+}
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+GMMClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::AddScalarImage(InputImageType *image)
+{
+  this->AddInput(image);
+}
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+GMMClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::AddVectorImage(InputVectorImageType *image)
+{
+  this->AddInput(image);
+}
+
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+GMMClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::GenerateInputRequestedRegion()
+{
+  itk::ImageSource<TOutputImage>::GenerateInputRequestedRegion();
+
+  for( itk::InputDataObjectIterator it( this ); !it.IsAtEnd(); it++ )
+    {
+    // Check whether the input is an image of the appropriate dimension
+    InputImageType *input = dynamic_cast< InputImageType * >( it.GetInput() );
+    InputVectorImageType *vecInput = dynamic_cast< InputVectorImageType * >( it.GetInput() );
+    if (input)
+      {
+      InputImageRegionType inputRegion;
+      this->CallCopyOutputRegionToInputRegion( inputRegion, this->GetOutput()->GetRequestedRegion() );
+      input->SetRequestedRegion(inputRegion);
+      }
+    else if(vecInput)
+      {
+      InputImageRegionType inputRegion;
+      this->CallCopyOutputRegionToInputRegion( inputRegion, this->GetOutput()->GetRequestedRegion() );
+      vecInput->SetRequestedRegion(inputRegion);
+      }
+    }
+}
+
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+GMMClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::PrintSelf(std::ostream &os, itk::Indent indent) const
+{
+  os << indent << "GMMClassifyImageFilter" << std::endl;
+}
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+GMMClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread,
+                       itk::ThreadIdType threadId)
+{
+  // Get the number of inputs
+  assert(m_MixtureModel);
+  int n_input = this->GetNumberOfIndexedInputs();
+  OutputImagePointer outputPtr = this->GetOutput(0);
+
+  // Create a collection iterator
+  typedef ImageCollectionConstRegionIteratorWithIndex<
+      TInputImage, TInputVectorImage> CollectionIter;
+
+  typedef itk::ImageRegionIterator<TOutputImage> OutputIter;
+  OutputIter it_out(outputPtr, outputRegionForThread);
+
+  vnl_vector<double> x(m_MixtureModel->GetNumberOfComponents());
+  vnl_vector<double> x_scratch(m_MixtureModel->GetNumberOfComponents());
+  vnl_vector<double> z_scratch(m_MixtureModel->GetNumberOfComponents());
+  vnl_vector<double> log_pdf(m_MixtureModel->GetNumberOfGaussians());
+  vnl_vector<double> log_w(m_MixtureModel->GetNumberOfGaussians());
+  vnl_vector<double> w(m_MixtureModel->GetNumberOfGaussians());
+  vnl_vector<double> p(m_MixtureModel->GetNumberOfGaussians());
+
+  // Create a multiplier vector (1 for foreground, -1 for background)
+  vnl_vector<double> pfactor(m_MixtureModel->GetNumberOfGaussians());
+  for(int i = 0; i < m_MixtureModel->GetNumberOfGaussians(); i++)
+    {
+    pfactor[i] = m_MixtureModel->IsForeground(i) ? 1.0 : -1.0;
+    log_w[i] = log(m_MixtureModel->GetWeight(i));
+    w[i] = m_MixtureModel->GetWeight(i);
+    }
+
+  // Configure the input collection iterator
+  CollectionIter cit(outputRegionForThread);
+  for( itk::InputDataObjectIterator it( this ); !it.IsAtEnd(); it++ )
+    cit.AddImage(it.GetInput());
+
+  // Get the number of components
+  int nComp = cit.GetTotalComponents();
+
+  // Iterate through all the voxels
+  while ( !it_out.IsAtEnd() )
+    {
+    for(int i = 0; i < nComp; i++)
+      {
+      x[i] = cit.Value(i);
+      }
+
+    // Evaluate the posterior probability robustly
+    for(int k = 0; k < m_MixtureModel->GetNumberOfGaussians(); k++)
+      {
+      log_pdf[k] = m_MixtureModel->EvaluateLogPDF(k, x, x_scratch);
+      }
+
+    // Evaluate the GMM for each of the clusters
+    double pdiff = 0;
+    for(int k = 0; k < m_MixtureModel->GetNumberOfGaussians(); k++)
+      {
+      p[k] = EMGaussianMixtures::ComputePosterior(
+            m_MixtureModel->GetNumberOfGaussians(),
+            log_pdf.data_block(), w.data_block(), log_w.data_block(), k);
+
+      pdiff += p[k] * pfactor[k];
+      }
+
+    // Store the value
+    it_out.Set((OutputPixelType)(pdiff * 0x7fff));
+
+    ++it_out;
+    ++cit;
+    }
+}
+
+
+#endif
diff --git a/Logic/Preprocessing/ImageCollectionToImageFilter.h b/Logic/Preprocessing/ImageCollectionToImageFilter.h
new file mode 100644
index 0000000..8c1dcfe
--- /dev/null
+++ b/Logic/Preprocessing/ImageCollectionToImageFilter.h
@@ -0,0 +1,301 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: ImageCollectionToImageFilter.h,v $
+  Language:  C++
+  Date:      $Date: 2009/01/24 01:50:21 $
+  Version:   $Revision: 1.4 $
+  Copyright (c) 2007 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __ImageCollectionToImageFilter_h_
+#define __ImageCollectionToImageFilter_h_
+
+#include <itkImageSource.h>
+#include <itkImageToImageFilter.h>
+
+#include <itkImageRegionIteratorWithIndex.h>
+
+/**
+ * This class is derived from the itk::iterator hierarchy and used to gain
+ * access to the protected m_Offset property
+ */
+template <class TIterator>
+class IteratorOffsetAccessor : public TIterator
+{
+public:
+  typedef typename TIterator::ImageType ImageType;
+  typedef typename TIterator::RegionType RegionType;
+  typedef itk::OffsetValueType OffsetValueType;
+
+  IteratorOffsetAccessor() { }
+  IteratorOffsetAccessor(const IteratorOffsetAccessor<TIterator> &copy)
+    : TIterator(copy) {}
+  IteratorOffsetAccessor(ImageType *image, const RegionType &region)
+    : TIterator(image, region) {}
+
+  OffsetValueType GetOffset() const { return this->m_Offset; }
+};
+
+/**
+ * An iterator that can be used to iterate over a collection of scalar and
+ * vector images of the same type.
+ *
+ * Example usage:
+ *
+ * ImageCollectionConstRegionIteratorWithIndex it(out.GetBufferedRegion());
+ * it.AddImage(img1);
+ * it.AddImage(img2);
+ * it.AddImage(img3);
+ *
+ * int nComp = it.GetTotalComponents();
+ * for (; !it.IsAtEnd(); ++it)
+ * {
+ *   for(int j = 0; j < nComp; j++)
+ *   {
+ *     GreyType &val = it.Value(j);
+ *   }
+ * }
+ */
+template <class TImage, class TVectorImage>
+class ImageCollectionConstRegionIteratorWithIndex
+{
+public:
+  /** Standard class typedefs. */
+  typedef ImageCollectionConstRegionIteratorWithIndex Self;
+
+  /** Dimension of the image that the iterator walks.  This constant is needed so
+   * functions that are templated over image iterator type (as opposed to
+   * being templated over pixel type and dimension) can have compile time
+   * access to the dimension of the image that the iterator walks. */
+  itkStaticConstMacro(ImageDimension, unsigned int, TImage::ImageDimension);
+
+  /** Index typedef support. */
+  typedef typename TImage::IndexType         IndexType;
+  typedef typename IndexType::IndexValueType IndexValueType;
+
+  /** Size typedef support. */
+  typedef typename TImage::SizeType        SizeType;
+  typedef typename SizeType::SizeValueType SizeValueType;
+
+  /** Region typedef support. */
+  typedef typename TImage::RegionType RegionType;
+
+  /** Image typedef support. */
+  typedef TImage ImageType;
+
+  /** Image base type */
+  typedef itk::ImageBase<ImageDimension> ImageBaseType;
+
+  /** PixelContainer typedef support. Used to refer to the container for
+   * the pixel data. While this was already typdef'ed in the superclass,
+   * it needs to be redone here for this subclass to compile properly with gcc. */
+  typedef typename TImage::PixelContainer  PixelContainer;
+  typedef typename PixelContainer::Pointer PixelContainerPointer;
+
+  typedef typename TVectorImage::PixelContainer VectorPixelContainer;
+  typedef typename VectorPixelContainer::Pointer VectorPixelContainerPointer;
+
+  /** Internal Pixel Type */
+  typedef typename TImage::InternalPixelType InternalPixelType;
+  typedef typename TVectorImage::InternalPixelType VectorInternalPixelType;
+
+  /** Offsets */
+  typedef typename TImage::OffsetType OffsetType;
+  typedef typename TImage::OffsetValueType OffsetValueType;
+
+  /** Constructor is passed a region */
+  ImageCollectionConstRegionIteratorWithIndex(const RegionType &region);
+
+  /** Add a scalar image to the collection */
+  void AddScalarImage(TImage *image);
+
+  /** Add a vector image to the collection */
+  void AddVectorImage(TVectorImage *image);
+
+  /** Add an image that must be dynamically castable to either TImage or TVectorImage */
+  void AddImage(itk::DataObject *image);
+
+  /** Get the number of components across the collection */
+  itkGetMacro(TotalComponents, unsigned int)
+
+  /** Standard iterator operations */
+  bool IsAtEnd() const { return m_InternalIter.IsAtEnd(); }
+  bool IsAtBegin() const { return m_InternalIter.IsAtBegin(); }
+  Self & operator++() { ++m_InternalIter; return *this; }
+  Self & operator--() { --m_InternalIter; return *this; }
+  void GoToBegin() { m_InternalIter.GoToBegin(); }
+  void GoToEnd() { m_InternalIter.GoToEnd(); }
+
+  /** Get a pointer to a component */
+  InternalPixelType &Value(unsigned int comp)
+  {
+    OffsetValueType offset = m_InternalIter.GetOffset();
+    InternalPixelType *dataPtr = m_Start[comp] + offset * m_OffsetScaling[comp];
+    return *(dataPtr);
+  }
+
+protected:
+
+  // Collection of scalar images
+  std::vector<const TImage *> m_ScalarImages;
+
+  // Collection of vector images
+  std::vector<const TVectorImage *> m_VectorImages;
+
+  // An array of start pointers for each component
+  std::vector<InternalPixelType *> m_Start;
+
+  // The scaling of offsets for each component
+  std::vector<int> m_OffsetScaling;
+
+  // A dummy image used to create an internal iterator. Instead of replicating
+  // all of the iterator mechanics code in this class, we defer to the internal
+  // iterator for all of that.
+  typename ImageType::Pointer m_DummyImage;
+
+  // Internal iterator
+  typedef itk::ImageRegionIterator<ImageType> WrappedIteratorType;
+  typedef IteratorOffsetAccessor<WrappedIteratorType> InternalIteratorType;
+  InternalIteratorType m_InternalIter;
+
+  // Total number of components that have been added
+  unsigned int m_TotalComponents;
+
+  // The offset for current iteration
+  RegionType m_Region;
+
+  // This method initializes all the iteration mechanics
+  void ComputeMechanics(ImageBaseType *image);
+};
+
+
+template <class TImage, class TVectorImage>
+ImageCollectionConstRegionIteratorWithIndex<TImage, TVectorImage>
+::ImageCollectionConstRegionIteratorWithIndex(const RegionType &region)
+{
+  m_Region = region;
+  m_TotalComponents = 0;
+}
+
+template <class TImage, class TVectorImage>
+void
+ImageCollectionConstRegionIteratorWithIndex<TImage, TVectorImage>
+::AddScalarImage(TImage *image)
+{
+  // Initialize the iteration mechanics
+  if(m_TotalComponents == 0)
+    ComputeMechanics(image);
+  else
+    assert(m_DummyImage->GetBufferedRegion() == image->GetBufferedRegion());
+
+  // Add the image to the list
+  m_ScalarImages.push_back(image);
+  m_TotalComponents++;
+
+  m_Start.push_back(image->GetBufferPointer());
+  m_OffsetScaling.push_back(1);
+}
+
+template <class TImage, class TVectorImage>
+void
+ImageCollectionConstRegionIteratorWithIndex<TImage, TVectorImage>
+::AddVectorImage(TVectorImage *image)
+{
+  // Initialize the iteration mechanics
+  if(m_TotalComponents == 0)
+    ComputeMechanics(image);
+  else
+    assert(m_DummyImage->GetBufferedRegion() == image->GetBufferedRegion());
+
+  m_VectorImages.push_back(image);
+  m_TotalComponents += image->GetVectorLength();
+
+  for(int i = 0; i < image->GetVectorLength(); i++)
+    {
+    m_Start.push_back(image->GetBufferPointer() + i);
+    m_OffsetScaling.push_back(image->GetVectorLength());
+    }
+}
+
+template <class TImage, class TVectorImage>
+void
+ImageCollectionConstRegionIteratorWithIndex<TImage, TVectorImage>
+::AddImage(itk::DataObject *dobj)
+{
+  TImage *image = dynamic_cast<TImage *>(dobj);
+  if(image)
+    {
+    this->AddScalarImage(image);
+    }
+  else
+    {
+    TVectorImage *vecImage = dynamic_cast<TVectorImage *>(dobj);
+    if(vecImage)
+      {
+      this->AddVectorImage(vecImage);
+      }
+    else
+      {
+      itkAssertInDebugOrThrowInReleaseMacro(
+            "Wrong input type to ImageCollectionConstRegionIteratorWithIndex");
+      }
+    }
+}
+
+template <class TImage, class TVectorImage>
+void
+ImageCollectionConstRegionIteratorWithIndex<TImage, TVectorImage>
+::ComputeMechanics(ImageBaseType *image)
+{
+  m_DummyImage = ImageType::New();
+  m_DummyImage->SetRegions(image->GetBufferedRegion());
+
+  m_InternalIter = InternalIteratorType(m_DummyImage, m_Region);
+}
+
+
+
+/* example usage:
+
+
+
+  */
+
+/*
+template <class TScalarImage, class TVectorImage, class TOutputImage>
+class ImageCollectionToImageFilter
+: public itk::ImageSource<TOutputImage>
+{
+public:
+
+protected:
+};
+
+*/
+
+#endif
diff --git a/Logic/Preprocessing/PreprocessingFilterConfigTraits.cxx b/Logic/Preprocessing/PreprocessingFilterConfigTraits.cxx
new file mode 100644
index 0000000..a01239f
--- /dev/null
+++ b/Logic/Preprocessing/PreprocessingFilterConfigTraits.cxx
@@ -0,0 +1,252 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: SNAPImageData.cxx,v $
+  Language:  C++
+  Date:      $Date: 2011/04/18 17:35:30 $
+  Version:   $Revision: 1.11 $
+  Copyright (c) 2007 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+
+#include "PreprocessingFilterConfigTraits.h"
+#include "SlicePreviewFilterWrapper.h"
+#include "SlicePreviewFilterWrapper.txx"
+#include "GMMClassifyImageFilter.h"
+#include "GMMClassifyImageFilter.txx"
+#include "RandomForestClassifyImageFilter.h"
+#include "RandomForestClassifyImageFilter.txx"
+#include "IRISApplication.h"
+#include "UnsupervisedClustering.h"
+#include "RFClassificationEngine.h"
+#include "Rebroadcaster.h"
+
+void
+SmoothBinaryThresholdFilterConfigTraits
+::AttachInputs(SNAPImageData *sid, FilterType *filter, int channel)
+{
+  // The work of attaching inputs to the filter is done in SetActiveScalarLayer,
+  // so this method does nothing.
+}
+
+ScalarImageWrapperBase *
+SmoothBinaryThresholdFilterConfigTraits
+::GetDefaultScalarLayer(SNAPImageData *sid)
+{
+  return sid->GetMain()->GetDefaultScalarRepresentation();
+}
+
+void
+SmoothBinaryThresholdFilterConfigTraits
+::DetachInputs(FilterType *filter)
+{
+  filter->SetInput(NULL);
+  filter->SetInputImageMinimum(0);
+  filter->SetInputImageMaximum(0);
+}
+
+void
+SmoothBinaryThresholdFilterConfigTraits
+::SetParameters(ParameterType *p, FilterType *filter, int channel)
+{
+  // Parameters are associated with the layer, so there is nothing to do here
+}
+
+void SmoothBinaryThresholdFilterConfigTraits::SetActiveScalarLayer(
+    ScalarImageWrapperBase *layer, SmoothBinaryThresholdFilterConfigTraits::FilterType *filter, int channel)
+{
+  ScalarImageWrapperBase::CommonFormatImageType *image =
+      layer->GetCommonFormatImage(
+        static_cast<ScalarImageWrapperBase::ExportChannel>(channel));
+
+  filter->SetInput(image);
+  filter->SetInputImageMinimum(layer->GetImageMinAsDouble());
+  filter->SetInputImageMaximum(layer->GetImageMaxAsDouble());
+
+  // Check if we have threshold parameters already associated with this layer
+  SmartPtr<ThresholdSettings> ts =
+      dynamic_cast<ThresholdSettings *>(layer->GetUserData("ThresholdSettings"));
+
+  if(!ts->GetInitialized())
+    {
+    // Associate threshold settings with this layer
+    ts->InitializeToDefaultForImage(layer);
+    }
+
+  // Propagate modified events from the threshold settings object as events
+  // from ImageWrapper. These events are further broadcast by GenericImageData
+  // and IRISApplication, making it easy for GUI classes to respond to them
+  Rebroadcaster::Rebroadcast(ts, itk::ModifiedEvent(),
+                             layer, WrapperProcessingSettingsChangeEvent());
+
+  // Pass the parameters to the filter
+  filter->SetParameters(ts);
+}
+
+void
+EdgePreprocessingFilterConfigTraits
+::AttachInputs(SNAPImageData *sid, FilterType *filter, int channel)
+{
+  ScalarImageWrapperBase *scalar = sid->GetMain()->GetDefaultScalarRepresentation();
+  ScalarImageWrapperBase::CommonFormatImageType *image =
+      scalar->GetCommonFormatImage(
+        static_cast<ScalarImageWrapperBase::ExportChannel>(channel));
+
+  filter->SetInput(image);
+  filter->SetInputImageMaximumGradientMagnitude(
+        scalar->GetImageGradientMagnitudeUpperLimit());
+}
+
+void
+EdgePreprocessingFilterConfigTraits
+::DetachInputs(FilterType *filter)
+{
+  filter->SetInput(NULL);
+}
+
+void
+EdgePreprocessingFilterConfigTraits
+::SetParameters(ParameterType *p, FilterType *filter, int channel)
+{
+  filter->SetParameters(p);
+}
+
+
+
+void
+GMMPreprocessingFilterConfigTraits
+::AttachInputs(SNAPImageData *sid, FilterType *filter, int channel)
+{
+  // Iterate through all of the relevant layers
+  for(LayerIterator it = sid->GetLayers(MAIN_ROLE | OVERLAY_ROLE);
+      !it.IsAtEnd(); ++it)
+    {
+    if(it.GetLayerAsScalar())
+      {
+      AnatomicScalarImageWrapper *w = dynamic_cast<AnatomicScalarImageWrapper *>(it.GetLayer());
+      filter->AddScalarImage(w->GetImage());
+      }
+    else if (it.GetLayerAsVector())
+      {
+      AnatomicImageWrapper *w = dynamic_cast<AnatomicImageWrapper *>(it.GetLayer());
+      filter->AddVectorImage(w->GetImage());
+      }
+    }
+
+  // Set the GMM input
+  UnsupervisedClustering *uc = sid->GetParent()->GetClusteringEngine();
+  assert(uc);
+  filter->SetMixtureModel(uc->GetMixtureModel());
+}
+
+void
+GMMPreprocessingFilterConfigTraits
+::DetachInputs(FilterType *filter)
+{
+  while(filter->GetNumberOfValidRequiredInputs())
+    filter->PopBackInput();
+
+  filter->SetMixtureModel(NULL);
+}
+
+void
+GMMPreprocessingFilterConfigTraits
+::SetParameters(ParameterType *p, FilterType *filter, int channel)
+{
+  filter->SetMixtureModel(p);
+}
+
+
+
+
+
+
+
+
+void
+RFPreprocessingFilterConfigTraits
+::AttachInputs(SNAPImageData *sid, FilterType *filter, int channel)
+{
+  // Iterate through all of the relevant layers
+  for(LayerIterator it = sid->GetLayers(MAIN_ROLE | OVERLAY_ROLE);
+      !it.IsAtEnd(); ++it)
+    {
+    if(it.GetLayerAsScalar())
+      {
+      AnatomicScalarImageWrapper *w = dynamic_cast<AnatomicScalarImageWrapper *>(it.GetLayer());
+      filter->AddScalarImage(w->GetImage());
+      }
+    else if (it.GetLayerAsVector())
+      {
+      AnatomicImageWrapper *w = dynamic_cast<AnatomicImageWrapper *>(it.GetLayer());
+      filter->AddVectorImage(w->GetImage());
+      }
+    }
+
+  // Set the classifier input
+  RFClassificationEngine *rfe = sid->GetParent()->GetClassificationEngine();
+  assert(rfe);
+  filter->SetClassifier(rfe->GetClassifier());
+}
+
+void
+RFPreprocessingFilterConfigTraits
+::DetachInputs(FilterType *filter)
+{
+  while(filter->GetNumberOfValidRequiredInputs())
+    filter->PopBackInput();
+
+  filter->SetClassifier(NULL);
+}
+
+void
+RFPreprocessingFilterConfigTraits
+::SetParameters(ParameterType *p, FilterType *filter, int channel)
+{
+  filter->SetClassifier(p);
+}
+
+bool
+RFPreprocessingFilterConfigTraits
+::IsPreviewable(FilterType *filter[])
+{
+  return (filter[0]->GetClassifier() != NULL && filter[0]->GetClassifier()->IsValidClassifier());
+}
+
+
+
+
+
+
+
+
+// Instantiate preview wrappers
+template class SlicePreviewFilterWrapper<SmoothBinaryThresholdFilterConfigTraits>;
+template class SlicePreviewFilterWrapper<EdgePreprocessingFilterConfigTraits>;
+template class SlicePreviewFilterWrapper<GMMPreprocessingFilterConfigTraits>;
+template class SlicePreviewFilterWrapper<RFPreprocessingFilterConfigTraits>;
+
diff --git a/Logic/Preprocessing/PreprocessingFilterConfigTraits.h b/Logic/Preprocessing/PreprocessingFilterConfigTraits.h
new file mode 100644
index 0000000..ff7f2c7
--- /dev/null
+++ b/Logic/Preprocessing/PreprocessingFilterConfigTraits.h
@@ -0,0 +1,158 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: IRISApplication.cxx,v $
+  Language:  C++
+  Date:      $Date: 2011/04/18 17:35:30 $
+  Version:   $Revision: 1.37 $
+  Copyright (c) 2007 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+  -----
+
+  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+
+#ifndef PREPROCESSINGFILTERCONFIGTRAITS_H
+#define PREPROCESSINGFILTERCONFIGTRAITS_H
+
+#include <SNAPImageData.h>
+template <class TInput, class TOutput> class SmoothBinaryThresholdImageFilter;
+template <class TInput, class TOutput> class EdgePreprocessingImageFilter;
+template <class TInput, class TVectorInput, class TOutput> class GMMClassifyImageFilter;
+template <class TInput, class TVectorInput, class TOutput> class RandomForestClassifyImageFilter;
+
+class ThresholdSettings;
+class EdgePreprocessingSettings;
+class GaussianMixtureModel;
+class RandomForestClassifier;
+
+class SmoothBinaryThresholdFilterConfigTraits {
+public:
+
+  typedef ScalarImageWrapperBase::CommonFormatImageType               GreyType;
+  typedef SNAPImageData::SpeedImageType                              SpeedType;
+  typedef SpeedImageWrapper                                  OutputWrapperType;
+
+  typedef SmoothBinaryThresholdImageFilter<GreyType, SpeedType>     FilterType;
+
+  // The 'parameters' for this filter consist of just the scalar image layer to
+  // which the filter should be applied. The actual parameters (thresholds) are
+  // obtained from the selected layer's user data.
+  typedef ThresholdSettings                                      ParameterType;
+
+  static void AttachInputs(SNAPImageData *sid, FilterType *filter, int channel);
+  static void DetachInputs(FilterType *filter);
+  static void SetParameters(ParameterType *p, FilterType *filter, int channel);
+  static bool GetDefaultPreviewMode() { return true; }
+
+  // This filter always has preview ready
+  static bool IsPreviewable(FilterType *filter[]) { return true; }
+
+  static ScalarImageWrapperBase* GetDefaultScalarLayer(SNAPImageData *sid);
+  static void SetActiveScalarLayer(
+      ScalarImageWrapperBase *layer, FilterType *filter, int channel);
+};
+
+class EdgePreprocessingFilterConfigTraits {
+public:
+
+  typedef ScalarImageWrapperBase::CommonFormatImageType               GreyType;
+  typedef SNAPImageData::SpeedImageType                              SpeedType;
+  typedef SpeedImageWrapper                                  OutputWrapperType;
+
+  typedef EdgePreprocessingImageFilter<GreyType, SpeedType>         FilterType;
+  typedef EdgePreprocessingSettings                              ParameterType;
+
+  static void AttachInputs(SNAPImageData *sid, FilterType *filter, int channel);
+  static void DetachInputs(FilterType *filter);
+  static void SetParameters(ParameterType *p, FilterType *filter, int channel);
+  static bool GetDefaultPreviewMode() { return true; }
+
+  // This filter always has preview ready
+  static bool IsPreviewable(FilterType *filter[]) { return true; }
+
+  static ScalarImageWrapperBase* GetDefaultScalarLayer(SNAPImageData *sid) { return NULL; }
+  static void SetActiveScalarLayer(
+      ScalarImageWrapperBase *layer, FilterType *filter, int channel) {}
+};
+
+
+class GMMPreprocessingFilterConfigTraits {
+public:
+
+  typedef AnatomicScalarImageWrapper::ImageType                 GreyScalarType;
+  typedef AnatomicImageWrapper::ImageType                       GreyVectorType;
+  typedef SNAPImageData::SpeedImageType                              SpeedType;
+  typedef SpeedImageWrapper                                  OutputWrapperType;
+
+  typedef GMMClassifyImageFilter<
+    GreyScalarType, GreyVectorType, SpeedType>                      FilterType;
+
+  typedef GaussianMixtureModel                                   ParameterType;
+
+  static void AttachInputs(SNAPImageData *sid, FilterType *filter, int channel);
+  static void DetachInputs(FilterType *filter);
+  static void SetParameters(ParameterType *p, FilterType *filter, int channel);
+  static bool GetDefaultPreviewMode() { return true; }
+
+  // This filter always has preview ready
+  static bool IsPreviewable(FilterType *filter[]) { return true; }
+
+  static ScalarImageWrapperBase* GetDefaultScalarLayer(SNAPImageData *sid) { return NULL; }
+  static void SetActiveScalarLayer(
+      ScalarImageWrapperBase *layer, FilterType *filter, int channel) {}
+};
+
+
+/** Traits class for random forest based preprocessing */
+class RFPreprocessingFilterConfigTraits {
+public:
+
+  typedef AnatomicScalarImageWrapper::ImageType                 GreyScalarType;
+  typedef AnatomicImageWrapper::ImageType                       GreyVectorType;
+  typedef SNAPImageData::SpeedImageType                              SpeedType;
+  typedef SpeedImageWrapper                                  OutputWrapperType;
+
+  typedef RandomForestClassifyImageFilter<
+    GreyScalarType, GreyVectorType, SpeedType>                      FilterType;
+
+  typedef RandomForestClassifier                                 ParameterType;
+
+  static void AttachInputs(SNAPImageData *sid, FilterType *filter, int channel);
+  static void DetachInputs(FilterType *filter);
+  static void SetParameters(ParameterType *p, FilterType *filter, int channel);
+  static bool GetDefaultPreviewMode() { return true; }
+
+  // This filter always has preview ready
+  static bool IsPreviewable(FilterType *filter[]);
+
+  static ScalarImageWrapperBase* GetDefaultScalarLayer(SNAPImageData *sid) { return NULL; }
+  static void SetActiveScalarLayer(
+      ScalarImageWrapperBase *layer, FilterType *filter, int channel) {}
+};
+
+
+
+
+#endif // PREPROCESSINGFILTERCONFIGTRAITS_H
diff --git a/Logic/Preprocessing/RandomForest/Library/classification.h b/Logic/Preprocessing/RandomForest/Library/classification.h
new file mode 100755
index 0000000..f5094e0
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/classification.h
@@ -0,0 +1,167 @@
+/**
+ * Solve classification problem by random forest.
+ */
+
+#ifndef CLASSIFICATION_H
+#define CLASSIFICATION_H
+
+#include <set>
+#include <map>
+#include "trainer.h"
+
+// Bug - Paul (changed labelT to be a parameter)
+template<class dataT, class labelT, class ClassifierT>
+class Classification
+{
+public:
+  // typedef int labelT;
+  typedef Histogram<dataT, labelT> HistStatisticsT;
+  typedef ClassificationContext<ClassifierT, dataT, labelT> ClassificationContextT;
+  typedef DecisionForest<HistStatisticsT, ClassifierT, dataT> DecisionForestT;
+  typedef Trainer<ClassifierT, HistStatisticsT, dataT, labelT> TrainerT;
+
+  // Bug - Paul (changed int to labelT)
+  typedef MLData<dataT, labelT> TrainingDataT;
+  typedef MLData<dataT, HistStatisticsT*> TestingDataT;
+  typedef Vector<Vector<HistStatisticsT*> > TestingResultT;
+  typedef Matrix<double> SoftPredictionT;
+  typedef Vector<int> HardPredictionT;
+
+  bool ValidData(TrainingDataT& trainingData,
+                 std::map<index_t, labelT>& mapping)
+  {
+    std::set<int> labelSet(trainingData.label.Begin(),
+                           trainingData.label.End());
+    std::set<int>::iterator setIter;
+    std::map<int, index_t> backMapping;
+    mapping.clear();
+    index_t i = 0;
+    bool valid = true;
+    for (setIter = labelSet.begin(); setIter != labelSet.end(); ++setIter, ++i)
+      {
+        backMapping.insert(std::map<int, index_t>::value_type(*setIter, i));
+        mapping.insert(std::map<index_t, int>::value_type(i, *setIter));
+        if (*setIter != i)
+          {
+            valid = false;
+          }
+      }
+    if (valid == false)
+      {
+        std::map<int, index_t>::iterator backMappingIter;
+        for (index_t i = 0; i < trainingData.Size(); ++i)
+          {
+            backMappingIter = backMapping.find(trainingData.label[i]);
+            if (backMappingIter == backMapping.end())
+              {
+                throw std::runtime_error("Classificaiton: ValidData error");
+              }
+            else
+              {
+                trainingData.label[i] = backMappingIter->second;
+              }
+          }
+      }
+    return valid;
+  }
+
+  // Bug: paul - int should be labelT
+  void Learning(TrainingParameters& trainingParameters,
+                TrainingDataT& trainingData,
+                DecisionForestT& forest,
+                bool& validLabel,
+                std::map<index_t, labelT>& mapping)
+  {
+    validLabel = ValidData(trainingData, mapping);
+    size_t classNum = mapping.size();
+    if ( !trainingParameters.weights.empty() )
+      {
+        if (classNum != trainingParameters.weights.size())
+          {
+            throw std::runtime_error("Traing parameter weights size doesn't match class size in data\n");
+          }
+      }
+
+    Random random;
+    ClassificationContextT classificationTC(trainingData.Dimension(), classNum);
+    TrainerT trainer(trainingData, trainingParameters, classificationTC, random);
+
+    trainer.Training(forest);
+  }
+
+  void Predicting(DecisionForestT& forest,
+                  TestingDataT& testingData,
+                  bool& validLabel, std::map<index_t, int>& mapping,
+                  SoftPredictionT& softPrediction,
+                  HardPredictionT&  hardPrediction)
+  {
+    TestingResultT testingResult;
+    forest.Apply(testingData, testingResult);
+
+    size_t classNum = mapping.size();
+    size_t treeNum = testingResult.Size();
+    size_t dataNum = testingResult[0].Size();
+    std::vector<double> max(dataNum, 0);
+
+    #pragma omp parallel for
+    for (index_t i = 0; i < dataNum; ++i)
+      {
+        for (index_t j = 0; j < classNum; ++j)
+          {
+            for (index_t k = 0; k < treeNum; ++k)
+              {
+                if (k == 0)
+                  {
+                    softPrediction[i][j] = testingResult[k][i]->prob_[j];
+                  }
+                else
+                  {
+                    softPrediction[i][j] = softPrediction[i][j] + testingResult[k][i]->prob_[j];
+                  }
+              }
+            softPrediction[i][j] = softPrediction[i][j] / treeNum;
+            if (softPrediction[i][j] > max[i])
+              {
+                max[i] = softPrediction[i][j];
+                hardPrediction[i] = j;
+              }
+          }
+        if (validLabel == false)
+          {
+            // Bug: typename missing
+            typename std::map<index_t, labelT>::iterator mapIter = mapping.find(hardPrediction[i]);
+            if (mapIter == mapping.end())
+              {
+                throw std::runtime_error("Classificaiton: Predicting mapping error");
+              }
+            else
+              {
+                hardPrediction[i] = mapIter->second;
+              }
+          }
+      }
+
+  }
+
+  void Run(TrainingParameters& trainingParameters,
+           TrainingDataT& trainingData,
+           TestingDataT& testingData,
+           DecisionForestT& forest,
+           std::map<index_t, int>& mapping,
+           SoftPredictionT& softPrediction,
+           HardPredictionT& hardPrediction)
+  {
+    bool validLabel = true;
+    MPTimer timer;
+    std::cerr << "training begin\n";
+    timer.Start();
+    Learning(trainingParameters, trainingData, forest, validLabel, mapping);
+    std::cerr << "training finished, spending " << timer.StopAndSpendSecond() << " secs\n";
+    std::cerr << "testing begin\n";
+    timer.Start();
+    Predicting(forest, testingData, validLabel, mapping, softPrediction, hardPrediction);
+    std::cerr << "testing finished, spending " << timer.StopAndSpendSecond() << " secs\n";
+  }
+};
+
+#endif // CLASSIFICATION_H
diff --git a/Logic/Preprocessing/RandomForest/Library/classifier.h b/Logic/Preprocessing/RandomForest/Library/classifier.h
new file mode 100755
index 0000000..f98383f
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/classifier.h
@@ -0,0 +1,180 @@
+/**
+ * Define some weak classifiers inherited from abstract Classifier class.
+ */
+
+#ifndef CLASSIFIER_H
+#define CLASSIFIER_H
+
+#include <math.h>
+#include "data.h"
+#include "random.h"
+
+template<class C, class dataT, class labelT>
+class Classifier
+{
+public:
+  // randomly get a classifier
+  virtual C RandomClassifier(Random& random) = 0;
+
+  // calculate feature's response for this classifier
+  virtual double FeatureResponse(const DataSet& data, index_t index) const = 0;
+
+  // calculate boolean response for this classifier and threshold
+  bool Response(const DataSet& data, index_t index)
+  {
+    return FeatureResponse(data, index) < threshold_? true:false;
+  }
+
+  virtual void Read(std::istream& is) = 0;
+  virtual void Write(std::ostream& os) = 0;
+
+  double threshold_;
+};
+
+template<class dataT, class labelT>
+class AxisAlignedClassifier :
+    public Classifier<AxisAlignedClassifier<dataT, labelT>, dataT, labelT>
+{
+public:
+  typedef Classifier<AxisAlignedClassifier<dataT, labelT>, dataT, labelT> ClassifierT;
+  typedef AxisAlignedClassifier<dataT, labelT> AxisAlignedClassifierT;
+  typedef MLData<dataT, labelT> MLDataT;
+
+  AxisAlignedClassifier(): featureDim_(-1), axis_(-1) {}
+  AxisAlignedClassifier(int dimension): featureDim_(dimension), axis_(-1) {}
+  AxisAlignedClassifier(int dimension, int axis): featureDim_(dimension), axis_(axis) {}
+  AxisAlignedClassifierT RandomClassifier(Random &random)
+  {
+    return AxisAlignedClassifierT(featureDim_, random.RandI(0, featureDim_));
+  }
+
+  double FeatureResponse(const DataSet& data, index_t index) const
+  {
+    return ((const MLDataT&)data).data[index][axis_];
+  }
+
+  void Print(int level)
+  {
+    std::cout << "- Classifier: axis"
+              << "    dim = " << featureDim_
+              << "    axis = " << axis_
+              << "    threshold = " << ClassifierT::threshold_;
+    if ((level/100 - (level/1000)*10)  == 2)
+      {
+        std::cout << "    [Addr: " <<  this << "]";
+      }
+    std::cout << std::endl;
+  }
+
+  virtual void Read(std::istream& is)
+  {
+    readBasicType(is, featureDim_);
+    readBasicType(is, axis_);
+    readBasicType(is, ClassifierT::threshold_);
+  }
+
+  virtual void Write(std::ostream& os)
+  {
+    writeBasicType(os, featureDim_);
+    writeBasicType(os, axis_);
+    writeBasicType(os, ClassifierT::threshold_);
+  }
+
+  int featureDim_;
+  int axis_;
+};
+
+template<class dataT, class labelT>
+class LinearClassifier
+    : public Classifier<LinearClassifier<dataT, labelT>, dataT, labelT>
+{
+public:
+  typedef Classifier<LinearClassifier<dataT, labelT>, dataT, labelT> ClassifierT;
+  typedef LinearClassifier<dataT, labelT> LinearClassifierT;
+  typedef MLData<dataT, labelT> MLDataT;
+
+  LinearClassifier(): featureDim_(-1) {}
+  LinearClassifier(int dimension): featureDim_(dimension)
+  {
+    unitVector_.resize(dimension);
+  }
+  LinearClassifier(int dimension, std::vector<dataT>& unitVector)
+    : featureDim_(dimension), unitVector_(unitVector) {}
+
+  LinearClassifierT RandomClassifier(Random &random)
+  {
+    double length = 0;
+    for (int i = 0; i < featureDim_; ++i)
+      {
+        unitVector_[i] = 2.0 * random.RandD() - 1.0;
+        length += unitVector_[i] * unitVector_[i];
+      }
+    length = sqrt(length);
+    for (int i = 0; i < featureDim_; ++i)
+      {
+        unitVector_[i] = unitVector_[i] / length;
+      }
+    return LinearClassifierT(featureDim_, unitVector_);
+  }
+
+  double FeatureResponse(const DataSet &data, index_t index) const
+  {
+    double dotProduct = 0;
+    for (int i = 0; i < featureDim_; ++i)
+      {
+        dotProduct += ((const MLDataT&)data).data[index][i] * unitVector_[i];
+      }
+    return dotProduct;
+  }
+
+  void Print(int level)
+  {
+    std::cout << "- Classifier: linear"
+              << "    dim = " << featureDim_
+              << "    unit vector = [";
+    for (int i = 0; i < featureDim_; ++i)
+      {
+        std::cout << unitVector_[i];
+        if (i != (featureDim_-1))
+          {
+            std::cout << "  ";
+          }
+        else
+          {
+            std::cout << "]";
+          }
+      }
+    std::cout << "    threshold = " << ClassifierT::threshold_;
+    if ((level/100 - (level/1000)*10)  == 2)
+      {
+        std::cout << "    [Addr: " <<  this << "]";
+      }
+    std::cout << std::endl;
+  }
+
+  virtual void Read(std::istream& is)
+  {
+    readBasicType(is, featureDim_);
+    unitVector_.resize(featureDim_);
+    for (int i = 0; i < featureDim_; ++i)
+      {
+        readBasicType(is, unitVector_[i]);
+      }
+    readBasicType(is, ClassifierT::threshold_);
+  }
+
+  virtual void Write(std::ostream& os)
+  {
+    writeBasicType(os, featureDim_);
+    for (int i = 0; i < featureDim_; ++i)
+      {
+        writeBasicType(os, unitVector_[i]);
+      }
+    writeBasicType(os, ClassifierT::threshold_);
+  }
+
+  int featureDim_;
+  std::vector<dataT> unitVector_;
+};
+
+#endif // CLASSIFIER_H
diff --git a/Logic/Preprocessing/RandomForest/Library/data.h b/Logic/Preprocessing/RandomForest/Library/data.h
new file mode 100755
index 0000000..1841db0
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/data.h
@@ -0,0 +1,360 @@
+/**
+ * Define some datasets inherited from abstract DataSet class.
+ */
+
+#ifndef DATA_H
+#define DATA_H
+
+#include <vector>
+#include "random.h"
+
+typedef std::size_t size_t;
+typedef std::size_t index_t;
+
+class DataSet
+{
+public:
+  virtual size_t Size() const = 0;
+  virtual void Resize(size_t n) = 0;
+};
+
+template<class T>
+class Vector : public DataSet
+{
+public:
+  typedef typename std::vector<T>::iterator iterator;
+  typedef typename std::vector<T>::const_iterator const_iterator;
+
+  Vector(): usable_(0) {}
+  Vector(size_t n): usable_(0)
+  {
+    Resize(n);
+  }
+  Vector(size_t n, const T& val=T()): usable_(n)
+  {
+    data_ = std::vector<T>(n,val);
+  }
+
+  size_t Size() const { return data_.size(); }
+  size_t UsableSize() const { return usable_; }
+  void Resize(size_t n)
+  {
+    data_.resize(n);
+    if (n < usable_)
+      {
+        usable_ = n;
+      }
+  }
+
+  void ResetUsable()
+  {
+    usable_ = 0;
+  }
+
+  void PushBack(const T& t)
+  {
+    data_.push_back(t);
+    usable_ = data_.size();
+  }
+
+  void PutBack(const T& t)
+  {
+    if (usable_ < data_.size())
+      {
+        data_[usable_] = t;
+        ++usable_;
+      }
+    else
+      {
+        throw std::runtime_error("PutBack out of range of Vector\n");
+      }
+  }
+
+  const T& Get(index_t i) const
+  {
+    if (i < data_.size())
+      {
+        return data_[i];
+      }
+    else
+      {
+        throw std::runtime_error("Get out of range of Vector\n");
+      }
+  }
+
+  void Set(index_t i, T& t)
+  {
+    if (i < data_.size())
+      {
+        data_[i] = t;;
+      }
+    else
+      {
+        throw std::runtime_error("Set out of range of Vector\n");
+      }
+  }
+
+  T& operator[](index_t i)
+  {
+    if (i < data_.size())
+      {
+        return data_[i];
+      }
+    else
+      {
+        throw std::runtime_error("[] out of range of Vector\n");
+      }
+  }
+  const T& operator[](index_t i) const
+  {
+    if (i < data_.size())
+      {
+        return data_[i];
+      }
+    else
+      {
+        throw std::runtime_error("[] out of range of Vector\n");
+      }
+  }
+
+  iterator Begin() { return data_.begin(); }
+  const_iterator Begin() const { return data_.begin(); }
+  iterator End() { return data_.end(); }
+  const_iterator End() const { return data_.end(); }
+
+private:
+  std::vector<T> data_;
+  index_t usable_;
+};
+
+template<class T>
+class Matrix : public DataSet
+{
+public:
+  Matrix(): rowUsable_(0), colUsable_(0), rowNum_(0), colNum_(0) {}
+  Matrix(size_t rowNum, size_t colNum): rowUsable_(0), colUsable_(0)
+  {
+    Resize(rowNum, colNum);
+  }
+
+  size_t Size() const { return RowSize(); }
+  size_t RowSize() const { return rowNum_; }
+  size_t ColumnSize() const { return colNum_; }
+  size_t UsableSize() const { return RowUsableSize(); }
+  size_t RowUsableSize() const { return rowUsable_; }
+  size_t ColumnUsableSize() const { return colUsable_; }
+
+  void Resize(size_t rowNum, size_t colNum)
+  {
+    data_.resize(rowNum);
+    for (index_t i = 0; i < rowNum; ++i)
+      {
+        data_[i].resize(colNum);
+      }
+    if (rowNum < rowUsable_)
+      {
+        rowUsable_ = rowNum;
+      }
+    if (colNum < colUsable_)
+      {
+        colUsable_ = colNum;
+      }
+    rowNum_ = rowNum;
+    colNum_ = colNum;
+  }
+
+  void Resize(size_t rowNum)
+  {
+    data_.resize(rowNum);
+    for (index_t i = 0; i < rowNum; ++i)
+      {
+        data_[i].resize(colNum_);
+      }
+    if (rowNum < rowUsable_)
+      {
+        rowUsable_ = rowNum;
+      }
+    rowNum_ = rowNum;
+  }
+
+  void ResetUsable()
+  {
+    rowUsable_ = 0;
+    colUsable_ = 0;
+  }
+
+  void PushBack(const std::vector<T>& t)
+  {
+    data_.push_back(t);
+    rowUsable_ = data_.size();
+    ++rowNum_;
+  }
+
+  void PutBack(const T& t)
+  {
+    if ((rowUsable_ < rowNum_) && (colUsable_ < colNum_))
+      {
+        data_[rowUsable_][colUsable_] = t;
+        ++colUsable_;
+        if (colUsable_ == colNum_)
+          {
+            ++rowUsable_;
+            colUsable_ = 0;
+          }
+      }
+    else
+      {
+        throw std::runtime_error("PutBack out of range of Matrix\n");
+      }
+  }
+
+  const T& Get(index_t rowIdx, index_t colIdx) const
+  {
+    if ((rowIdx < rowNum_) && (colIdx < colNum_))
+      {
+        return data_[rowIdx][colIdx];
+      }
+    else
+      {
+        throw std::runtime_error("Get out of range of Matrix\n");
+      }
+  }
+
+  std::vector<T>& GetRow(index_t rowIdx) const
+  {
+    if (rowIdx < rowNum_)
+      {
+        return data_[rowIdx];
+      }
+    else
+      {
+        throw std::runtime_error("GetRow out of range of Matrix\n");
+      }
+  }
+
+  void Set(index_t rowIdx, index_t colIdx, T& t)
+  {
+    if ((rowIdx < rowNum_) && (colIdx < colNum_))
+      {
+        data_[rowIdx][colIdx] = t;
+        if (rowIdx > rowUsable_)
+          {
+            rowUsable_ = rowIdx;
+          }
+        if (colIdx > colUsable_)
+          {
+            colUsable_ = colIdx;
+          }
+      }
+    else
+      {
+        throw std::runtime_error("Set out of range of Matrix\n");
+      }
+  }
+
+  std::vector<T>& operator[](index_t i)
+  {
+    if (i < rowNum_)
+      {
+        return data_[i];
+      }
+    else
+      {
+        throw std::runtime_error("[] out of range of Matrix\n");
+      }
+  }
+  const std::vector<T>& operator[](index_t i) const
+  {
+    if (i < rowNum_)
+      {
+        return data_[i];
+      }
+    else
+      {
+        throw std::runtime_error("[] out of range of Matrix\n");
+      }
+  }
+private:
+  std::vector<std::vector<T> > data_;
+  size_t rowNum_;
+  size_t colNum_;
+  size_t rowUsable_;
+  size_t colUsable_;
+};
+
+template<class dataT, class labelT>
+class MLData: public DataSet
+{
+public:
+  MLData(): dataNum_(0), dataDim_(0) {}
+  MLData(size_t rowNum, size_t colNum): dataNum_(rowNum), dataDim_(colNum)
+  {
+    data.Resize(rowNum, colNum);
+    label.Resize(rowNum);
+  }
+
+  size_t Size() const
+  {
+    return dataNum_;
+  }
+
+  size_t Dimension() const
+  {
+    return dataDim_;
+  }
+
+  void Resize(size_t n)
+  {
+    data.Resize(n);
+    label.Resize(n);
+  }
+
+  size_t LabelClassNum()
+  {
+    std::set<labelT> labelSet(label.Begin(), label.End());
+    return labelSet.size();
+  }
+
+  MLData<dataT, labelT>* Sampling(size_t eachClassNum)
+  {
+    std::set<labelT> labelSet(label.Begin(), label.End());
+    size_t classNum = labelSet.size();
+    std::map<labelT, index_t> backMapping;
+    typename std::set<labelT>::iterator setIter;
+    index_t i = 0;
+    for (setIter = labelSet.begin(); setIter != labelSet.end(); ++setIter, ++i)
+      {
+        backMapping.insert(typename std::map<labelT, index_t>::value_type(*setIter, i));
+      }
+
+    Random random;
+    MLData<dataT, labelT>* sample = new MLData<dataT, labelT>(eachClassNum * classNum, dataDim_);
+    std::vector<std::vector<index_t> > dataIndexSet;
+    dataIndexSet.resize(classNum);
+    for (index_t i = 0; i < dataNum_; ++i)
+      {
+        dataIndexSet[(backMapping.find(label[i]))->second].push_back(i);
+      }
+    for (index_t i = 0; i < classNum; ++i)
+      {
+        size_t maxNum = dataIndexSet[i].size();
+        for (index_t j = 0; j < eachClassNum; ++j)
+          {
+            index_t tmpIdx = dataIndexSet[i][random.RandI(0, maxNum)];
+            sample->label[eachClassNum*i+j] = label[tmpIdx];
+            for (index_t k = 0; k < dataDim_; ++k)
+              {
+                sample->data[eachClassNum*i+j][k] = data[tmpIdx][k];
+              }
+          }
+      }
+    return sample;
+  }
+
+  Matrix<dataT> data;
+  Vector<labelT> label;
+  size_t dataNum_;
+  size_t dataDim_;
+};
+
+#endif // DATA_H
diff --git a/Logic/Preprocessing/RandomForest/Library/forest.h b/Logic/Preprocessing/RandomForest/Library/forest.h
new file mode 100755
index 0000000..ee2707e
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/forest.h
@@ -0,0 +1,114 @@
+/**
+ * Define decision forest as a vector of decision tree's pointer,
+ * testing processing runs in parallel by openMP.
+ */
+
+#ifndef FOREST_H
+#define FOREST_H
+
+#include "tree.h"
+
+template<class S, class C, class dataT>
+class DecisionForest
+{
+public:
+  typedef DecisionTree<S, C, dataT> DecisionTreeT;
+
+  DecisionForest(): verbose_(false) {}
+  DecisionForest(bool verbose): verbose_(verbose) {}
+  ~DecisionForest()
+  {
+    for (size_t i = 0; i < trees_.size(); ++i)
+      {
+        delete trees_[i];
+      }
+  }
+
+  DecisionTreeT* AddTree()
+  {
+    DecisionTreeT* ctree = new DecisionTreeT(verbose_);
+    ctree->idx_ = trees_.size();
+    trees_.push_back(ctree);
+    return ctree;
+  }
+
+  void Apply(MLData<dataT, S*>& testingData,
+             Vector<Vector<S*> >& testingResult)
+  {
+    size_t treeNum = trees_.size();
+    size_t dataNum = testingData.Size();
+
+    testingResult.Resize(treeNum);
+    #pragma omp parallel for
+    for (index_t i = 0; i < treeNum; ++i)
+      {
+        testingResult[i].Resize(dataNum);
+        trees_[i]->Apply(testingData, testingResult[i]);
+      }
+  }
+
+  // Added by Paul. This version of the method allows the same testingResult
+  // vector to be reused. For speed, it does not check that the size of the
+  // testing result is sufficient
+  // This version of the method takes a preallocated vector
+  // index and a preallocated vector response_vec of the same size as
+  // testingData. It does not do allocation to save on computation time
+  void ApplyFast(MLData<dataT, S*>& testingData,
+                 Vector<Vector<S*> >& testingResult,
+                 std::vector<index_t> &index,
+                 std::vector<bool> &response)
+  {
+    size_t treeNum = trees_.size();
+    for (index_t i = 0; i < treeNum; ++i)
+        trees_[i]->ApplyFast(testingData, testingResult[i], index, response);
+  }
+
+  void Print(int level)
+  {
+    for (index_t i = 0; i < trees_.size(); ++i)
+      {
+        std::cout << "tree " << i << " information:" << std::endl;
+        trees_[i]->Print(level);
+      }
+  }
+
+  void Read(std::istream& is)
+  {
+    size_t treeNum = 0;
+    readBasicType(is, verbose_);
+    readBasicType(is, treeNum);
+
+    size_t treeNumBefore = trees_.size();
+    if (treeNumBefore != 0)
+      {
+        for (index_t i = 0; i < treeNumBefore; ++i)
+          {
+            delete trees_[i];
+          }
+      }
+    trees_.resize(treeNum);
+    for (index_t i = 0; i < treeNum; ++i)
+      {
+        trees_[i] = new DecisionTreeT(verbose_);
+        trees_[i]->Read(is);
+      }
+  }
+
+  void Write(std::ostream& os)
+  {
+    size_t treeNum = trees_.size();
+    writeBasicType(os, verbose_);
+    writeBasicType(os, treeNum);
+    for (index_t i = 0; i < treeNum; ++i)
+      {
+        trees_[i]->Write(os);
+      }
+  }
+
+  int GetForestSize() { return trees_.size(); }
+
+  std::vector<DecisionTreeT*> trees_;
+  bool verbose_;
+};
+
+#endif // FOREST_H
diff --git a/Logic/Preprocessing/RandomForest/Library/imageio.h b/Logic/Preprocessing/RandomForest/Library/imageio.h
new file mode 100755
index 0000000..aae9f74
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/imageio.h
@@ -0,0 +1,149 @@
+/**
+ * Use ITK library to deal with image IO.
+ */
+
+#ifndef IMAGEIO_H
+#define IMAGEIO_H
+
+#include "itkImageFileReader.h"
+#include "itkImageFileWriter.h"
+#include "itkImageRegionConstIterator.h"
+#include "itkImageRegionIterator.h"
+#include "data.h"
+
+typedef std::vector<std::string> StringVector;
+
+template<typename TImageType>
+void ImageSizeReader(const std::string& filename, typename TImageType::SizeType& size, typename TImageType::Pointer& image)
+{
+  typedef itk::ImageFileReader<TImageType> ReaderType;
+  typename ReaderType::Pointer reader = ReaderType::New();
+  typename TImageType::RegionType region;
+  try
+  {
+    reader->SetFileName(filename);
+    reader->Update();
+    image = reader->GetOutput();
+    region = image->GetLargestPossibleRegion();
+    size = region.GetSize();
+  }
+  catch( itk::ExceptionObject &err )
+  {
+    std::cerr << "ImageSizeReader Exception Caught !" << std::endl;
+    std::cerr << err << std::endl;
+    exit(1);
+  }
+}
+
+template<typename TImageType, typename dataT, typename labelT>
+MLData<dataT, labelT>* ImageSeriesReader(StringVector& filenames,
+                       size_t& dataNum,
+                       size_t& dataDim,
+                       typename TImageType::SizeType& size)
+{
+  typedef itk::ImageRegionConstIterator<TImageType> ConstIteratorType;
+  typename TImageType::Pointer image;
+  typename TImageType::SizeType curSize;
+
+  int imageDim = size.GetSizeDimension();
+  dataDim = filenames.size() - 1;
+  dataNum = 1;
+
+  MLData<dataT, labelT>* data;
+
+  int dimIdx = -1;
+  for (StringVector::const_iterator filename = filenames.begin();
+       filename != filenames.end(); ++filename, ++dimIdx)
+    {
+      ImageSizeReader<TImageType>(*filename, curSize, image);
+
+      if (filename == filenames.begin())
+        {
+          size = curSize;
+          for (int i = 0; i < imageDim; i++)
+            {
+              dataNum *= size[i];
+            }
+          data = new MLData<dataT, labelT>(dataNum, dataDim);
+//          data = new double*[dataNum];
+//          double *block = new double[dataNum*dataDim];
+//          for (int i = 0; i < dataNum; i++)
+//            {
+//              data[i] = &block[i*dataDim];
+//            }
+        }
+      else if (curSize != size)
+        {
+          std::cerr << "ImageSeriesReader size different !" << std::endl;
+          exit(1);
+        }
+
+      ConstIteratorType iter(image, image->GetLargestPossibleRegion());
+      size_t dataIdx = 0;
+      if (filename == filenames.begin())
+        {
+          for (iter.GoToBegin(); !iter.IsAtEnd(); ++iter, ++dataIdx)
+            {
+              data->label[dataIdx] = iter.Get();
+            }
+        }
+      else
+        {
+          for (iter.GoToBegin(); !iter.IsAtEnd(); ++iter, ++dataIdx)
+            {
+              data->data[dataIdx][dimIdx] = iter.Get();
+            }
+        }
+    }
+  return data;
+}
+
+template<typename TImageType>
+void ImageWriter(const std::string& filename, typename TImageType::Pointer image)
+{
+  typedef itk::ImageFileWriter<TImageType> WriterType;
+  typename WriterType::Pointer writer = WriterType::New();
+  try
+  {
+    writer->SetFileName(filename);
+    writer->SetInput(image);
+    writer->Update();
+  }
+  catch( itk::ExceptionObject &err )
+  {
+    std::cerr << "ImageWriter Exception Caught !" << std::endl;
+    std::cerr << err << std::endl;
+    exit(1);
+  }
+}
+
+template<typename TImageType>
+void ImageSeriesWriter(StringVector& filenames,
+                       Matrix<double>& data,
+                       typename TImageType::SizeType size)
+{
+  typename TImageType::IndexType index;
+  index.Fill(0);
+  typename TImageType::RegionType region(index, size);
+  typename TImageType::Pointer image = TImageType::New();
+  image->SetRegions(region);
+  image->Allocate();
+
+  typedef itk::ImageRegionIterator<TImageType> IteratorType;
+
+  int dimIdx = 0;
+  for (StringVector::const_iterator filename = filenames.begin();
+       filename != filenames.end(); ++filename, ++dimIdx)
+    {
+      IteratorType iter(image, image->GetLargestPossibleRegion());
+      long dataIdx = 0;
+      for (iter.GoToBegin(); !iter.IsAtEnd(); ++iter, ++dataIdx)
+        {
+          iter.Set(data[dataIdx][dimIdx]);
+        }
+
+      ImageWriter<TImageType>(*filename, image);
+    }
+}
+
+#endif // IMAGEIO_H
diff --git a/Logic/Preprocessing/RandomForest/Library/linearalgebra.h b/Logic/Preprocessing/RandomForest/Library/linearalgebra.h
new file mode 100755
index 0000000..db802d2
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/linearalgebra.h
@@ -0,0 +1,227 @@
+/**
+ * Define some basic linear algebra operations.
+ */
+
+#ifndef LINEARALGEBRA_H
+#define LINEARALGEBRA_H
+
+typedef std::size_t size_t;
+typedef std::size_t index_t;
+
+template<class T>
+void cholesky(const std::vector<std::vector<T> >& A,
+              std::vector<std::vector<T> >& L)
+{
+  size_t N = A.size();
+  for (index_t i = 0; i < N; ++i)
+    {
+      for (index_t j = 0; j < N; ++j)
+        {
+          if (j <= i)
+            {
+              T sum = 0;
+              for (index_t k = 0; k < j; ++k)
+                {
+                  sum += L[i][k] * L[j][k];
+                }
+              L[i][j] = (i == j) ?
+                    sqrt(A[i][i] - sum) :
+                    (1.0 / L[j][j] * (A[i][j] - sum));
+            }
+          else
+            {
+              L[i][j] = 0;
+            }
+        }
+    }
+}
+
+template<class T>
+T spddeterminant(const std::vector<std::vector<T> >& A,
+                 bool isTriangular = false)
+{
+  size_t N = A.size();
+  T prod = 1;
+  if (isTriangular)
+    {
+      for (index_t i = 0; i < N; ++i)
+        {
+          prod *= A[i][i] * A[i][i];
+        }
+      return prod;
+    }
+  else
+    {
+      std::vector<std::vector<T> > L;
+      L.resize(N);
+      for (index_t i = 0; i < N; ++i)
+        {
+          L[i].resize(N);
+        }
+      cholesky(A, L);
+      for (index_t i = 0; i < N; ++i)
+        {
+          prod *= L[i][i] * L[i][i];
+        }
+      return prod;
+    }
+}
+
+template<class T>
+void multiply(const std::vector<std::vector<T> >& X,
+              const std::vector<std::vector<T> >& Y,
+              std::vector<std::vector<T> >& result)
+{
+  size_t rowXN = X.size();
+  size_t colXN = X[0].size();
+  size_t rowYN = Y.size();
+  size_t colYN = Y[0].size();
+  if (colXN != rowYN)
+    {
+      throw std::runtime_error("matrix multiplication: XColNum != YRowNum\n");
+    }
+  else
+    {
+      for (index_t i = 0; i < rowXN; ++i)
+        {
+          for (index_t j = 0; j < colYN; ++j)
+            {
+              T sum = 0;
+              for (index_t k = 0; k < colXN; ++k)
+                {
+                  sum += X[i][k] * Y[k][j];
+                }
+              result[i][j] = sum;
+            }
+        }
+    }
+}
+
+template<class T>
+void multiplyXTX(const std::vector<std::vector<T> >& X,
+                 std::vector<std::vector<T> >& result)
+{
+  size_t N = X.size();
+  for (index_t i = 0; i < N; ++i)
+    {
+      for (index_t j = 0; j < N; ++j)
+        {
+          T sum = 0;
+          for (index_t k = 0; k < N; ++k)
+            {
+              sum += X[k][i] * X[k][j];
+            }
+          result[i][j] = sum;
+        }
+    }
+}
+
+template<class T>
+void trianginverse(const std::vector<std::vector<T> >& L,
+                   std::vector<std::vector<T> >& invL)
+{
+  size_t N = L.size();
+  for (index_t j = 0; j < N; ++j)
+    {
+      for (index_t i = 0; i < N; ++i)
+        {
+          if (j <= i)
+            {
+              T sum = (i == j)? 1 : 0;
+              for (index_t k = j; k < i; ++k)
+                {
+                  sum -= L[i][k] * invL[k][j];
+                }
+              invL[i][j] = sum / L[i][i];
+            }
+          else
+            {
+              invL[i][j] = 0;
+            }
+        }
+    }
+}
+
+template<class T>
+void spdinverse(const std::vector<std::vector<T> >& A,
+             std::vector<std::vector<T> >& invA,
+             bool isTriangular = false)
+{
+  size_t N = A.size();
+  static std::vector<std::vector<T> > invL;
+  invL.resize(N);
+  for (index_t i = 0; i < N; ++i)
+    {
+      invL[i].resize(N);
+    }
+  if (isTriangular)
+    {
+      trianginverse(A, invL);
+    }
+  else
+    {
+      std::vector<std::vector<T> > L;
+      L.resize(N);
+      for (index_t i = 0; i < N; ++i)
+        {
+          L[i].resize(N);
+        }
+      cholesky(A, L);
+      trianginverse(L, invL);
+    }
+  multiplyXTX(invL, invA);
+}
+
+template<class T>
+T multiplyXTspdAinvX(const std::vector<T>& X,
+                     const std::vector<std::vector<T> >& A,
+                     bool isTriangular = false)
+{
+  size_t N = A.size();
+  if (N != X.size())
+    {
+      throw std::runtime_error("multiplyXTspdAinvX: XNum != ARowNum\n");
+    }
+  else
+    {
+      std::vector<std::vector<T> > invL;
+      invL.resize(N);
+      for (index_t i = 0; i < N; ++i)
+        {
+          invL[i].resize(N);
+        }
+      if (isTriangular)
+        {
+          trianginverse(A, invL);
+        }
+      else
+        {
+          std::vector<std::vector<T> > L;
+          L.resize(N);
+          for (index_t i = 0; i < N; ++i)
+            {
+              L[i].resize(N);
+            }
+          cholesky(A, L);
+          trianginverse(L, invL);
+        }
+      std::vector<T> tmp(N, 0);
+      for (index_t i = 0; i < N; ++i)
+        {
+          for (index_t j = 0; j < (i+1); ++j)
+            {
+              tmp[i] += invL[i][j] * X[j];
+            }
+        }
+      T result = 0;
+      for (index_t i = 0; i < N; ++i)
+        {
+          result += tmp[i] * tmp[i];
+        }
+      return result;
+    }
+}
+
+
+
+#endif // LINEARALGEBRA_H
diff --git a/Logic/Preprocessing/RandomForest/Library/node.h b/Logic/Preprocessing/RandomForest/Library/node.h
new file mode 100755
index 0000000..baba4ff
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/node.h
@@ -0,0 +1,302 @@
+/**
+ * Define node inheritance:
+ * DTLeaf::Node
+ * DTSplitFull::DTSplit::SplitNode::Node
+ *
+ * and its constructor, streaming and serialization interface.
+ */
+
+
+#ifndef NODE_H
+#define NODE_H
+
+#include "utility.h"
+
+class Node
+{
+public:
+  Node(): type_('l'), parent_(0) {}
+  Node(char type): type_(type), parent_(0) {}
+  Node(Node* parent): type_('l'), parent_(parent) {}
+  Node(char type, Node* parent): type_(type), parent_(parent) {}
+
+  bool IsRoot()
+  {
+    if (type_ == 'r')
+      {
+        return true;
+      }
+    else
+      {
+        return false;
+      }
+  }
+
+  bool IsLeaf()
+  {
+    if (type_ == 'l')
+      {
+        return true;
+      }
+    else
+      {
+        return false;
+      }
+  }
+
+  bool IsSplit()
+  {
+    if (type_ == 's')
+      {
+        return true;
+      }
+    else
+      {
+        return false;
+      }
+  }
+
+  // four digits indicate print results
+  // 0 : nothing
+  // 0001: node index, 0002: node index + address, 0003: node address only
+  // 0010: statistics, 0020: statistics + address
+  // 0100: classifier, 0200: classifier + address
+  // 1000: tree structure depth first, 2000: breath first
+  virtual void Print(int level)
+  {
+    if (((level - (level/10)*10)  == 1) ||
+        ((level - (level/10)*10)  == 2) ||
+        ((level - (level/10)*10)  == 3))
+      {
+        std::cout << "* Node: ";
+        if (IsRoot())
+          {
+            std::cout << "root ";
+          }
+        else if (IsLeaf())
+          {
+            std::cout << "leaf ";
+          }
+        else
+          {
+            std::cout << "split";
+          }
+        if (((level - (level/10)*10)  == 1) ||
+            ((level - (level/10)*10)  == 2))
+          {
+            std::cout << "    (Idx: " << idx_ << ")";
+            if (!IsRoot())
+              {
+                std::cout << "    (Parent Idx: " << parentIdx_ << ")";
+              }
+          }
+        if (((level - (level/10)*10)  == 2) ||
+            ((level - (level/10)*10)  == 3))
+          {
+            std::cout << "    [Addr: " << this << "]";
+            if (!IsRoot())
+              {
+                std::cout << "    [Parent Addr: " << parent_ << "]";
+              }
+          }
+        std::cout << std::endl;
+      }
+  }
+
+  virtual void Read(std::istream& is)
+  {
+    readBasicType(is, type_);
+    readBasicType(is, idx_);
+    readBasicType(is, parentIdx_);
+  }
+
+  virtual void Write(std::ostream& os)
+  {
+    writeBasicType(os, type_);
+    writeBasicType(os, idx_);
+    writeBasicType(os, parentIdx_);
+  }
+
+  // node type (r:root, l:leaf, s:split)
+  char type_;
+  index_t idx_;
+  index_t parentIdx_;
+  Node* parent_;
+};
+
+class SplitNode : public Node
+{
+public:
+  SplitNode(): Node('s'), leftChild_(0), rightChild_(0) {}
+  SplitNode(Node* parent): Node('s', parent) {}
+  SplitNode(Node* parent, Node* leftChild, Node* rightChild)
+    : Node('s', parent), leftChild_(leftChild), rightChild_(rightChild) {}
+
+  virtual void Print(int level)
+  {
+    Node::Print(level);
+    if (((level - (level/10)*10)  == 1) ||
+        ((level - (level/10)*10)  == 2) ||
+        ((level - (level/10)*10)  == 3))
+      {
+        if (((level - (level/10)*10)  == 1) ||
+            ((level - (level/10)*10)  == 2))
+          {
+            std::cout << "    (LeftChild Idx: " << leftChildIdx_ << ")"
+                      << "    (RightChild Idx: " << rightChildIdx_ << ")";
+          }
+        if (((level - (level/10)*10)  == 2) ||
+            ((level - (level/10)*10)  == 3))
+          {
+            std::cout << "    [LeftChild Addr: " << leftChild_ << "]"
+                      << "    [RightChild Addr: " << rightChild_ << "]";
+          }
+        std::cout << std::endl;
+      }
+  }
+
+  virtual void Read(std::istream& is)
+  {
+    Node::Read(is);
+    readBasicType(is, leftChildIdx_);
+    readBasicType(is, rightChildIdx_);
+  }
+
+  virtual void Write(std::ostream& os)
+  {
+    Node::Write(os);
+    writeBasicType(os, leftChildIdx_);
+    writeBasicType(os, rightChildIdx_);
+  }
+
+  index_t leftChildIdx_;
+  index_t rightChildIdx_;
+  Node* leftChild_;
+  Node* rightChild_;
+};
+
+template<class S>
+class DTLeaf : public Node
+{
+public:
+  DTLeaf(): Node() {}
+  DTLeaf(Node* parent): Node(parent) {}
+  DTLeaf(S& statistics): Node(), statistics_(statistics) {} //Need to define copy constructor in S
+  DTLeaf(Node* parent, S& statistics): Node(parent), statistics_(statistics) {}
+  virtual void Print(int level)
+  {
+    Node::Print(level);
+    if (((level/10 - (level/100)*10)  == 1) ||
+        ((level/10 - (level/100)*10)  == 2))
+      {
+        statistics_.Print(level);
+      }
+    std::cout << std::endl;
+  }
+
+  virtual void Read(std::istream& is)
+  {
+    Node::Read(is);
+    statistics_.Read(is);
+  }
+
+  virtual void Write(std::ostream& os)
+  {
+    Node::Write(os);
+    statistics_.Write(os);
+  }
+
+  S statistics_;
+  double informationGain_;
+};
+
+template<class C>
+class DTSplit : public SplitNode
+{
+public:
+  DTSplit(): SplitNode() {}
+  DTSplit(Node* parent): SplitNode(parent) {}
+  DTSplit(Node* parent, Node* leftChild, Node* rightChild)
+    : SplitNode(parent, leftChild, rightChild) {}
+  DTSplit(C& classifier)
+    : SplitNode(), classifier_(classifier) {}//Need to define copy constructor in C
+  DTSplit(Node* parent, C& classifier)
+    : SplitNode(parent), classifier_(classifier) {}
+  DTSplit(Node* parent, Node* leftChild, Node* rightChild, C& classifier)
+    : SplitNode(parent, leftChild, rightChild), classifier_(classifier) {}
+  virtual void Print(int level)
+  {
+    SplitNode::Print(level);
+    if (((level/100 - (level/1000)*10)  == 1) ||
+        ((level/100 - (level/1000)*10)  == 2))
+      {
+        classifier_.Print(level);
+      }
+    std::cout << std::endl;
+  }
+
+  virtual void Read(std::istream& is)
+  {
+    SplitNode::Read(is);
+    classifier_.Read(is);
+  }
+
+  virtual void Write(std::ostream& os)
+  {
+    SplitNode::Write(os);
+    classifier_.Write(os);
+  }
+
+  C classifier_;
+  double informationGain_;
+};
+
+template<class S, class C>
+class DTSplitFull : public DTSplit<C>
+{
+public:
+  DTSplitFull(): DTSplit<C>() {}
+  DTSplitFull(Node* parent): DTSplit<C>(parent) {}
+  DTSplitFull(Node* parent, Node* leftChild, Node* rightChild)
+    : DTSplit<C>(parent, leftChild, rightChild) {}
+  DTSplitFull(S& statistics, C& classifier)
+    : DTSplit<C>(classifier), statistics_(statistics) {}
+  DTSplitFull(Node* parent, S& statistics, C& classifier)
+    : DTSplit<C>(parent, classifier), statistics_(statistics) {}
+  DTSplitFull(Node* parent, Node* leftChild, Node* rightChild,
+              S& statistics, C& classifier)
+    : DTSplit<C>(parent, leftChild, rightChild, classifier),
+      statistics_(statistics) {}
+
+  virtual void Print(int level)
+  {
+    SplitNode::Print(level);
+    if (((level/10 - (level/100)*10)  == 1) ||
+        ((level/10 - (level/100)*10)  == 2))
+      {
+        statistics_.Print(level);
+      }
+    if (((level/100 - (level/1000)*10)  == 1) ||
+        ((level/100 - (level/1000)*10)  == 2))
+      {
+        DTSplitFull<S,C>::classifier_.Print(level);
+      }
+    std::cout << std::endl;
+  }
+
+  virtual void Read(std::istream& is)
+  {
+    DTSplit<C>::Read(is);
+    statistics_.Read(is);
+  }
+
+  virtual void Write(std::ostream& os)
+  {
+    DTSplit<C>::Write(os);
+    statistics_.Write(os);
+  }
+
+  S statistics_;
+};
+
+#endif // NODE_H
diff --git a/Logic/Preprocessing/RandomForest/Library/random.h b/Logic/Preprocessing/RandomForest/Library/random.h
new file mode 100755
index 0000000..1e26c4f
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/random.h
@@ -0,0 +1,45 @@
+/**
+ * Define random number generator.
+ */
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+#include <cstdlib>
+#include <time.h>
+
+class Random
+{
+public:
+  Random()
+  {
+    srand(time(NULL));
+  }
+
+  Random(unsigned int seed)
+  {
+    srand(seed);
+  }
+
+  int RandI()
+  {
+    return rand();
+  }
+
+  int RandI(int min, int max)
+  {
+    return min + rand() % (max-min);
+  }
+
+  double RandD()
+  {
+    return (double) rand() / RAND_MAX;
+  }
+
+  double RandD(double min, double max)
+  {
+    return min + ((double)rand()/RAND_MAX) * (max-min);
+  }
+};
+
+#endif // RANDOM_H
diff --git a/Logic/Preprocessing/RandomForest/Library/statistics.h b/Logic/Preprocessing/RandomForest/Library/statistics.h
new file mode 100755
index 0000000..51caf88
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/statistics.h
@@ -0,0 +1,567 @@
+/**
+ * Define statistics inherited from abstract Statistics class.
+ */
+
+#ifndef STATISTICS_H
+#define STATISTICS_H
+
+#define _USE_MATH_DEFINES
+
+#include <vector>
+#include <math.h>
+#include "data.h"
+#include "linearalgebra.h"
+
+class Statistics
+{
+public:
+//  Statistics();
+//  Statistics(const Statistics& s);
+
+  // aggregate a data with current statistics
+  virtual void Aggregate(const DataSet& data, index_t index) = 0;
+
+  // aggregate two statistics
+  virtual void Aggregate(const Statistics& s) = 0;
+
+  // clear current statistics
+  virtual void Clear() = 0;
+
+  virtual void Read(std::istream& is) = 0;
+  virtual void Write(std::ostream& os) = 0;
+};
+
+template<class dataT, class labelT>
+class Histogram: public Statistics
+{
+public:
+  typedef MLData<dataT, labelT> MLDataT;
+
+  Histogram()
+  {
+    bins_.resize(0);
+    prob_.resize(0);
+    sampleNum_ = 0;
+  }
+  Histogram(size_t classNum)
+  {
+    bins_.resize(classNum);
+    prob_.resize(classNum);
+    for(int i = 0; i < classNum; ++i)
+      {
+        bins_[i] = 0;
+        prob_[i] = 0;
+      }
+    sampleNum_ = 0;
+  }
+
+  void Aggregate(const DataSet& data, index_t index)
+  {
+    // label must start at 0
+    bins_[((const MLDataT&)data).label[index]]++;
+    sampleNum_++;
+  }
+
+  void Aggregate(const Statistics& s)
+  {
+    const Histogram& hist = (const Histogram&)s;
+    if (hist.bins_.size() != bins_.size())
+      {
+        throw std::runtime_error("Aggregate two histgram have different bins!");
+      }
+    for(int i = 0; i < bins_.size(); ++i)
+      {
+        bins_[i] += hist.bins_[i];
+      }
+    sampleNum_ += hist.sampleNum_;
+  }
+
+  void Clear()
+  {
+    for(int i = 0; i < bins_.size(); ++i)
+      {
+        bins_[i] = 0;
+        prob_[i] = 0;
+      }
+    sampleNum_ = 0;
+  }
+
+  double Probability(index_t index) const
+  {
+    return (double)bins_[index] / (double)sampleNum_;
+  }
+
+  // never call this function before calling Entropy(weights) to get prob_ set
+  double Entropy()
+  {
+    static const double ONE_OVER_LOG_2 = 3.3219280945;
+    if (sampleNum_ == 0)
+      {
+        return 0.0;
+      }
+    else
+      {
+        double entropy = 0.0;
+        for (int i = 0; i < prob_.size(); ++i)
+          {
+            if (prob_[i] != 0)
+              {
+                entropy -= prob_[i] * log(prob_[i]) * ONE_OVER_LOG_2;
+              }
+          }
+        return entropy;
+      }
+  }
+
+  double Entropy(const std::vector<double>& weights)
+  {
+    static const double ONE_OVER_LOG_2 = 3.3219280945;
+    if (sampleNum_ == 0)
+      {
+        return 0.0;
+      }
+    else
+      {
+        double entropy = 0.0;
+        if ( weights.empty() )
+          {
+            for(int i = 0; i < bins_.size(); ++i)
+              {
+                if (bins_[i] != 0)
+                  {
+                    prob_[i] = Probability(i);
+                    entropy -= prob_[i] * log(prob_[i]) * ONE_OVER_LOG_2;
+                  }
+              }
+          }
+        else
+          {
+            double sum = 0.0;
+            for(int i = 0; i < bins_.size(); ++i)
+              {
+                prob_[i] = weights[i] * bins_[i];
+                sum += prob_[i];
+              }
+            if (sum != 0.0)
+              {
+                for(int i = 0; i < bins_.size(); ++i)
+                  {
+                    if (prob_[i] != 0)
+                      {
+                        prob_[i] = prob_[i] / sum;
+                        entropy -= prob_[i] * log(prob_[i]);
+                      }
+                  }
+              }
+          }
+
+        return entropy;
+      }
+  }
+
+  void Print(int level)
+  {
+    static int colNum = 8;
+    int i = 0;
+    std::cout << "+ Statistics: hist"
+              << "    sample# = " << sampleNum_;
+    if ((level/10 - (level/100)*10)  == 2)
+      {
+        std::cout << "    [Addr: " << this << "]";
+      }
+    std::cout << std::endl << "  bins: ";
+    for (i = 0; i < bins_.size(); ++i)
+      {
+        std::cout << bins_[i] << "  ";
+        if ((i % colNum) == (colNum - 1))
+          {
+            std::cout << std::endl << "        ";
+          }
+      }
+    if ((i % colNum) != 0)
+      {
+        std::cout << std::endl;
+      }
+  }
+
+  bool Valid()
+  {
+    size_t total = 0;
+    for (size_t i = 0; i < bins_.size(); ++i)
+      {
+        total += bins_[i];
+      }
+    if (total == sampleNum_)
+      {
+        return true;
+      }
+    else
+      {
+        return false;
+      }
+  }
+
+  virtual void Read(std::istream& is)
+  {
+    readBasicType(is, sampleNum_);
+    size_t binSize = 0;
+    readBasicType(is, binSize);
+    bins_.resize(binSize);
+    sampleNum_ = 0;
+    for (size_t i = 0; i < binSize; ++i)
+      {
+        readBasicType(is, bins_[i]);
+        readBasicType(is, prob_[i]);
+      }
+  }
+
+  virtual void Write(std::ostream& os)
+  {
+    if (! Valid())
+      {
+        std::runtime_error("Write statistics, sampleNum_ error!");
+        return;
+      }
+    writeBasicType(os, sampleNum_);
+    size_t binSize = bins_.size();
+    writeBasicType(os, binSize);
+    for (size_t i = 0; i < binSize; ++i)
+      {
+        writeBasicType(os, bins_[i]);
+        writeBasicType(os, prob_[i]);
+      }
+  }
+
+  std::vector<size_t> bins_;
+  std::vector<double> prob_;
+  size_t sampleNum_;
+};
+
+template<class dataT, class labelT>
+class GaussianStat: public Statistics
+{
+public:
+  typedef MLData<dataT, labelT> MLDataT;
+
+  GaussianStat()
+  {
+    x_.resize(0);
+    xSquare_.resize(0);
+    meanValid_ = false;
+    covValid_ = false;
+    featureDim_ = 0;
+    sampleNum_ = 0;
+    a_ = 0.0000001;
+    b_ = 1.0;
+  }
+  GaussianStat(size_t featureDim, double a = 0.0000001, double b = 1.0)
+  {
+    x_.resize(featureDim);
+    xSquare_.resize(featureDim);
+    for(index_t i = 0; i < featureDim; ++i)
+      {
+        x_[i] = 0;
+        xSquare_[i].resize(featureDim);
+        for (index_t j = 0; j < featureDim; ++j)
+          {
+            xSquare_[i][j] = 0;
+          }
+      }
+    meanValid_ = false;
+    covValid_ = false;
+    featureDim_ = featureDim;
+    sampleNum_ = 0;
+    a_ = a < 0.0000001 ? 0.0000001 : a;
+    b_ = b < 1 ? 1.0 : b;
+  }
+
+  void Aggregate(const DataSet& data, index_t index)
+  {
+    dataT tmp = 0;
+    const std::vector<dataT>& vData = ((const MLDataT&)data).data[index];
+    for (index_t i = 0; i < featureDim_; ++i)
+      {
+        x_[i] += vData[i];
+        for (index_t j = i; j < featureDim_; ++j)
+          {
+            tmp = vData[i] * vData[j];
+            xSquare_[i][j] += tmp;
+          }
+        for (index_t j = 0; j < i; ++j)
+          {
+            xSquare_[i][j] = xSquare_[j][i];
+          }
+      }
+    meanValid_ = false;
+    covValid_ = false;
+    sampleNum_++;
+  }
+
+  void Aggregate(const Statistics& s)
+  {
+    const GaussianStat& gaussian = (const GaussianStat&)s;
+    if (gaussian.featureDim_ != featureDim_)
+      {
+        throw std::runtime_error("Aggregate two GaussianStat have different dimension!");
+      }
+    for(index_t i = 0; i < featureDim_; ++i)
+      {
+        x_[i] += gaussian.x_[i];
+        for(index_t j = 0; j < featureDim_; ++j)
+          {
+            xSquare_[i][j] += gaussian.xSquare_[i][j];
+          }
+      }
+    meanValid_ = false;
+    covValid_ = false;
+    sampleNum_ += gaussian.sampleNum_;
+  }
+
+  void CalculateMean()
+  {
+    mean_.resize(featureDim_);
+    for (index_t i = 0; i < featureDim_; ++i)
+      {
+        mean_[i] = x_[i] / sampleNum_;
+      }
+    meanValid_ = true;
+  }
+
+  void CalculateCov()
+  {
+    double alpha = sampleNum_ / (sampleNum_ + a_);
+    double beta = (1 - alpha) * b_;
+    cov_.resize(featureDim_);
+    L_.resize(featureDim_);
+    for (index_t i = 0; i < featureDim_; ++i)
+      {
+        cov_[i].resize(featureDim_);
+        L_[i].resize(featureDim_);
+        for (index_t j = i; j < featureDim_; ++j)
+          {
+            cov_[i][j] = xSquare_[i][j] / sampleNum_
+                - (x_[i] * x_[j]) / (sampleNum_ * sampleNum_);
+//            cov_[i][j] = xSquare_[i][j] / (sampleNum_ - 1)
+//                - (x_[i] * x_[j]) / (sampleNum_ * (sampleNum_ - 1));
+            if (i == j)
+              {
+                cov_[i][j] = alpha * cov_[i][j] + beta;
+              }
+          }
+        for (index_t j = 0; j < i; ++j)
+          {
+            cov_[i][j] = cov_[j][i];
+          }
+      }
+    cholesky(cov_, L_);
+    covValid_ = true;
+  }
+
+  double Entropy(const std::vector<double>& weights)
+  {
+    if (sampleNum_ == 0)
+      {
+        return 0.0;
+      }
+    else
+      {
+        if ( ! covValid_ )
+          {
+            CalculateCov();
+          }
+        return (0.5 * log(pow(2*M_PI*M_E, featureDim_)
+                          * spddeterminant(L_, true)));
+      }
+  }
+
+  double Pdf(std::vector<dataT> X)
+  {
+    if ( ! meanValid_ )
+      {
+        CalculateMean();
+      }
+    if ( ! covValid_ )
+      {
+        CalculateCov();
+      }
+    if (X.size() != mean_.size())
+      {
+        throw std::runtime_error("GaussianStat::Pdf: XSize != meanSize\n");
+      }
+    for (index_t i = 0; i < X.size(); ++i)
+      {
+        X[i] -= mean_[i];
+      }
+    return (sqrt(1.0 / (pow(2 * M_PI, featureDim_) * spddeterminant(L_, true)))
+            * exp(-0.5 * multiplyXTspdAinvX(X, L_, true)));
+  }
+
+  void Clear()
+  {
+    bool hasMean = (mean_.size() != 0);
+    bool hasCov = (cov_.size() != 0);
+    for(index_t i = 0; i < featureDim_; ++i)
+      {
+        x_[i] = 0;
+        if (hasMean)
+          {
+            mean_[i] = 0;
+          }
+        for (index_t j = 0; j < featureDim_; ++j)
+          {
+            xSquare_[i][j] = 0;
+            if (hasCov)
+              {
+                cov_[i][j] = 0;
+                L_[i][j] = 0;
+              }
+          }
+      }
+    meanValid_ = false;
+    covValid_ = false;
+    sampleNum_ = 0;
+  }
+
+  void Print(int level)
+  {
+    std::cout << "+ Statistics: gaussian"
+              << "    sample# = " << sampleNum_;
+    if ((level/10 - (level/100)*10)  == 2)
+      {
+        std::cout << "    [Addr: " << this << "]";
+      }
+    std::cout << std::endl << "a = " << a_ << " , b = " << b_ << std::endl;
+    if (meanValid_)
+      {
+        std::cout << "  mean: " << std::endl;
+        for (index_t i = 0; i < featureDim_; ++i)
+          {
+            std::cout << mean_[i] << "  ";
+          }
+        std::cout << std::endl;
+      }
+    else
+      {
+        std::cout << "  x: " << std::endl;
+        for (index_t i = 0; i < featureDim_; ++i)
+          {
+            std::cout << x_[i] << "  ";
+          }
+        std::cout << std::endl;
+      }
+    if (covValid_)
+      {
+        std::cout << "  covariance: " << std::endl;
+        for (index_t i = 0; i < featureDim_; ++i)
+          {
+            for (index_t j = 0; j < featureDim_; ++j)
+              {
+                std::cout << cov_[i][j] << "  ";
+              }
+            std::cout << std::endl;
+          }
+      }
+    else
+      {
+        std::cout << "  xSquare: " << std::endl;
+        for (index_t i = 0; i < featureDim_; ++i)
+          {
+            for (index_t j = 0; j < featureDim_; ++j)
+              {
+                std::cout << xSquare_[i][j] << "  ";
+              }
+            std::cout << std::endl;
+          }
+      }
+  }
+
+  virtual void Read(std::istream& is)
+  {
+    readBasicType(is, featureDim_);
+    readBasicType(is, sampleNum_);
+    readBasicType(is, a_);
+    readBasicType(is, b_);
+    readBasicType(is, meanValid_);
+    readBasicType(is, covValid_);
+    for (index_t i = 0; i < featureDim_; ++i)
+      {
+        readBasicType(is, x_[i]);
+      }
+    for (index_t i = 0; i < featureDim_; ++i)
+      {
+        for (index_t j = 0; j < featureDim_; ++j)
+          {
+            readBasicType(is, xSquare_[i]);
+          }
+      }
+    if (meanValid_)
+      {
+        for (index_t i = 0; i < featureDim_; ++i)
+          {
+            readBasicType(is, mean_[i]);
+          }
+      }
+    if (covValid_)
+      {
+        for (index_t i = 0; i < featureDim_; ++i)
+          {
+            for (index_t j = 0; j < featureDim_; ++j)
+              {
+                readBasicType(is, cov_[i]);
+              }
+          }
+      }
+  }
+
+  virtual void Write(std::ostream& os)
+  {
+    writeBasicType(os, featureDim_);
+    writeBasicType(os, sampleNum_);
+    writeBasicType(os, a_);
+    writeBasicType(os, b_);
+    writeBasicType(os, meanValid_);
+    writeBasicType(os, covValid_);
+    for (index_t i = 0; i < featureDim_; ++i)
+      {
+        writeBasicType(os, x_[i]);
+      }
+    for (index_t i = 0; i < featureDim_; ++i)
+      {
+        for (index_t j = 0; j < featureDim_; ++j)
+          {
+            writeBasicType(os, xSquare_[i]);
+          }
+      }
+    if (meanValid_)
+      {
+        for (index_t i = 0; i < featureDim_; ++i)
+          {
+            writeBasicType(os, mean_[i]);
+          }
+      }
+    if (covValid_)
+      {
+        for (index_t i = 0; i < featureDim_; ++i)
+          {
+            for (index_t j = 0; j < featureDim_; ++j)
+              {
+                writeBasicType(os, cov_[i]);
+              }
+          }
+      }
+  }
+
+  std::vector<dataT> x_;
+  std::vector<std::vector<dataT> > xSquare_;
+  std::vector<dataT> mean_;
+  std::vector<std::vector<dataT> > cov_;
+  std::vector<std::vector<dataT> > L_;
+  bool meanValid_;
+  bool covValid_;
+  size_t featureDim_;
+  size_t sampleNum_;
+  double a_;
+  double b_;
+};
+
+#endif // STATISTICS_H
diff --git a/Logic/Preprocessing/RandomForest/Library/trainer.h b/Logic/Preprocessing/RandomForest/Library/trainer.h
new file mode 100755
index 0000000..3604665
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/trainer.h
@@ -0,0 +1,325 @@
+/**
+ * Define trainer class to deal with tree training processing in a depth first way,
+ * forest training is just a lot of parallel tree training implemented by openMP.
+ * Randomness is achieved by two ways:
+ * randomness in sub-sample input dataset (bagging);
+ * randomness in weak learner parameters chosen in each tree node, achieved by
+ *   randomly choosing the best combination of weak classifier parameters (outside loop)
+ *   and thresholds (inside loop) to get the largest information gain.
+ */
+
+#ifndef TRAINER_H
+#define TRAINER_H
+
+#include <limits>
+#include "forest.h"
+#include "trainingcontext.h"
+
+template<class C, class S, class dataT, class labelT>
+class Trainer
+{
+public:
+  typedef DecisionTree<S,C,dataT> DecisionTreeT;
+  typedef DecisionForest<S,C,dataT> DecisionForestT;
+
+  Trainer(const MLData<dataT, labelT>& trainingData,
+          TrainingParameters trainingParameters,
+          TrainingContext<S, C>& trainingContext,
+          Random& random)
+    : trainingData_(trainingData),
+      trainingParameters_(trainingParameters),
+      trainingContext_(trainingContext),
+      random_(random)
+  {
+    if (trainingParameters_.subSamplePercent == 0.0)
+      {
+        subSampleNum_ = trainingData_.Size();
+      }
+    else
+      {
+        subSampleNum_ = trainingData_.Size()
+            * trainingParameters_.subSamplePercent / 100;
+      }
+  }
+
+  size_t CandidateThresholds(std::vector<double>& thresholds,
+                             std::vector<double>& featureResponses,
+                             index_t begin, index_t end)
+  {
+    size_t thresholdNum;
+    if ((end - begin) > trainingParameters_.candidateClassifierThresholdNum)
+      {
+        thresholdNum = trainingParameters_.candidateClassifierThresholdNum;
+        for (size_t i = 0; i < (thresholdNum + 1); ++i)
+          {
+            thresholds[i] = featureResponses[random_.RandI(begin, end)];
+          }
+      }
+    else
+      {
+        thresholdNum = end - begin - 1;
+        std::copy(featureResponses.begin() + begin,
+                  featureResponses.begin() + end,
+                  thresholds.begin());
+      }
+
+    std::sort(thresholds.begin(), thresholds.begin() + thresholdNum + 1);
+
+    if (thresholds[0] == thresholds[thresholdNum])
+      {
+        return 0;
+      }
+    else
+      {
+        for (size_t i = 0; i < thresholdNum; ++i)
+          {
+            thresholds[i] = thresholds[i] +
+                random_.RandD() * (thresholds[i+1] - thresholds[i]);
+          }
+        return thresholdNum;
+      }
+  }
+
+  void DepthFirst(DecisionTreeT& tree, Node* pnode,
+                  bool side, size_t cDepth,
+                  index_t begin, index_t end,
+                  S& pStatistics, S& lStatistics, S& rStatistics,
+                  std::vector<S>& ctStatistics,
+                  std::vector<double>& cthresholds,
+                  std::vector<size_t>& indices,
+                  std::vector<double>& featureResponses,
+                  std::vector<bool>& responses)
+  {
+    if (trainingParameters_.treeDepth == 1)
+      {
+        throw std::runtime_error("training parameters: treeDepth couldn't be 1\n");
+      }
+    if (tree.depth_ < cDepth)
+      {
+        tree.depth_ = cDepth;
+      }
+    Node* cNode;
+    pStatistics.Clear();
+    for(index_t i = begin; i < end; ++i)
+      {
+        pStatistics.Aggregate(trainingData_, indices[i]);
+      }
+
+    if (trainingParameters_.treeDepth > 0)
+      {
+        if (cDepth >= trainingParameters_.treeDepth)
+          {
+            cNode = tree.AddLeafNode(side, pnode, pStatistics,
+                                     -std::numeric_limits<double>::infinity());
+            return;
+          }
+      }
+
+    size_t thresholdNum;
+    double bestIG = 0.0;
+    double cIG = 0.0;
+    C bestClassifier = trainingContext_.RandomClassifier(random_);
+    int maxTrial = 3;
+    int trial = 0;
+    while (trial < maxTrial)
+      {
+        for(size_t i = 0; i < trainingParameters_.candidateNodeClassifierNum; ++i)
+          {
+            C cClassifier = trainingContext_.RandomClassifier(random_);
+
+            for (size_t j = 0; j < ctStatistics.size(); ++j)
+              {
+                ctStatistics[j].Clear();
+              }
+
+            for (index_t j = begin; j < end; ++j)
+              {
+                featureResponses[j] = cClassifier.FeatureResponse(trainingData_, indices[j]);
+              }
+
+            thresholdNum = 0;
+            int counts = 0;
+            while ((thresholdNum == 0) && (end - begin > 1) && (counts < 10))     /////////////
+              {
+                thresholdNum = CandidateThresholds(cthresholds, featureResponses, begin, end);
+                counts++;
+              }
+
+            size_t which;
+            for (index_t j = begin; j < end; ++j)
+              {
+                which = 0;
+                while ((which < thresholdNum) &&
+                       (featureResponses[j] >= cthresholds[which]))
+                  {
+                    ++which;
+                  }
+                ctStatistics[which].Aggregate(trainingData_, indices[j]);
+              }
+
+            for (size_t j = 0; j < thresholdNum; ++j)
+              {
+                lStatistics.Clear();
+                rStatistics.Clear();
+
+                for (size_t k = 0; k < (thresholdNum + 1); ++k)
+                  {
+                    if (k <= j)
+                      {
+                        lStatistics.Aggregate(ctStatistics[k]);
+                      }
+                    else
+                      {
+                        rStatistics.Aggregate(ctStatistics[k]);
+                      }
+                  }
+
+                cIG = trainingContext_.ComputeIG(pStatistics, lStatistics, rStatistics,
+                                                 trainingParameters_.weights);
+
+                if (cIG >= bestIG)
+                  {
+                    bestIG = cIG;
+                    bestClassifier = cClassifier;
+                    bestClassifier.threshold_ = cthresholds[j];
+                  }
+              }
+          }
+
+        if (cDepth == 1)
+          {
+            cNode = tree.AddRoot(bestClassifier, pStatistics, bestIG);
+            break;
+          }
+        else
+          {
+            if (bestIG <= trainingParameters_.splitIG)
+              {
+                if ((pStatistics.Entropy() <= trainingParameters_.leafEntropy) ||
+                    (trainingParameters_.leafEntropy == -std::numeric_limits<double>::infinity()))
+                  {
+                    cNode = tree.AddLeafNode(side, pnode, pStatistics, bestIG);
+                    return;
+                  }
+                else
+                  {
+                    ++trial;
+                    if (trial == maxTrial)
+                      {
+                        ++tree.suspectLeaves_;
+                        cNode = tree.AddLeafNode(side, pnode, pStatistics, bestIG);
+                        return;
+                      }
+                    continue;
+                  }
+              }
+            else
+              {
+                cNode = tree.AddSplitNode(side, pnode, bestClassifier, pStatistics, bestIG);
+                break;
+              }
+          }
+      }
+
+    for (index_t i = begin; i < end; ++i)
+      {
+        responses[i] = bestClassifier.Response(trainingData_, indices[i]);
+      }
+
+    index_t division = Partition(responses, indices, begin, end);
+
+    DepthFirst(tree, cNode, true, cDepth + 1, begin, division,
+               pStatistics, lStatistics, rStatistics, ctStatistics,
+               cthresholds, indices, featureResponses, responses);
+    DepthFirst(tree, cNode, false, cDepth + 1, division, end,
+               pStatistics, lStatistics, rStatistics, ctStatistics,
+               cthresholds, indices, featureResponses, responses);
+  }
+
+  void Training(DecisionTreeT& tree)
+  {
+    size_t nodeNumBefore = tree.nodes_.size();
+    if (nodeNumBefore != 0)
+      {
+        for (index_t i = 0; i < nodeNumBefore; ++i)
+          {
+            delete tree.nodes_[i];
+          }
+        tree.nodes_.resize(0);
+      }
+
+    S pStatistics, lStatistics, rStatistics;
+    std::vector<S> ctStatistics;
+    std::vector<double> cthresholds;
+    std::vector<size_t> indices;
+    std::vector<double> featureResponses;
+    std::vector<bool> responses;
+
+    indices.resize(subSampleNum_);
+    if (subSampleNum_ == trainingData_.Size())
+      {
+        for(index_t i = 0; i < indices.size(); ++i)
+          {
+            indices[i] = i;
+          }
+      }
+    else
+      {
+        for(index_t i = 0; i < indices.size(); ++i)
+          {
+            indices[i] = random_.RandD(0, trainingData_.Size());
+          }
+      }
+
+    featureResponses.resize(subSampleNum_);
+    responses.resize(subSampleNum_);
+
+    pStatistics = trainingContext_.Statistics();
+    lStatistics = trainingContext_.Statistics();
+    rStatistics = trainingContext_.Statistics();
+
+    ctStatistics.resize(trainingParameters_.candidateClassifierThresholdNum + 1);
+    for(size_t i = 0; i < (trainingParameters_.candidateClassifierThresholdNum + 1); ++i)
+      {
+        ctStatistics[i] = trainingContext_.Statistics();
+      }
+
+    cthresholds.resize(trainingParameters_.candidateClassifierThresholdNum + 1); // only candidateClassifierThresholdNum is valid
+
+    DepthFirst(tree, 0, true, 1, 0, subSampleNum_,
+               pStatistics, lStatistics, rStatistics, ctStatistics,
+               cthresholds, indices, featureResponses, responses);
+  }
+
+  void Training(DecisionForestT& forest)
+  {
+    size_t treeNumBefore = forest.trees_.size();
+    if (treeNumBefore != 0)
+      {
+        for (index_t i = 0; i < treeNumBefore; ++i)
+          {
+            delete forest.trees_[i];
+          }
+        forest.trees_.resize(0);
+      }
+
+    for (index_t i = 0; i < trainingParameters_.treeNum; ++i)
+      {
+        forest.AddTree();
+      }
+
+    #pragma omp parallel for
+    for (index_t i = 0; i < trainingParameters_.treeNum; ++i)
+      {
+        Training(*(forest.trees_[i]));
+      }
+  }
+
+  const MLData<dataT, labelT>& trainingData_;
+  TrainingParameters trainingParameters_;
+  TrainingContext<S, C>& trainingContext_;
+  size_t subSampleNum_;
+  Random& random_;
+};
+
+#endif // TRAINER_H
diff --git a/Logic/Preprocessing/RandomForest/Library/trainingcontext.h b/Logic/Preprocessing/RandomForest/Library/trainingcontext.h
new file mode 100755
index 0000000..2327634
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/trainingcontext.h
@@ -0,0 +1,140 @@
+/**
+ * Define different traning context inherited from abstract TrainingContext class
+ * by instantiating different statistics and classifiers.
+ */
+
+#ifndef TRAININGCONTEXT_H
+#define TRAININGCONTEXT_H
+
+#include "classifier.h"
+#include "statistics.h"
+
+struct TrainingParameters
+{
+  size_t treeNum;
+  size_t treeDepth;
+  size_t candidateNodeClassifierNum;
+  size_t candidateClassifierThresholdNum;
+  std::vector<double> weights;
+  double subSamplePercent;
+  double splitIG;
+  double leafEntropy;
+  bool verbose;
+};
+
+template<class S, class C>
+class TrainingContext
+{
+public:
+  // randomly get a classifier
+  virtual C RandomClassifier(Random& random) = 0;
+
+  // get an object of statistics
+  virtual S Statistics() = 0;
+
+  // compute information gain
+  virtual double ComputeIG(S& parent, S& leftChild, S& rightChild,
+                           const std::vector<double>& weights) = 0;
+};
+
+template<class C, class dataT, class labelT>
+class ClassificationContext : public TrainingContext<Histogram<dataT, labelT>, C>
+{
+public:
+  ClassificationContext(int featureDim, int classNum): classNum_(classNum)
+  {
+    classifier_ = new C(featureDim);
+  }
+  ~ClassificationContext()
+  {
+    delete classifier_;
+  }
+
+  //// law of four here???
+
+  C RandomClassifier(Random &random)
+  {
+    return classifier_->RandomClassifier(random);
+  }
+
+  Histogram<dataT, labelT> Statistics()
+  {
+    return Histogram<dataT, labelT>(classNum_);
+  }
+
+  double ComputeIG(Histogram<dataT, labelT>& parent,
+                   Histogram<dataT, labelT>& leftChild,
+                   Histogram<dataT, labelT>& rightChild,
+                   const std::vector<double>& weights)
+  {
+    std::size_t pSampleNum = parent.sampleNum_;
+    std::size_t lSampleNum = leftChild.sampleNum_;
+    std::size_t rSampleNum = rightChild.sampleNum_;
+    if ((lSampleNum == 0) || (rSampleNum == 0))
+      {
+        return 0.0;
+      }
+    else if ((lSampleNum + rSampleNum) != pSampleNum) {
+        throw std::runtime_error("ComputeIG sampleNum error!");
+      }
+    else
+      {
+        return (parent.Entropy(weights) -
+                (lSampleNum * leftChild.Entropy(weights) + rSampleNum * rightChild.Entropy(weights))/pSampleNum);
+      }
+  }
+
+  C* classifier_;
+  std::size_t classNum_;
+};
+
+template<class C, class dataT, class labelT>
+class DensityEstimationContext : public TrainingContext<GaussianStat<dataT, labelT>, C>
+{
+public:
+  DensityEstimationContext(int featureDim): featureDim_(featureDim)
+  {
+    classifier_ = new C(featureDim);
+  }
+  ~DensityEstimationContext()
+  {
+    delete classifier_;
+  }
+
+  C RandomClassifier(Random &random)
+  {
+    return classifier_->RandomClassifier(random);
+  }
+
+  GaussianStat<dataT, labelT> Statistics()
+  {
+    return GaussianStat<dataT, labelT>(featureDim_);
+  }
+
+  double ComputeIG(Histogram<dataT, labelT>& parent,
+                   Histogram<dataT, labelT>& leftChild,
+                   Histogram<dataT, labelT>& rightChild,
+                   const std::vector<double>& weights)
+  {
+    std::size_t pSampleNum = parent.sampleNum_;
+    std::size_t lSampleNum = leftChild.sampleNum_;
+    std::size_t rSampleNum = rightChild.sampleNum_;
+    if ((lSampleNum == 0) || (rSampleNum == 0))
+      {
+        return 0.0;
+      }
+    else if ((lSampleNum + rSampleNum) != pSampleNum) {
+        throw std::runtime_error("ComputeIG sampleNum error!");
+      }
+    else
+      {
+        return (parent.Entropy(weights) -
+                (lSampleNum * leftChild.Entropy(weights) + rSampleNum * rightChild.Entropy(weights))/pSampleNum);
+      }
+  }
+
+  C* classifier_;
+  std::size_t featureDim_;
+};
+
+#endif // TRAININGCONTEXT_H
diff --git a/Logic/Preprocessing/RandomForest/Library/tree.h b/Logic/Preprocessing/RandomForest/Library/tree.h
new file mode 100755
index 0000000..99f5326
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/tree.h
@@ -0,0 +1,563 @@
+/**
+ * Define tree structure as a vector of nodes' pointer,
+ * member nodes_ is stored as depth first way, as well as Travel member function,
+ * add node into tree should be done through AddRoot, AddSplitNode or AddLeafNode,
+ * streaming and serialization interface are included into DecisionTree class.
+ *
+ * Partition define as a public function that divides parent node's data into
+ * its left and right child node according to pre-calculated boolean response.
+ */
+
+#ifndef TREE_H
+#define TREE_H
+
+#include <iomanip>
+#include <queue>
+#include <stdexcept>
+#include <cmath>
+#include "node.h"
+#include "data.h"
+
+// paul: bug, this function needs inlining
+inline std::size_t Partition(std::vector<bool>& response,
+                      std::vector<index_t>& index,
+                      index_t begin,
+                      index_t end)
+{
+  index_t i = begin;
+  index_t j = end-1;
+  index_t tmpIdx;
+  bool tmpResps;
+  while (i != j)
+    {
+      while ((response[i] == false) && (i != j))
+        {
+          ++i;
+        }
+      while ((response[j] == true) && (i != j))
+        {
+          --j;
+        }
+      if (i != j)
+        {
+          tmpIdx = index[i];
+          tmpResps = response[i];
+          index[i] = index[j];
+          response[i] = response[j];
+          index[j] = tmpIdx;
+          response[j] = tmpResps;
+        }
+    }
+
+  return (response[i] == false? i+1 : i);
+}
+
+template<class S, class C, class dataT>
+class DecisionTree
+{
+public:
+  typedef DTLeaf<S> LeafT;
+  typedef DTSplit<C> SplitT;
+  typedef DTSplitFull<S, C> SplitFullT;
+
+  DecisionTree(bool verbose): verbose_(verbose), depth_(0), suspectLeaves_(0) {}
+  ~DecisionTree()
+  {
+    for (size_t i = 0; i < nodes_.size(); ++i)
+      {
+        delete nodes_[i];
+      }
+  }
+
+  void Apply(MLData<dataT, S*>& testingData,
+             Vector<S*>& testingResult)
+  {
+    std::vector<index_t> index(testingData.Size());
+    for (index_t i = 0; i != testingData.Size(); ++i)
+      {
+        index[i] = i;
+      }
+
+    std::vector<bool> response(testingData.Size());
+
+    Travel(nodes_[0], 0, testingData.Size(), testingData, testingResult,
+           index, response);
+  }
+
+  // Added by Paul. This version of the method takes a preallocated vector
+  // index and a preallocated vector response_vec of the same size as
+  // testingData. It does not do allocation to save on computation time
+  void ApplyFast(MLData<dataT, S*>& testingData,
+                 Vector<S*>& testingResult,
+                 std::vector<index_t> &index,
+                 std::vector<bool> &response)
+  {
+    for (index_t i = 0; i != testingData.Size(); ++i)
+      {
+        index[i] = i;
+      }
+
+    Travel(nodes_[0], 0, testingData.Size(), testingData, testingResult,
+           index, response);
+  }
+
+  // depth first travel
+  void Travel(Node* node, index_t begin, index_t end,
+              MLData<dataT, S*>& testingData, Vector<S*>& testingResult,
+              std::vector<index_t>& index, std::vector<bool>& response)
+  {
+    if (begin == end)
+      {
+        return;
+      }
+
+    if (node->IsLeaf())
+      {
+        for (index_t i = begin; i != end; ++i)
+          {
+            testingResult[index[i]] = &(((LeafT*)node)->statistics_);
+          }
+        return;
+      }
+
+//    #pragma omp parallel for
+    for (index_t i = begin; i < end; ++i)
+      {
+        response[i] = ((SplitT*)node)->classifier_.Response(testingData, index[i]);
+      }
+
+    std::size_t division = Partition(response, index, begin, end);
+
+    Travel(((SplitT*)node)->leftChild_, begin, division,
+           testingData, testingResult, index, response);
+    Travel(((SplitT*)node)->rightChild_, division, end,
+           testingData, testingResult, index, response);
+  }
+
+  Node* AddLeafNode(bool side, Node* parent, S& statistics, double gain)
+  {
+    Node* cnode = (Node*) new LeafT(statistics);
+    cnode->type_ = 'l';
+    cnode->parent_ = parent;
+    cnode->idx_ = nodes_.size();
+    cnode->parentIdx_ = parent->idx_;
+    ((LeafT*)cnode)->informationGain_ = gain;
+    if (side == true)
+      {
+        ((SplitNode*)parent)->leftChild_ = cnode;
+        ((SplitNode*)parent)->leftChildIdx_ = cnode->idx_;
+      }
+    else
+      {
+        ((SplitNode*)parent)->rightChild_ = cnode;
+        ((SplitNode*)parent)->rightChildIdx_ = cnode->idx_;
+      }
+    nodes_.push_back(cnode);
+    return cnode;
+  }
+
+  Node* AddSplitNode(bool side, Node* parent, C& classifier, S& statistics, double gain)
+  {
+    Node* cnode = 0;
+    if (verbose_)
+      {
+        cnode = (Node*) new SplitFullT(statistics, classifier);
+      }
+    else
+      {
+        cnode = (Node*) new SplitT(classifier);
+      }
+    cnode->type_ = 's';
+    cnode->parent_ = parent;
+    cnode->idx_ = nodes_.size();
+    cnode->parentIdx_ = parent->idx_;
+    ((SplitT*)cnode)->informationGain_ = gain;
+    if (side == true)
+      {
+        ((SplitNode*)parent)->leftChild_ = cnode;
+        ((SplitNode*)parent)->leftChildIdx_ = cnode->idx_;
+      }
+    else
+      {
+        ((SplitNode*)parent)->rightChild_ = cnode;
+        ((SplitNode*)parent)->rightChildIdx_ = cnode->idx_;
+      }
+    nodes_.push_back(cnode);
+    return cnode;
+  }
+
+  Node* AddRoot(C& classifier, S& statistics, double gain)
+  {
+    Node* cnode = 0;
+    if (verbose_)
+      {
+        cnode = (Node*) new SplitFullT(statistics, classifier);
+      }
+    else
+      {
+        cnode = (Node*) new SplitT(classifier);
+      }
+    cnode->type_ = 'r';
+    cnode->parent_ = 0;
+    cnode->idx_ = nodes_.size();
+    cnode->parentIdx_ = -1;
+    ((SplitT*)cnode)->informationGain_ = gain;
+    nodes_.push_back(cnode);
+    return cnode;
+  }
+
+//  void BreadthFirstTraversal()
+//  {
+//    nodesBreadthFirst_.resize(nodes_.size());
+//    std::queue<Node*> unvisited;
+//    Node* cNode;
+//    unvisited.push(nodes_[0]);
+//    int idx = 0;
+//    while (!unvisited.empty())
+//      {
+//        cNode = unvisited.front();
+//        if (!cNode->IsLeaf())
+//          {
+//            if (((SplitNode*)cNode)->leftChild != 0)
+//              {
+//                unvisited.push(((SplitNode*)cNode)->leftChild);
+//              }
+//            if (((SplitNode*)cNode)->rightChild != 0)
+//              {
+//                unvisited.push(((SplitNode*)cNode)->rightChild);
+//              }
+//          }
+//        nodesBreadthFirst_[idx++] = cNode;
+//        unvisited.pop();
+//      }
+//  }
+
+  void PreOrderDepthFirst(Node* cNode, int cIndex)
+  {
+    breadthFirstFullTree_[cIndex-1] = cNode;
+    if (cNode->IsLeaf())
+      {
+        return;
+      }
+    PreOrderDepthFirst(((SplitNode*)cNode)->leftChild_, cIndex * 2);
+    PreOrderDepthFirst(((SplitNode*)cNode)->rightChild_, cIndex * 2 + 1);
+  }
+
+  void BreathFirstFullTree()
+  {
+    breadthFirstFullTree_.resize(pow(2, depth_)-1);
+    for (int i = 0; i < breadthFirstFullTree_.size(); ++i)
+      {
+        breadthFirstFullTree_[i] = 0;
+      }
+    PreOrderDepthFirst(nodes_[0], 1);
+  }
+
+  void DepthFirstPrint(Node* cNode, size_t cDepth, bool side, std::string str)
+  {
+    if (cNode->type_ == 'r')
+      {
+        std::cout << str << "R " << cNode->idx_
+                  << std::setprecision(4)
+                  << ":  ("
+//                  << "threshold = "
+//                  << ((SplitT*)cNode)->classifier_.threshold_
+//                  << ", "
+                  << "IG = "
+                  << ((SplitT*)cNode)->informationGain_
+                  << ")"<< std::endl;
+      }
+    else
+      {
+        if (cNode->type_ == 'l')
+          {
+            if (((LeafT*)cNode)->informationGain_ == -std::numeric_limits<double>::infinity())
+              {
+                if (side == true)
+                  {
+                    std::cout << str << "|-L " << cNode->idx_
+                              << ":  Reach max tree depth (H = "
+                              << ((LeafT*)cNode)->statistics_.Entropy()
+                              << ")"<< std::endl;
+                  }
+                else
+                  {
+                    std::cout << str << "+-L " << cNode->idx_
+                              << ":  Reach max tree depth (H = "
+                              << ((LeafT*)cNode)->statistics_.Entropy()
+                              << ")"<< std::endl;
+                  }
+              }
+            else
+              {
+                if (side == true)
+                  {
+                    std::cout << str << "|-L " << cNode->idx_
+                              << ":  Small IG = "
+                              << std::setiosflags(std::ios::fixed)
+                              << std::setprecision(2)
+                              << ((SplitT*)cNode)->informationGain_
+                              << " (H = "
+                              << ((LeafT*)cNode)->statistics_.Entropy()
+                              << ")"<< std::endl;
+                  }
+                else
+                  {
+                    std::cout << str << "+-L " << cNode->idx_
+                              << ":  Small IG = "
+                              << std::setiosflags(std::ios::fixed)
+                              << std::setprecision(2)
+                              << ((SplitT*)cNode)->informationGain_
+                              << " (H = "
+                              << ((LeafT*)cNode)->statistics_.Entropy()
+                              << ")"<< std::endl;
+                  }
+              }
+            return;
+          }
+        else
+          {
+            if (side == true)
+              {
+                std::cout << str << "|-S " << cNode->idx_
+                          << std::setprecision(4)
+                          << ":  ("
+//                          << "threshold = "
+//                          << ((SplitT*)cNode)->classifier_.threshold_
+//                          << ", "
+                          << "IG = "
+                          << ((SplitT*)cNode)->informationGain_
+                          << ")"<< std::endl;
+              }
+            else
+              {
+                std::cout << str << "+-S " << cNode->idx_
+                          << std::setprecision(4)
+                          << ":  ("
+//                          << "threshold = "
+//                          << ((SplitT*)cNode)->classifier_.threshold_
+//                          << ", "
+                          << "IG = "
+                          << ((SplitT*)cNode)->informationGain_
+                          << ")"<< std::endl;
+              }
+          }
+      }
+    if (cDepth > 1)
+      {
+        if (side == true)
+          {
+            str += "| ";
+          }
+        else
+          {
+            str += "  ";
+          }
+      }
+    DepthFirstPrint(((SplitNode*)cNode)->leftChild_, cDepth+1, true, str);
+    DepthFirstPrint(((SplitNode*)cNode)->rightChild_, cDepth+1, false, str);
+  }
+
+  void Print(int level)
+  {
+    if ((level % 1000) > 0)
+      {
+        for (size_t i = 0; i < nodes_.size(); ++i)
+          {
+            nodes_[i]->Print(level);
+          }
+      }
+    if ((level/1000 - (level/10000)*10)  == 1)
+      {
+        DepthFirstPrint(nodes_[0], 1, true, std::string(""));
+      }
+    if ((level/1000 - (level/10000)*10)  == 2)
+      {
+        if ((breadthFirstFullTree_.size() == 0) && (nodes_.size() != 0))
+          {
+            BreathFirstFullTree();
+          }
+        if (breadthFirstFullTree_.size() != 0)
+          {
+            int spaceWidth = 1;
+            int numWidth = 0;
+            int s = nodes_.size();
+            while (s != 0)
+              {
+                numWidth++;
+                s /= 10;
+              }
+
+            std::ios_base::fmtflags original_flags = std::cout.flags();
+            int index = 0;
+            int interval = pow(2, depth_) - 1;
+            int start = (interval - 1) / 2;
+
+            int nodeNum = 0;
+            for (int i = 0; i < depth_; ++i)
+              {
+                nodeNum = pow(2, i);
+                for (int j = 0; j < start; ++j)
+                  {
+                    for (int k = 0; k < (spaceWidth + numWidth); ++k)
+                      {
+                        std::cout << " ";
+                      }
+                  }
+                for (int j = 0; j < spaceWidth; ++j)
+                  {
+                    std::cout << " ";
+                  }
+                if (breadthFirstFullTree_[index] != 0)
+                  {
+                    std::cout << std::setw(numWidth)
+                              << breadthFirstFullTree_[index]->idx_;
+                  }
+                else
+                  {
+                    for (int j = 0; j < numWidth; ++j)
+                      {
+                        std::cout << " ";
+                      }
+                  }
+                index++;
+                std::cout.flags(original_flags);
+                for (int j = 1; j < nodeNum; ++j)
+                  {
+                    for (int k = 0; k < interval; ++k)
+                      {
+                        for (int m = 0; m < (spaceWidth + numWidth); ++m)
+                          {
+                            std::cout << " ";
+                          }
+                      }
+                    for (int k = 0; k < spaceWidth; ++k)
+                      {
+                        std::cout << " ";
+                      }
+                    if (breadthFirstFullTree_[index] != 0)
+                      {
+                        std::cout << std::setw(numWidth)
+                                  << breadthFirstFullTree_[index]->idx_;
+                      }
+                    else
+                      {
+                        for (int j = 0; j < numWidth; ++j)
+                          {
+                            std::cout << " ";
+                          }
+                      }
+                    index++;
+                    std::cout.flags(original_flags);
+                  }
+                std::cout << std::endl;
+                interval = start;
+                start = (start - 1) / 2;
+              }
+          }
+      }
+  }
+
+  void Read(std::istream& is)
+  {
+    size_t nodeNum = 0;
+    std::vector<char> nodeTypes;
+    readBasicType(is, verbose_);
+    readBasicType(is, depth_);
+    readBasicType(is, suspectLeaves_);
+    readBasicType(is, nodeNum);
+
+    nodeTypes.resize(nodeNum);
+    for (index_t i = 0; i < nodeNum; ++i)
+      {
+        readBasicType(is, nodeTypes[i]);
+      }
+
+    size_t nodeNumBefore = nodes_.size();
+    if (nodeNumBefore != 0)
+      {
+        for (index_t i = 0; i < nodeNumBefore; ++i)
+          {
+            delete nodes_[i];
+          }
+      }
+    nodes_.resize(nodeNum);
+    for (index_t i = 0; i < nodeNum; ++i)
+      {
+        if (nodeTypes[i] == 'l')
+          {
+            nodes_[i] = (Node*) new LeafT();
+          }
+        else
+          {
+            if (verbose_ == true)
+              {
+                nodes_[i] = (Node*) new SplitFullT();
+              }
+            else
+              {
+                nodes_[i] = (Node*) new SplitT();
+              }
+          }
+        nodes_[i]->Read(is);
+      }
+    for (index_t i = 0; i < nodeNum; ++i)
+      {
+        if (nodeTypes[i] == 'l')
+          {
+            nodes_[i]->parent_ = nodes_[nodes_[i]->parentIdx_];
+          }
+        else
+          {
+            if (nodeTypes[i] == 'r')
+              {
+                nodes_[i]->parent_ = 0;
+              }
+            else
+              {
+                nodes_[i]->parent_ = nodes_[nodes_[i]->parentIdx_];
+              }
+            ((SplitNode*)nodes_[i])->leftChild_ =
+                nodes_[((SplitNode*)nodes_[i])->leftChildIdx_];
+            ((SplitNode*)nodes_[i])->rightChild_ =
+                nodes_[((SplitNode*)nodes_[i])->rightChildIdx_];
+          }
+      }
+  }
+
+  void Write(std::ostream& os)
+  {
+    size_t nodeNum = nodes_.size();
+    writeBasicType(os, verbose_);
+    writeBasicType(os, depth_);
+    writeBasicType(os, suspectLeaves_);
+    writeBasicType(os, nodeNum);
+    for (index_t i = 0; i < nodeNum; ++i)
+      {
+        writeBasicType(os, nodes_[i]->type_);
+      }
+    for (index_t i = 0; i < nodeNum; ++i)
+      {
+        nodes_[i]->Write(os);
+      }
+  }
+
+  std::vector<Node*> nodes_;  // stored as depth first way
+
+  // full binary tree stored as breadth first way, lacked nodes suppled with null pointer
+  std::vector<Node*> breadthFirstFullTree_;
+
+//  // stored as breath first way
+//  std::vector<Node*> nodesBreadthFirst_;
+
+  size_t depth_;
+  index_t idx_;
+
+  // store the number of leaf node with entropy higher
+  // than user defined leafEntropy, could be considered as tree quality criterion
+  size_t suspectLeaves_;
+
+  bool verbose_;
+};
+
+#endif // TREE_H
diff --git a/Logic/Preprocessing/RandomForest/Library/type.h b/Logic/Preprocessing/RandomForest/Library/type.h
new file mode 100755
index 0000000..26e16fb
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/type.h
@@ -0,0 +1,16 @@
+#ifndef TYPE_H
+#define TYPE_H
+
+#include "classification.h"
+
+typedef AxisAlignedClassifier<dataT, labelT> AxisClassifierT;
+typedef LinearClassifier<dataT, labelT> LinearClassifierT;
+typedef Histogram<dataT, labelT> HistStatisticsT;
+typedef DecisionForest<HistStatisticsT, AxisClassifierT, dataT> ClassificationForestAxisT;
+typedef DecisionForest<HistStatisticsT, LinearClassifierT, dataT> ClassificationForestLinearT;
+typedef Classification<dataT, AxisClassifierT> ClassificationAxisT;
+typedef Classification<dataT, LinearClassifierT> ClassificationLinearT;
+typedef Matrix<double> SoftPredictionT;
+typedef Vector<labelT> HardPredictionT;
+
+#endif // TYPE_H
diff --git a/Logic/Preprocessing/RandomForest/Library/utility.h b/Logic/Preprocessing/RandomForest/Library/utility.h
new file mode 100755
index 0000000..bf68171
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/Library/utility.h
@@ -0,0 +1,142 @@
+#ifndef UTILITY_H
+#define UTILITY_H
+
+#include <fstream>
+#include <sstream>
+#include <iterator>
+#include <algorithm>
+#include <time.h>
+// #include "omp.h"
+#include "data.h"
+
+template<class T>
+void readBasicType(std::istream& is, T& obj)
+{
+  is.read((char*)(&obj), sizeof(T));
+}
+
+template<class T>
+void writeBasicType(std::ostream& os, const T& obj)
+{
+  os.write((const char*)(&obj), sizeof(T));
+}
+
+// paul: bug, this needs to be inline
+inline int getLineNum(const std::string& name)
+{
+  std::ifstream inFile(name.c_str(), std::ios::in);
+  return std::count(std::istreambuf_iterator<char>(inFile),
+                    std::istreambuf_iterator<char>(), '\n');
+  inFile.close();
+}
+
+template<class dataT, class labelT>
+MLData<dataT, labelT>* readTextFile(const std::string& name)
+{
+  int dataNum = getLineNum(name);
+  int dataDim = 0;
+  bool first = true;
+  MLData<dataT, labelT>* data;
+  int tmpLabel = 0;
+  double tmpData = 0;
+  size_t cLineIdx = 0;
+  std::string line;
+  std::ifstream inFile(name.c_str(), std::ios::in);
+  if (inFile.is_open())
+    {
+      while ( getline(inFile, line) )
+        {
+          std::istringstream iss(line);
+          std::vector<std::string> tokens;
+          std::copy(std::istream_iterator<std::string>(iss),
+                    std::istream_iterator<std::string>(),
+                    std::back_inserter<std::vector<std::string> >(tokens));
+          if (first)
+            {
+              dataDim = tokens.size() - 1;
+              data = new MLData<dataT, labelT>(dataNum, dataDim);
+              first = false;
+            }
+          std::stringstream(tokens[0]) >> tmpLabel;
+          data->label[cLineIdx] = tmpLabel;
+          for (index_t i = 1; i < tokens.size(); ++i)
+            {
+              std::stringstream(tokens[i]) >> tmpData;
+              data->data[cLineIdx][i-1] = tmpData;
+            }
+          cLineIdx++;
+        }
+      inFile.close();
+    }
+  else
+    {
+      throw std::runtime_error("open file error");
+    }
+  return data;
+}
+
+class Timer
+{
+public:
+  void Reset(void)
+  {
+    start_ = 0;
+    finish_ = 0;
+  }
+
+  void Start(void)
+  {
+    start_ = clock();
+  }
+  void Stop(void)
+  {
+    finish_ = clock();
+  }
+  double SpendSecond(void)
+  {
+    return (double)(finish_-start_)/CLOCKS_PER_SEC;
+  }
+  double StopAndSpendSecond(void)
+  {
+    Stop();
+    return SpendSecond();
+  }
+
+private:
+  clock_t start_, finish_;
+};
+
+class MPTimer
+{
+public:
+  void Reset(void)
+  {
+    start_ = 0.0;
+    finish_ = 0.0;
+  }
+
+  void Start(void)
+  {
+    // start_ = omp_get_wtime();
+    start_ = clock();
+  }
+  void Stop(void)
+  {
+    // finish_ = omp_get_wtime();
+    finish_ = clock();
+  }
+  double SpendSecond(void)
+  {
+    return (finish_-start_) / CLOCKS_PER_SEC;
+  }
+  double StopAndSpendSecond(void)
+  {
+    Stop();
+    return SpendSecond();
+  }
+
+private:
+  double start_, finish_;
+};
+
+#endif // UTILITY_H
diff --git a/Logic/Preprocessing/RandomForest/RFClassificationEngine.cxx b/Logic/Preprocessing/RandomForest/RFClassificationEngine.cxx
new file mode 100644
index 0000000..4d4d116
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/RFClassificationEngine.cxx
@@ -0,0 +1,194 @@
+#include "RFClassificationEngine.h"
+#include "RandomForestClassifier.h"
+
+#include "SNAPImageData.h"
+#include "ImageWrapper.h"
+#include "ImageCollectionToImageFilter.h"
+#include "itkImageRegionIterator.h"
+
+// Includes from the random forest library
+typedef GreyType data_t;
+typedef LabelType label_t;
+
+#include "Library/classification.h"
+#include "Library/data.h"
+
+RFClassificationEngine::RFClassificationEngine()
+{
+  m_DataSource = NULL;
+  m_Sample = NULL;
+  m_Classifier = RandomForestClassifier::New();
+  m_ForestSize = 50;
+}
+
+RFClassificationEngine::~RFClassificationEngine()
+{
+  if(m_Sample)
+    delete m_Sample;
+}
+
+void RFClassificationEngine::SetDataSource(SNAPImageData *imageData)
+{
+  if(m_DataSource != imageData)
+    {
+    // Copy the data source
+    m_DataSource = imageData;
+
+    // Reset the classifier
+    m_Classifier->Reset();
+    }
+}
+
+void RFClassificationEngine::ResetClassifier()
+{
+  m_Classifier->Reset();
+}
+
+void RFClassificationEngine:: TrainClassifier()
+{
+  assert(m_DataSource && m_DataSource->IsMainLoaded());
+
+  // TODO: in the future, we should only recompute the sample when we know
+  // that the data has changed. However, currently, we are just going to
+  // compute a new sample every time
+
+  // Delete the sample
+  if(m_Sample)
+    delete m_Sample;
+
+  // Get the segmentation image - which determines the samples
+  LabelImageWrapper *wrpSeg = m_DataSource->GetSegmentation();
+  LabelImageWrapper::ImagePointer imgSeg = wrpSeg->GetImage();
+  typedef itk::ImageRegionConstIterator<LabelImageWrapper::ImageType> LabelIter;
+
+  // We need to iterate throught the label image once to determine the
+  // number of samples to allocate.
+  unsigned long nSamples = 0;
+  for(LabelIter lit(imgSeg, imgSeg->GetBufferedRegion()); !lit.IsAtEnd(); ++lit)
+    if(lit.Value())
+      nSamples++;
+
+  // Create an iterator for going over all the anatomical image data
+  typedef ImageCollectionConstRegionIteratorWithIndex<
+      AnatomicScalarImageWrapper::ImageType,
+      AnatomicImageWrapper::ImageType> CollectionIter;
+
+  CollectionIter cit(imgSeg->GetBufferedRegion());
+
+  // Add all the anatomical images to this iterator
+  for(LayerIterator it = m_DataSource->GetLayers(MAIN_ROLE | OVERLAY_ROLE);
+      !it.IsAtEnd(); ++it)
+    {
+    cit.AddImage(it.GetLayer()->GetImageBase());
+    }
+
+  // Get the number of components
+  int nComp = cit.GetTotalComponents();
+
+  // Create a new sample
+  m_Sample = new SampleType(nSamples, nComp);
+
+  // Now fill out the samples
+  int iSample = 0;
+  for(LabelIter lit(imgSeg, imgSeg->GetBufferedRegion()); !lit.IsAtEnd(); ++lit, ++cit)
+    {
+    LabelType label = lit.Value();
+    if(label)
+      {
+      // Fill in the data
+      std::vector<GreyType> &column = m_Sample->data[iSample];
+      for(int i = 0; i < nComp; i++)
+        column[i] = cit.Value(i);
+
+      // Fill in the label
+      m_Sample->label[iSample] = label;
+
+      ++iSample;
+      }
+    }
+
+  // Check that the sample has at least two distinct labels
+  bool isValidSample = false;
+  for(int iSample = 1; iSample < m_Sample->Size(); iSample++)
+    if(m_Sample->label[iSample] != m_Sample->label[iSample-1])
+      { isValidSample = true; break; }
+
+  // Now there is a valid sample. The text task is to train the classifier
+  if(!isValidSample)
+    throw IRISException("A classifier cannot be trained because the training "
+                        "data contain fewer than two classes. Please label "
+                        "examples of two or more tissue classes in the image.");
+
+  // Set up the classifier parameters
+  TrainingParameters params;
+  params.treeDepth = 10;
+  params.treeNum = m_ForestSize;
+  params.candidateNodeClassifierNum = 10;
+  params.candidateClassifierThresholdNum = 10;
+  params.subSamplePercent = 0;
+  params.splitIG = 0.1;
+  params.leafEntropy = 0.05;
+  params.verbose = true;
+
+  // Create the classification engine
+  typedef RandomForestClassifier::RFAxisClassifierType RFAxisClassifierType;
+  typedef Classification<GreyType, LabelType, RFAxisClassifierType> ClassificationType;
+  ClassificationType classification;
+
+  // Before resetting the classifier, we want to retain whatever the
+  // foreground label was.
+  bool isOldForegroundLabelValid = m_Classifier->IsValidClassifier();
+  LabelType oldForegroundLabel = 0;
+
+  if(isOldForegroundLabelValid)
+    oldForegroundLabel = m_Classifier->GetForegroundClassLabel();
+
+  // Prepare the classifier
+  m_Classifier->Reset();
+
+  // Perform classifier training
+  classification.Learning(
+        params, *m_Sample,
+        *m_Classifier->m_Forest,
+        m_Classifier->m_ValidLabel,
+        m_Classifier->m_ClassToLabelMapping);
+
+  // Assign the foreground index to zero (default)
+  m_Classifier->m_ForegroundClass = 0;
+
+  // Now maybe re-assign the old foreground label
+  if(isOldForegroundLabelValid)
+    {
+    for(RandomForestClassifier::MappingType::const_iterator it =
+        m_Classifier->m_ClassToLabelMapping.begin();
+        it != m_Classifier->m_ClassToLabelMapping.end(); ++it)
+      {
+      if(it->second == oldForegroundLabel)
+        m_Classifier->m_ForegroundClass = it->first;
+      }
+    }
+}
+
+void RFClassificationEngine::SetClassifier(RandomForestClassifier *rf)
+{
+  // Set the classifier
+  m_Classifier = rf;
+
+  // Update the forest size
+  m_ForestSize = m_Classifier->GetForest()->GetForestSize();
+}
+
+int RFClassificationEngine::GetNumberOfComponents() const
+{
+  assert(m_DataSource);
+
+  int ncomp = 0;
+
+  for(LayerIterator it = m_DataSource->GetLayers(MAIN_ROLE | OVERLAY_ROLE);
+      !it.IsAtEnd(); ++it)
+    ncomp += it.GetLayer()->GetNumberOfComponents();
+
+  return ncomp;
+}
+
+
diff --git a/Logic/Preprocessing/RandomForest/RFClassificationEngine.h b/Logic/Preprocessing/RandomForest/RFClassificationEngine.h
new file mode 100644
index 0000000..2ad5f4c
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/RFClassificationEngine.h
@@ -0,0 +1,70 @@
+#ifndef RFCLASSIFICATIONENGINE_H
+#define RFCLASSIFICATIONENGINE_H
+
+#include <itkObject.h>
+#include <itkObjectFactory.h>
+#include "SNAPCommon.h"
+#include "PropertyModel.h"
+
+class SNAPImageData;
+class RandomForestClassifier;
+
+template <class TData, class TLabel> class MLData;
+
+/**
+ * This class serves as the high-level interface between ITK-SNAP and the
+ * random forest code.
+ */
+class RFClassificationEngine : public itk::Object
+{
+public:
+
+  // Standard ITK class stuff
+  irisITKObjectMacro(RFClassificationEngine, itk::Object)
+
+  /** Set the data source for the classification */
+  void SetDataSource(SNAPImageData *imageData);
+
+  /** Reset the classifier */
+  void ResetClassifier();
+
+  /** Train the classifier */
+  void TrainClassifier();
+
+  /** Set the classifier */
+  void SetClassifier(RandomForestClassifier *rf);
+
+  /** Access the trained classifier */
+  irisGetMacro(Classifier, RandomForestClassifier *)
+
+  /** Size of the random forest (main parameter) */
+  irisGetSetMacro(ForestSize, int)
+
+  /** Get the number of components passed to the classifier */
+  int GetNumberOfComponents() const;
+
+
+protected:
+
+  RFClassificationEngine();
+  virtual ~RFClassificationEngine();
+
+  // The trained classifier
+  SmartPtr<RandomForestClassifier> m_Classifier;
+
+  // The data source
+  SNAPImageData *m_DataSource;
+
+  // The foreground label
+  LabelType m_ForegroundLabel;
+
+  // Number of trees
+  int m_ForestSize;
+
+  // Cached samples used to train the classifier
+  typedef MLData<GreyType, LabelType> SampleType;
+  SampleType *m_Sample;
+
+};
+
+#endif // RFCLASSIFICATIONENGINE_H
diff --git a/Logic/Preprocessing/RandomForest/RandomForestClassifier.cxx b/Logic/Preprocessing/RandomForest/RandomForestClassifier.cxx
new file mode 100644
index 0000000..38cb7ee
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/RandomForestClassifier.cxx
@@ -0,0 +1,51 @@
+#include "RandomForestClassifier.h"
+#include "Library/classification.h"
+
+void RandomForestClassifier::Reset()
+{
+  if(m_Forest)
+    delete m_Forest;
+
+  m_Forest = new RandomForestType(true);
+  m_ClassToLabelMapping.clear();
+  m_ForegroundClass = 0;
+}
+
+LabelType RandomForestClassifier::GetForegroundClassLabel() const
+{
+  MappingType::const_iterator it = m_ClassToLabelMapping.find(m_ForegroundClass);
+  if(it != m_ClassToLabelMapping.end())
+    return it->second;
+
+  // Default behavior - clear label
+  return 0;
+}
+
+void RandomForestClassifier::SetForegroundClassLabel(LabelType label)
+{
+  MappingType::const_iterator it = m_ClassToLabelMapping.begin();
+  for(; it != m_ClassToLabelMapping.end(); ++it)
+    {
+    if(it->second == label)
+      {
+      m_ForegroundClass = it->first;
+      return;
+      }
+    }
+}
+
+bool RandomForestClassifier::IsValidClassifier() const
+{
+  return m_ClassToLabelMapping.size() >= 2;
+}
+
+RandomForestClassifier::RandomForestClassifier()
+{
+  m_Forest = new RandomForestType(true);
+}
+
+RandomForestClassifier::~RandomForestClassifier()
+{
+  if(m_Forest)
+    delete m_Forest;
+}
diff --git a/Logic/Preprocessing/RandomForest/RandomForestClassifier.h b/Logic/Preprocessing/RandomForest/RandomForestClassifier.h
new file mode 100644
index 0000000..78ea4b1
--- /dev/null
+++ b/Logic/Preprocessing/RandomForest/RandomForestClassifier.h
@@ -0,0 +1,75 @@
+#ifndef RANDOMFORESTCLASSIFIER_H
+#define RANDOMFORESTCLASSIFIER_H
+
+#include <itkDataObject.h>
+#include <itkObjectFactory.h>
+#include <SNAPCommon.h>
+#include <map>
+
+template <class dataT, class labelT> class Histogram;
+template <class dataT, class labelT> class AxisAlignedClassifier;
+template <class HistT, class ClassT, class dataT> class DecisionForest;
+
+/**
+ * This class encapsulates a Random Forest classifier
+ */
+class RandomForestClassifier : public itk::DataObject
+{
+public:
+
+  // Standard ITK stuff
+  irisITKObjectMacro(RandomForestClassifier, itk::DataObject)
+
+  // typedefs
+  typedef Histogram<GreyType, LabelType> RFHistogramType;
+  typedef AxisAlignedClassifier<GreyType, LabelType> RFAxisClassifierType;
+  typedef DecisionForest<RFHistogramType, RFAxisClassifierType, GreyType> RandomForestType;
+  typedef std::map<size_t, LabelType> MappingType;
+
+  // Reset the classifier
+  void Reset();
+
+  // Get the mapping from the class indices to labels
+  irisGetMacro(ClassToLabelMapping, const MappingType &)
+
+  // Get the random forest
+  irisGetMacro(Forest, RandomForestType *)
+
+  // Get the foreground class
+  irisGetMacro(ForegroundClass, size_t)
+
+  // Get the label of the foreground class
+  LabelType GetForegroundClassLabel() const;
+
+  // Set the foreground class by label
+  void SetForegroundClassLabel(LabelType label);
+
+  // Test if the classifier is valid (has 2+ classes)
+  bool IsValidClassifier() const;
+
+protected:
+
+  RandomForestClassifier();
+  ~RandomForestClassifier();
+
+  // The actual decision forest
+  RandomForestType *m_Forest;
+
+  // Whether the labels are valid (?)
+  bool m_ValidLabel;
+
+  // Mapping of index to label (?)
+  MappingType m_ClassToLabelMapping;
+
+  // The class that is currently active
+  size_t m_ForegroundClass;
+
+  // Let the engine handle our data
+  friend class RFClassificationEngine;
+
+  // TODO: make all that protected!
+
+
+};
+
+#endif // RANDOMFORESTCLASSIFIER_H
diff --git a/Logic/Preprocessing/RandomForestClassifyImageFilter.h b/Logic/Preprocessing/RandomForestClassifyImageFilter.h
new file mode 100644
index 0000000..fc7fb24
--- /dev/null
+++ b/Logic/Preprocessing/RandomForestClassifyImageFilter.h
@@ -0,0 +1,83 @@
+#ifndef RANDOMFORESTCLASSIFYIMAGEFILTER_H
+#define RANDOMFORESTCLASSIFYIMAGEFILTER_H
+
+#include "itkImageToImageFilter.h"
+
+class RandomForestClassifier;
+
+/**
+ * @brief A class that takes multiple multi-component images and uses a
+ * Gaussian mixture model to combine them into a single probability map.
+ *
+ * // TODO: derive this and the GMM filter from a common base class that
+ * // simplifies working with multiple vector/scalar images
+ */
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+class RandomForestClassifyImageFilter :
+    public itk::ImageToImageFilter<TInputImage, TOutputImage>
+{
+public:
+
+  /** Pixel Type of the input image */
+  typedef TInputImage                                    InputImageType;
+  typedef typename InputImageType::PixelType             InputPixelType;
+  typedef typename InputImageType::InternalPixelType InputComponentType;
+  typedef typename InputImageType::RegionType      InputImageRegionType;
+
+  /** Define the corresponding vector image */
+  typedef TInputVectorImage                        InputVectorImageType;
+
+  /** Pixel Type of the output image */
+  typedef TOutputImage                                  OutputImageType;
+  typedef typename OutputImageType::PixelType           OutputPixelType;
+  typedef typename OutputImageType::RegionType    OutputImageRegionType;
+  typedef typename OutputImageType::Pointer          OutputImagePointer;
+
+  /** Standard class typedefs. */
+  typedef RandomForestClassifyImageFilter                          Self;
+  typedef itk::ImageSource<OutputImageType>                  Superclass;
+  typedef itk::SmartPointer<Self>                               Pointer;
+  typedef itk::SmartPointer<const Self>                    ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self)
+
+  /** Image dimension. */
+  itkStaticConstMacro(ImageDimension, unsigned int,
+                      TInputImage::ImageDimension);
+
+  /** Add a scalar input image */
+  void AddScalarImage(InputImageType *image);
+
+  /** Add a vector (multi-component) input image */
+  void AddVectorImage(InputVectorImageType *image);
+
+  /** Set the mixture model */
+  void SetClassifier(RandomForestClassifier *classifier);
+
+  /** Get the current classifier */
+  irisGetMacro(Classifier, RandomForestClassifier *);
+
+  /** We need to override this method because of multiple input types */
+  void GenerateInputRequestedRegion();
+
+protected:
+
+  RandomForestClassifyImageFilter();
+  virtual ~RandomForestClassifyImageFilter();
+
+  void PrintSelf(std::ostream& os, itk::Indent indent) const;
+
+  void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread,
+                            itk::ThreadIdType threadId);
+
+  RandomForestClassifier *m_Classifier;
+};
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "RandomForestClassifyImageFilter.txx"
+#endif
+
+
+
+#endif // RANDOMFORESTCLASSIFYIMAGEFILTER_H
diff --git a/Logic/Preprocessing/RandomForestClassifyImageFilter.txx b/Logic/Preprocessing/RandomForestClassifyImageFilter.txx
new file mode 100644
index 0000000..8a963ed
--- /dev/null
+++ b/Logic/Preprocessing/RandomForestClassifyImageFilter.txx
@@ -0,0 +1,172 @@
+#ifndef RANDOMFORESTCLASSIFYIMAGEFILTER_TXX
+#define RANDOMFORESTCLASSIFYIMAGEFILTER_TXX
+
+#include "RandomForestClassifyImageFilter.h"
+#include "itkImageRegionConstIterator.h"
+#include "RandomForestClassifier.h"
+#include "ImageCollectionToImageFilter.h"
+#include <itkProgressReporter.h>
+
+#include "Library/data.h"
+#include "Library/forest.h"
+#include "Library/statistics.h"
+#include "Library/classifier.h"
+
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+RandomForestClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::RandomForestClassifyImageFilter()
+{
+  // m_MixtureModel = NULL;
+}
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+RandomForestClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::~RandomForestClassifyImageFilter()
+{
+}
+
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+RandomForestClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::AddScalarImage(InputImageType *image)
+{
+  this->AddInput(image);
+}
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+RandomForestClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::AddVectorImage(InputVectorImageType *image)
+{
+  this->AddInput(image);
+}
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+RandomForestClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::SetClassifier(RandomForestClassifier *classifier)
+{
+  m_Classifier = classifier;
+  this->Modified();
+}
+
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+RandomForestClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::GenerateInputRequestedRegion()
+{
+  itk::ImageSource<TOutputImage>::GenerateInputRequestedRegion();
+
+  for( itk::InputDataObjectIterator it( this ); !it.IsAtEnd(); it++ )
+    {
+    // Check whether the input is an image of the appropriate dimension
+    InputImageType *input = dynamic_cast< InputImageType * >( it.GetInput() );
+    InputVectorImageType *vecInput = dynamic_cast< InputVectorImageType * >( it.GetInput() );
+    if (input)
+      {
+      InputImageRegionType inputRegion;
+      this->CallCopyOutputRegionToInputRegion( inputRegion, this->GetOutput()->GetRequestedRegion() );
+      input->SetRequestedRegion(inputRegion);
+      }
+    else if(vecInput)
+      {
+      InputImageRegionType inputRegion;
+      this->CallCopyOutputRegionToInputRegion( inputRegion, this->GetOutput()->GetRequestedRegion() );
+      vecInput->SetRequestedRegion(inputRegion);
+      }
+    }
+}
+
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+RandomForestClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::PrintSelf(std::ostream &os, itk::Indent indent) const
+{
+  os << indent << "RandomForestClassifyImageFilter" << std::endl;
+}
+
+template <class TInputImage, class TInputVectorImage, class TOutputImage>
+void
+RandomForestClassifyImageFilter<TInputImage, TInputVectorImage, TOutputImage>
+::ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread,
+                       itk::ThreadIdType threadId)
+{
+  assert(m_Classifier);
+
+  // Create an iterator for the output
+  OutputImagePointer outputPtr = this->GetOutput(0);
+  typedef itk::ImageRegionIterator<TOutputImage> OutputIter;
+  OutputIter it_out(outputPtr, outputRegionForThread);
+
+  // Create a collection iterator for the inputs
+  typedef ImageCollectionConstRegionIteratorWithIndex<
+      TInputImage, TInputVectorImage> CollectionIter;
+
+  // Configure the input collection iterator
+  CollectionIter cit(outputRegionForThread);
+  for( itk::InputDataObjectIterator it( this ); !it.IsAtEnd(); it++ )
+    cit.AddImage(it.GetInput());
+
+  // Get the number of components
+  int nComp = cit.GetTotalComponents();
+
+  // Get the number of classes
+  int nClass = m_Classifier->GetClassToLabelMapping().size();
+
+  // Get the current class
+  int activeClass = (int) m_Classifier->GetForegroundClass();
+
+  // Create the MLdata representing each voxel (?)
+  typedef Histogram<InputPixelType,LabelType> HistogramType;
+  typedef MLData<InputPixelType,HistogramType *> TestingDataType;
+  TestingDataType testData(1, nComp);
+
+  // Get the number of trees
+  int nTrees = m_Classifier->GetForest()->trees_.size();
+
+  // Create and allocate the test result vector
+  typedef Vector<Vector<HistogramType *> > TestingResultType;
+  TestingResultType testResult;
+  testResult.Resize(nTrees);
+  for(int i = 0; i < nTrees; i++)
+    testResult[i].Resize(1);
+
+  // Some vectors that are allocated for speed
+  std::vector<size_t> vIndex(1);
+  std::vector<bool> vResult(1);
+
+  // Iterate through all the voxels
+  for(; !it_out.IsAtEnd(); ++it_out, ++cit)
+    {
+    // Assign the data to the testData vector
+    for(int i = 0; i < nComp; i++)
+      testData.data[0][i] = cit.Value(i);
+
+    // Perform classification on this data
+    m_Classifier->GetForest()->ApplyFast(testData, testResult, vIndex, vResult);
+
+    // Add up the predictions made by each tree for each class
+    double p = 0;
+    for(int i = 0; i < testResult.Size(); i++)
+      {
+      for(int j = 0; j < nClass; j++)
+        {
+        if(j == activeClass)
+          p += testResult[i][0]->prob_[j];
+        else
+          p -= testResult[i][0]->prob_[j];
+        }
+      }
+    p /= testResult.Size();
+
+    // Presumably, at this point p stores the (p_fore - p_back) value
+    it_out.Set((OutputPixelType)(p * 0x7fff));
+    }
+}
+
+
+#endif
diff --git a/Logic/Preprocessing/SlicePreviewFilterWrapper.h b/Logic/Preprocessing/SlicePreviewFilterWrapper.h
new file mode 100644
index 0000000..0b6acf3
--- /dev/null
+++ b/Logic/Preprocessing/SlicePreviewFilterWrapper.h
@@ -0,0 +1,188 @@
+#ifndef SLICEPREVIEWFILTERWRAPPER_H
+#define SLICEPREVIEWFILTERWRAPPER_H
+
+#include "SNAPCommon.h"
+#include "itkDataObject.h"
+#include "itkObjectFactory.h"
+
+class ImageWrapperBase;
+class ScalarImageWrapperBase;
+template <class TInputImage, class TOutputImage> class IRISSlicer;
+
+namespace itk {
+  template<class TIn, class TOut> class StreamingImageFilter;
+}
+
+class SNAPImageData;
+
+/**
+  Abstract parent class for SlicePreviewFilterWrapper. Allows us to call
+  some methods in the SlicePreviewFilterWrapper without knowing what traits
+  it has been templated over.
+  */
+class AbstractSlicePreviewFilterWrapper : public itk::DataObject
+{
+public:
+  typedef AbstractSlicePreviewFilterWrapper                            Self;
+  typedef itk::DataObject                                        Superclass;
+  typedef SmartPtr<Self>                                            Pointer;
+  typedef SmartPtr<const Self>                                 ConstPointer;
+
+  itkTypeMacro(AbstractSlicePreviewFilterWrapper, itk::DataObject)
+
+  /** Is the preview mode on? */
+  virtual bool IsPreviewMode() const = 0;
+
+  /** Enter preview mode */
+  virtual void SetPreviewMode(bool mode) = 0;
+
+  /** Compute the output volume (corresponds to the 'Apply' operation) */
+  virtual void ComputeOutputVolume(itk::Command *progress) = 0;
+
+  /** Select the active scalar layer (for filters that operate on only one) */
+  virtual void SetActiveScalarLayer(ScalarImageWrapperBase *layer) = 0;
+
+  /** Get the active scalar layer (for filters that operate on only one). */
+  virtual ScalarImageWrapperBase *GetActiveScalarLayer() const = 0;
+
+protected:
+
+  AbstractSlicePreviewFilterWrapper() {}
+  virtual ~AbstractSlicePreviewFilterWrapper() {}
+
+};
+
+/**
+  This class provides support for on-the-fly preview of speed images in
+  SNAP. It is designed to be very generic to allow use with complex
+  preprocessing pipelines that have multiple inputs. To make the object
+  so generic, we parameterize it by a traits object:
+
+    TFilterConfigTraits
+
+  The traits object must define the following types
+
+    FilterType         The filter that encapsulates the preprocessing pipeline
+
+    ParameterType      The parameters passed to the filter
+
+    OutputWrapperType  The type of wrapper these filters connect to
+
+  The traits object must also define the following functions
+
+    static void AttachInputs(SNAPImageData *sid, FilterType *filter)
+
+        This function should set the input image(s) for the filter given
+        a pointer to a SNAPImageData object.
+
+    static void DetachInputs(FilterType *filter)
+
+        This detaches all inputs from the filter.
+
+    static void SetParameters(ParameterType *p, FilterType *filter)
+
+        This sets the parameters of the filter
+
+
+  What does this filter do? It creates an assembly consisting
+  of three slice preview filters, and one whole-volume filter. The four
+  filters share the same output buffer, but have different buffered
+  regions.
+
+  The behavior is as follows. When the preview mode is turned on, a request
+  for a display slice will invoke one of the preview filters to apply its
+  preprocessing operation to generate just the region of the speed image
+  needed for display. When the preview mode is off, a request for a display
+  slice uses the data currently stored in the speed image buffer (possibly
+  uninitialized).
+
+  The user can also ask this wrapper to apply the filter to generate the
+  entire speed image volume. This can be done in or out of preview mode.
+
+  The filter is smart enough to know when the whole volume is up to date. If
+  the parameters of the preview filters have not been changed since the last
+  time the whole speed volume was generated, the preview filters are deemed
+  to be up to date, and no preprocessing operations take place.
+  */
+template<class TFilterConfigTraits>
+class SlicePreviewFilterWrapper : public AbstractSlicePreviewFilterWrapper
+{
+public:
+
+  typedef SlicePreviewFilterWrapper<TFilterConfigTraits>               Self;
+  typedef AbstractSlicePreviewFilterWrapper                      Superclass;
+  typedef SmartPtr<Self>                                            Pointer;
+  typedef SmartPtr<const Self>                                 ConstPointer;
+
+  itkTypeMacro(SlicePreviewFilterWrapper, AbstractSlicePreviewFilterWrapper)
+
+  itkNewMacro(Self)
+
+  typedef TFilterConfigTraits                                        Traits;
+
+  typedef typename TFilterConfigTraits::FilterType               FilterType;
+  typedef typename FilterType::OutputImageType              OutputImageType;
+  typedef typename OutputImageType::PixelType               OutputPixelType;
+
+  typedef typename TFilterConfigTraits::OutputWrapperType OutputWrapperType;
+  typedef IRISSlicer<OutputImageType, itk::Image<OutputPixelType, 2> >
+                                                                 SlicerType;
+
+  typedef typename TFilterConfigTraits::ParameterType         ParameterType;
+
+  /** Is the preview mode on? */
+  irisIsMacro(PreviewMode)
+
+  /** Enter preview mode */
+  void SetPreviewMode(bool mode);
+
+  /** Set the input image, etc */
+  void AttachInputs(SNAPImageData *sid);
+
+  /** Set the output volume */
+  void AttachOutputWrapper(OutputWrapperType *wrapper);
+
+  /** Select the active scalar layer (for filters that operate on only one) */
+  void SetActiveScalarLayer(ScalarImageWrapperBase *layer);
+
+  /** Get the active scalar layer (for filters that operate on only one). */
+  irisGetMacro(ActiveScalarLayer, ScalarImageWrapperBase *)
+
+  /** Set the parameters */
+  void SetParameters(ParameterType *param);
+
+  /** Detach from a wrapper */
+  void DetachInputsAndOutputs();
+
+  /** Compute the output volume (corresponds to the 'Apply' operation) */
+  void ComputeOutputVolume(itk::Command *progress);
+
+protected:
+
+  SlicePreviewFilterWrapper();
+  ~SlicePreviewFilterWrapper() {}
+
+  void UpdatePipeline();
+
+  OutputWrapperType *m_OutputWrapper;
+
+  // Streamer - to allow reduced memory footprint
+  typedef itk::StreamingImageFilter<OutputImageType, OutputImageType> Streamer;
+
+  SmartPtr<FilterType> m_PreviewFilter[3];
+  SmartPtr<FilterType> m_VolumeFilter;
+  SmartPtr<Streamer> m_VolumeStreamer;
+
+  // So we can loop over all four filters
+  FilterType *GetNthFilter(int);
+
+  // Active scalar layer (for layers that support this functionality)
+  ScalarImageWrapperBase *m_ActiveScalarLayer;
+
+  bool m_PreviewMode;
+
+  void UpdateOutputPipelineReadyStatus();
+};
+
+
+#endif // SLICEPREVIEWFILTERWRAPPER_H
diff --git a/Logic/Preprocessing/SlicePreviewFilterWrapper.txx b/Logic/Preprocessing/SlicePreviewFilterWrapper.txx
new file mode 100644
index 0000000..dfa8778
--- /dev/null
+++ b/Logic/Preprocessing/SlicePreviewFilterWrapper.txx
@@ -0,0 +1,203 @@
+#include "SlicePreviewFilterWrapper.h"
+
+#include "SmoothBinaryThresholdImageFilter.h"
+#include "EdgePreprocessingImageFilter.h"
+#include "itkStreamingImageFilter.h"
+#include <IRISSlicer.h>
+#include <ColorMap.h>
+#include <itkTimeProbe.h>
+
+
+template <class TFilterConfigTraits>
+SlicePreviewFilterWrapper<TFilterConfigTraits>
+::SlicePreviewFilterWrapper()
+{
+  m_PreviewMode = TFilterConfigTraits::GetDefaultPreviewMode();
+
+  // Allocate the volume filter and the preview filters
+  m_VolumeFilter = FilterType::New();
+  m_VolumeFilter->ReleaseDataFlagOn();
+
+  for(int i = 0; i < 3; i++)
+    m_PreviewFilter[i] = FilterType::New();
+
+  // Allocate the streamer and attach to the volume filter
+  m_VolumeStreamer = Streamer::New();
+  m_VolumeStreamer->SetInput(m_VolumeFilter->GetOutput());
+
+  // Set up a streaming filter to reduce the memory footprint during execution
+  m_VolumeStreamer->SetNumberOfStreamDivisions(9);
+
+  // No active layer by default
+  m_ActiveScalarLayer = NULL;
+
+  // Set the output wrapper to NULL
+  m_OutputWrapper = NULL;
+}
+
+template <class TFilterConfigTraits>
+void
+SlicePreviewFilterWrapper<TFilterConfigTraits>
+::SetParameters(ParameterType *param)
+{
+  // Set the parameters of all the filters
+  for(int i = 0; i < 4; i++)
+    Traits::SetParameters(param, this->GetNthFilter(i), i);
+
+  // After updates to the parameters/filters update the pipeline readiness
+  // status in the output wrapper
+  this->UpdateOutputPipelineReadyStatus();
+}
+
+template <class TFilterConfigTraits>
+void
+SlicePreviewFilterWrapper<TFilterConfigTraits>
+::UpdateOutputPipelineReadyStatus()
+{
+  FilterType *array[] = {m_PreviewFilter[0], m_PreviewFilter[1], m_PreviewFilter[2]};
+  if(m_OutputWrapper)
+    m_OutputWrapper->SetPipelineReady(Traits::IsPreviewable(array));
+}
+
+
+template <class TFilterConfigTraits>
+void
+SlicePreviewFilterWrapper<TFilterConfigTraits>
+::AttachInputs(SNAPImageData *sid)
+{
+  // Get the default scalar layer for the traits. If this is NULL, the method
+  // does not expect an active layer to be specified (acts on all inputs)
+  m_ActiveScalarLayer = Traits::GetDefaultScalarLayer(sid);
+  for(int i = 0; i < 4; i++)
+    {
+    Traits::AttachInputs(sid, this->GetNthFilter(i), i);
+    if(m_ActiveScalarLayer)
+      Traits::SetActiveScalarLayer(m_ActiveScalarLayer, this->GetNthFilter(i), i);
+    }
+}
+
+template <class TFilterConfigTraits>
+void
+SlicePreviewFilterWrapper<TFilterConfigTraits>
+::SetPreviewMode(bool mode)
+{
+  if(m_PreviewMode != mode)
+    {
+    m_PreviewMode = mode;
+    this->Modified();
+    this->UpdatePipeline();
+    }
+}
+
+template <class TFilterConfigTraits>
+void
+SlicePreviewFilterWrapper<TFilterConfigTraits>
+::AttachOutputWrapper(OutputWrapperType *wrapper)
+{
+  // The slice preview filters need to be attached to the slicer
+  m_OutputWrapper = wrapper;
+  this->UpdatePipeline();
+}
+
+template <class TFilterConfigTraits>
+void
+SlicePreviewFilterWrapper<TFilterConfigTraits>
+::DetachInputsAndOutputs()
+{
+  if(m_OutputWrapper)
+    {
+    for(unsigned int i = 0; i < 3; i++)
+      {
+      // Disconnect wrapper from this pipeline
+      m_OutputWrapper->GetSlicer(i)->SetPreviewInput(NULL);
+      }
+
+    // Undo the graft
+    m_VolumeStreamer->GraftOutput(m_VolumeStreamer->GetOutput());
+    }
+
+  m_OutputWrapper = NULL;
+
+  for(unsigned int i = 0; i < 4; i++)
+    {
+    // Disconnect wrapper from this pipeline
+    Traits::DetachInputs(this->GetNthFilter(i));
+    }
+
+  m_ActiveScalarLayer = NULL;
+}
+
+template <class TFilterConfigTraits>
+void
+SlicePreviewFilterWrapper<TFilterConfigTraits>
+::UpdatePipeline()
+{
+    if(m_OutputWrapper)
+    {
+    if(m_PreviewMode)
+      {
+      // Attach the pipeline filters
+      m_OutputWrapper->AttachPreviewPipeline(
+            m_PreviewFilter[0], m_PreviewFilter[1], m_PreviewFilter[2]);
+
+      this->UpdateOutputPipelineReadyStatus();
+      }
+    else
+      {
+      m_OutputWrapper->DetachPreviewPipeline();
+      }
+    }
+}
+
+template <class TFilterConfigTraits>
+void
+SlicePreviewFilterWrapper<TFilterConfigTraits>
+::ComputeOutputVolume(itk::Command *progress)
+{
+  // Attach the progress monitor
+  unsigned long tag = 0;
+
+  if(progress)
+    tag = m_VolumeStreamer->AddObserver(itk::ProgressEvent(), progress);
+
+  // Temporarily graft the target volume as output of the filter
+  m_VolumeStreamer->GraftOutput(m_OutputWrapper->GetImage());
+
+  // Execute the preprocessing on the whole image extent
+  // itk::TimeProbe probe;
+  // probe.Start();
+  m_VolumeStreamer->UpdateLargestPossibleRegion();
+  // probe.Stop();
+  // std::cout << "Time Elapsed: " << probe.GetTotal() << std::endl;
+
+  // Remove the progress monitor
+  if(progress)
+    m_VolumeStreamer->RemoveObserver(tag);
+
+  // Undo the graft
+  m_VolumeStreamer->GraftOutput(m_VolumeStreamer->GetOutput());
+
+  // Update the m-time of the output image
+  m_OutputWrapper->GetImage()->Modified();
+  m_OutputWrapper->GetImage()->DisconnectPipeline();
+}
+
+template <class TFilterConfigTraits>
+typename SlicePreviewFilterWrapper<TFilterConfigTraits>::FilterType *
+SlicePreviewFilterWrapper<TFilterConfigTraits>
+::GetNthFilter(int index)
+{
+  return (index > 0) ? m_PreviewFilter[index-1] : m_VolumeFilter;
+}
+
+
+template <class TFilterConfigTraits>
+void
+SlicePreviewFilterWrapper<TFilterConfigTraits>
+::SetActiveScalarLayer(ScalarImageWrapperBase *layer)
+{
+  m_ActiveScalarLayer = layer;
+  for(int i = 0; i < 4; i++)
+    Traits::SetActiveScalarLayer(m_ActiveScalarLayer, this->GetNthFilter(i), i);
+  this->Modified();
+}
diff --git a/Logic/Preprocessing/SmoothBinaryThresholdImageFilter.h b/Logic/Preprocessing/SmoothBinaryThresholdImageFilter.h
index 73f182c..38e823a 100644
--- a/Logic/Preprocessing/SmoothBinaryThresholdImageFilter.h
+++ b/Logic/Preprocessing/SmoothBinaryThresholdImageFilter.h
@@ -35,91 +35,28 @@
 #ifndef __SmoothBinaryThresholdImageFilter_h_
 #define __SmoothBinaryThresholdImageFilter_h_
 
-#include "itkCommand.h"
 #include "itkUnaryFunctorImageFilter.h"
-#include "itkMinimumMaximumImageCalculator.h"
-#include "itkProgressAccumulator.h"
 #include "ThresholdSettings.h"
 
 /**
  * A functor used for the smooth threshold operation on images.  
  * Used in conjuction with itk::UnaryFunctorImageFilter.
  */
-template<class TInput, class TOutput>
+template<class TInput>
 class SmoothBinaryThresholdFunctor 
 {
 public:
-  typedef SmoothBinaryThresholdFunctor<TInput, TOutput> Self;
-
-  /**
-   * Initialize the function
-   */
-  void SetParameters(TInput,TInput,
-                     const ThresholdSettings &settings)
-  {
-    // At least one threshold should be used
-    assert(settings.IsLowerThresholdEnabled() || 
-           settings.IsUpperThresholdEnabled());
-
-    // Store the upper and lower bounds
-    m_LowerThreshold = settings.GetLowerThreshold();
-    m_UpperThreshold = settings.GetUpperThreshold();
-
-    // Handle the bad case: everything is mapped to zero
-    if(m_LowerThreshold >= m_UpperThreshold)
-      {
-      m_ScalingFactor = m_FactorUpper = m_FactorLower = m_Shift = 0.0;
-      return;
-      }
-
-    // Compute the largest scaling for U-L such that the function is greater
-    // than 1-eps
-    float eps = pow((float)10,-(float)settings.GetSmoothness());
-    float maxScaling = (m_UpperThreshold - m_LowerThreshold) / log((2-eps)/eps);
-
-    // Set the factor by which the input is multiplied
-    // m_ScalingFactor = settings.GetSmoothness(); 
-    m_ScalingFactor = 1 / maxScaling; 
-
-    // Combine the usage and inversion flags to get the scaling factors    
-    m_FactorLower = settings.IsLowerThresholdEnabled() ? 1.0f : 0.0f;
-    m_FactorUpper = settings.IsUpperThresholdEnabled() ? 1.0f : 0.0f;
-
-    // Compute the shift
-    m_Shift = 1.0f - (m_FactorLower + m_FactorUpper);
-  }
-
-  /**
-   * Apply the function to image intensity
-   */
-  TOutput operator()(const TInput &x)
-  {
-    // Cast the input to float
-    float z = static_cast<float>(x);
-    
-    // Compute the left component
-    float yLower = m_FactorLower * tanh((z-m_LowerThreshold) * m_ScalingFactor);
-
-    // Compute the right component
-    float yUpper = m_FactorUpper * tanh((m_UpperThreshold-z) * m_ScalingFactor);
-
-    // Return the result (TODO: hack)
-    return static_cast<TOutput>(yLower + yUpper + m_Shift);
-  }
-
-  bool operator ==(const Self &z)
-    {
-    return 
-      m_LowerThreshold == z.m_LowerThreshold &&
-      m_UpperThreshold == z.m_UpperThreshold &&
-      m_ScalingFactor == z.m_ScalingFactor &&
-      m_FactorLower == z.m_FactorLower &&
-      m_FactorUpper == z.m_FactorUpper &&
-      m_Shift == z.m_Shift;
-    }
-
-  bool operator !=(const Self &x)
-    { return !((*this) == x); }
+  typedef SmoothBinaryThresholdFunctor<TInput> Self;
+
+  /** Initialize the function */
+  void SetParameters(ThresholdSettings *settings, double imin, double imax);
+
+  /** Apply the function to image intensity */
+  inline short operator()(const TInput &x);
+
+  /** Compare two functor objects */
+  bool operator ==(const Self &z);
+  bool operator !=(const Self &x);
 
 private:
   // The lower threshold in intensity units
@@ -148,18 +85,13 @@ private:
  * 
  * This filter uses a sigmoid function as a smooth threshold
  */
-template <typename TInputImage,typename TOutputImage = TInputImage>
+template <typename TInputImage,typename TOutputImage>
 class SmoothBinaryThresholdImageFilter: 
-  public itk::ImageToImageFilter<TInputImage,TOutputImage>
+  public itk::UnaryFunctorImageFilter<TInputImage,TOutputImage,
+    SmoothBinaryThresholdFunctor<typename TInputImage::PixelType> >
 {
 public:
-  
-  /** Standard class typedefs. */
-  typedef SmoothBinaryThresholdImageFilter                         Self;
-  typedef itk::ImageToImageFilter<TInputImage,TOutputImage>  Superclass;
-  typedef itk::SmartPointer<Self>                               Pointer;
-  typedef itk::SmartPointer<const Self>                    ConstPointer;  
-  
+
   /** Pixel Type of the input image */
   typedef TInputImage                                    InputImageType;
   typedef typename InputImageType::PixelType             InputPixelType;
@@ -168,47 +100,50 @@ public:
   typedef TOutputImage                                  OutputImageType;
   typedef typename OutputImageType::PixelType           OutputPixelType;
 
-  /** Functor type used for thresholding */
-  typedef SmoothBinaryThresholdFunctor<
-    InputPixelType,OutputPixelType>                          FunctorType;
+  /** The functor type */
+  typedef SmoothBinaryThresholdFunctor<InputPixelType>      FunctorType;
+
+  /** Standard class typedefs. */
+  typedef SmoothBinaryThresholdImageFilter                         Self;
+  typedef itk::UnaryFunctorImageFilter<InputImageType,
+                                       OutputImageType,
+                                       FunctorType>          Superclass;
+  typedef itk::SmartPointer<Self>                               Pointer;
+  typedef itk::SmartPointer<const Self>                    ConstPointer;  
+
 
   /** Method for creation through the object factory. */
   itkNewMacro(Self)
-    
+
   /** Image dimension. */
   itkStaticConstMacro(ImageDimension, unsigned int,
                       TInputImage::ImageDimension);
 
+  /** Set the minimum value of the input image. Must be provided for the
+    filter to work */
+  itkSetMacro(InputImageMinimum, double)
+
+  /** Set the maximum value of the input image. Must be provided for the
+    filter to work */
+  itkSetMacro(InputImageMaximum, double)
+
   /** Assign threshold settings */
-  void SetThresholdSettings(const ThresholdSettings &settings);
+  void SetParameters(ThresholdSettings *settings);
+
+  /** Access the threshold settings */
+  ThresholdSettings *GetParameters();
   
 protected:
 
   SmoothBinaryThresholdImageFilter();
-  virtual ~SmoothBinaryThresholdImageFilter() {};
+  virtual ~SmoothBinaryThresholdImageFilter() {}
   void PrintSelf(std::ostream& os, itk::Indent indent) const;
-  
-  /** Generate Data */
-  void GenerateData( void );
 
-private:
+  void GenerateData();
 
-  /** The unary functor filter type used for remapping */
-  typedef itk::UnaryFunctorImageFilter<
-    TInputImage,TOutputImage,FunctorType>            ThresholdFilterType;
-  typedef typename ThresholdFilterType::Pointer   ThresholdFilterPointer;
+  double m_InputImageMinimum, m_InputImageMaximum;
   
-  /** The min / max calculator used to compute input range */
-  typedef itk::MinimumMaximumImageCalculator<TInputImage> CalculatorType;
-  typedef typename CalculatorType::Pointer             CalculatorPointer;
-
-  /** Progress accumulator object */
-  typedef itk::ProgressAccumulator::Pointer           AccumulatorPointer;
-
-  ThresholdFilterPointer    m_ThresholdFilter;
-  CalculatorPointer         m_Calculator;                                               
-  ThresholdSettings         m_ThresholdSettings;
-  AccumulatorPointer        m_ProgressAccumulator;
+  SmartPtr<ThresholdSettings> m_Parameters;
 };
 
 #ifndef ITK_MANUAL_INSTANTIATION
diff --git a/Logic/Preprocessing/SmoothBinaryThresholdImageFilter.txx b/Logic/Preprocessing/SmoothBinaryThresholdImageFilter.txx
index 344ab5f..b90a155 100644
--- a/Logic/Preprocessing/SmoothBinaryThresholdImageFilter.txx
+++ b/Logic/Preprocessing/SmoothBinaryThresholdImageFilter.txx
@@ -36,74 +36,145 @@
 template<typename TInputImage,typename TOutputImage>
 SmoothBinaryThresholdImageFilter<TInputImage,TOutputImage>
 ::SmoothBinaryThresholdImageFilter()
+  : Superclass()
 {
-  // Construct the mini-pipeline
-  m_Calculator = CalculatorType::New();
-  m_ThresholdFilter = ThresholdFilterType::New();
-  
-  // Initialize the progress tracker
-  m_ProgressAccumulator = itk::ProgressAccumulator::New();
-  m_ProgressAccumulator->SetMiniPipelineFilter(this);
-  
-  // Add the filters to the progress accumulator (just one filter)
-  m_ProgressAccumulator->RegisterInternalFilter(m_ThresholdFilter,1.0f);
+  // Override the number of inputs to 4, so that we can respond to parameter
+  // changes and image min/max changes automatically.
+  this->SetNumberOfIndexedInputs(2);
+  m_InputImageMaximum = 0;
+  m_InputImageMinimum = 0;
+
+  // Set the parameters (second input) to NULL
+  m_Parameters = NULL;
 }
 
 template<typename TInputImage,typename TOutputImage>
 void
 SmoothBinaryThresholdImageFilter<TInputImage,TOutputImage>
-::GenerateData()
+::PrintSelf(std::ostream& os, itk::Indent indent) const
 {
-  // Get the input and output pointers
-  const typename InputImageType::ConstPointer inputImage = this->GetInput();
-  typename OutputImageType::Pointer outputImage = this->GetOutput();
-
-  // Allocate the output image
-  outputImage->SetBufferedRegion(outputImage->GetRequestedRegion());
-  outputImage->Allocate();
-
-  // Reset the progress
-  m_ProgressAccumulator->ResetProgress();
+  Superclass::PrintSelf(os,indent);
+}
 
-  // Compute the min/max of the image
-  m_Calculator->SetImage(inputImage);
-  m_Calculator->Compute();
-  
-  // Construct the functor
-  FunctorType functor;
-  functor.SetParameters(m_Calculator->GetMinimum(),
-                        m_Calculator->GetMaximum(),
-                        m_ThresholdSettings);
-
-  // Assign the functor to the filter
-  m_ThresholdFilter->SetInput(inputImage);
-  m_ThresholdFilter->SetFunctor(functor);
-
-  // Call the filter's GenerateData()
-  m_ThresholdFilter->GraftOutput(outputImage);
-  m_ThresholdFilter->Update();
-
-  // graft the mini-pipeline output back onto this filter's output.
-  // this is needed to get the appropriate regions passed back.
-  GraftOutput( m_ThresholdFilter->GetOutput() );
+template<typename TInputImage,typename TOutputImage>
+void 
+SmoothBinaryThresholdImageFilter<TInputImage,TOutputImage>
+::SetParameters(ThresholdSettings *settings)
+{
+  if(settings != m_Parameters)
+    {
+    // Store the settings as the second input
+	m_Parameters = settings;
+    this->SetNthInput(1, m_Parameters);
+    }
 }
 
 template<typename TInputImage,typename TOutputImage>
 void
 SmoothBinaryThresholdImageFilter<TInputImage,TOutputImage>
-::PrintSelf(std::ostream& os, itk::Indent indent) const
+::GenerateData()
 {
-  Superclass::PrintSelf(os,indent);
+  // All inputs must be set!
+  assert(m_Parameters);
+
+  // Set up the functor
+  this->GetFunctor().SetParameters(
+        m_Parameters, m_InputImageMinimum, m_InputImageMaximum);
+
+  // Execute the filter
+  Superclass::GenerateData();
 }
 
 template<typename TInputImage,typename TOutputImage>
-void 
+ThresholdSettings *
 SmoothBinaryThresholdImageFilter<TInputImage,TOutputImage>
-::SetThresholdSettings(const ThresholdSettings &settings)
+::GetParameters()
+{
+  return m_Parameters;
+}
+
+template<class TPixel>
+void
+SmoothBinaryThresholdFunctor<TPixel>
+::SetParameters(ThresholdSettings *ts, double imin, double imax)
 {
-  if(!(settings == m_ThresholdSettings))
+  // At least one threshold should be used
+  assert(ts->IsLowerThresholdEnabled() || ts->IsUpperThresholdEnabled());
+
+  // Bidirectional?
+  bool bidir = ts->IsLowerThresholdEnabled() && ts->IsUpperThresholdEnabled();
+
+  // Store the upper and lower bounds
+  m_LowerThreshold = ts->GetLowerThreshold();
+  m_UpperThreshold = ts->GetUpperThreshold();
+
+  // Handle the bidirectional threshold invalid case
+  if(bidir && m_LowerThreshold >= m_UpperThreshold)
     {
-    m_ThresholdSettings = settings;
-    this->Modified();
+    m_ScalingFactor = m_FactorUpper = m_FactorLower = m_Shift = 0.0;
+    return;
     }
+
+  // Combine the usage and inversion flags to get the scaling factors
+  m_FactorLower = ts->IsLowerThresholdEnabled() ? 1.0f : 0.0f;
+  m_FactorUpper = ts->IsUpperThresholdEnabled() ? 1.0f : 0.0f;
+
+  // Compute the shift
+  m_Shift = 1.0f - (m_FactorLower + m_FactorUpper);
+
+  // Compute the scaling factor (affecting smoothness) such that the supremum
+  // of the threshold function on the image domain is equal to 1-10^-s, where s
+  // is the smoothness factor
+  double range = bidir
+      ? m_UpperThreshold - m_LowerThreshold
+      : (imax - imin) / 3;        // This is kind of arbitrary
+
+  double eps = pow(10, -ts->GetSmoothness());
+  m_ScalingFactor = static_cast<float>(log((2-eps)/eps) / range);
+}
+
+template<class TInput>
+short
+SmoothBinaryThresholdFunctor<TInput>
+::operator ()(const TInput &x)
+{
+  // Cast the input to float
+  float z = static_cast<float>(x);
+
+  // Compute the left component
+  float yLower = m_FactorLower * tanh((z-m_LowerThreshold) * m_ScalingFactor);
+
+  // Compute the right component
+  float yUpper = m_FactorUpper * tanh((m_UpperThreshold-z) * m_ScalingFactor);
+
+  // Map to the range -1 ro 1
+  float t = (yLower + yUpper + m_Shift);
+
+  // Return the result (TODO: hack)
+  return static_cast<short>(t * 0x7fff);
+}
+
+template<class TInput>
+bool
+SmoothBinaryThresholdFunctor<TInput>
+::operator ==(const Self &z)
+{
+  return
+      m_LowerThreshold == z.m_LowerThreshold &&
+      m_UpperThreshold == z.m_UpperThreshold &&
+      m_ScalingFactor == z.m_ScalingFactor &&
+      m_FactorLower == z.m_FactorLower &&
+      m_FactorUpper == z.m_FactorUpper &&
+      m_Shift == z.m_Shift;
 }
+
+template<class TInput>
+bool
+SmoothBinaryThresholdFunctor<TInput>
+::operator !=(const Self &z)
+{
+  return !(*this == z);
+}
+
+
+
diff --git a/Logic/Preprocessing/ThresholdSettings.cxx b/Logic/Preprocessing/ThresholdSettings.cxx
index ebff640..ab9a497 100644
--- a/Logic/Preprocessing/ThresholdSettings.cxx
+++ b/Logic/Preprocessing/ThresholdSettings.cxx
@@ -33,59 +33,63 @@
 
 =========================================================================*/
 #include "ThresholdSettings.h"
-#include "GreyImageWrapper.h"
+#include "ImageWrapperBase.h"
+#include "Registry.h"
 
 bool 
 ThresholdSettings
 ::operator == (const ThresholdSettings &other) const
 {
-  return memcmp(this,&other,sizeof(ThresholdSettings)) == 0;
+  return(
+        this->m_LowerThreshold == other.m_LowerThreshold &&
+        this->m_UpperThreshold == other.m_UpperThreshold &&
+        this->m_Smoothness == other.m_Smoothness &&
+        this->m_ThresholdMode == other.m_ThresholdMode &&
+        this->m_Initialized == other.m_Initialized);
 }
 
+bool
 ThresholdSettings
-ThresholdSettings
-::MakeDefaultSettings(GreyImageWrapper *wrapper)
+::operator !=(const ThresholdSettings &other) const
 {
-  // Use the min and the max of the wrapper
-  int iMin = wrapper->GetImageMin();
-  int iMax = wrapper->GetImageMax();
-
-  // If the image is constant, return default settings
-  if(iMin == iMax) return MakeDefaultSettingsWithoutImage();
-  
-  // Generate the default settings
-  ThresholdSettings settings;
-  settings.m_LowerThresholdEnabled = true;
-  settings.m_UpperThresholdEnabled = true;  
-  settings.m_LowerThreshold = iMin + (iMax-iMin) / 3.0;
-  settings.m_UpperThreshold = iMin + 2.0 * (iMax-iMin) / 3.0;
-  settings.m_Smoothness = 3.0;
-
-  return settings;
+  return !((*this) == other);
 }
 
+void
 ThresholdSettings
-ThresholdSettings
-::MakeDefaultSettingsWithoutImage()
+::InitializeToDefaultForImage(ScalarImageWrapperBase *wrapper)
 {
-  ThresholdSettings settings;
-  settings.m_LowerThresholdEnabled = true;
-  settings.m_UpperThresholdEnabled = true;  
-  settings.m_LowerThreshold = 40.0;
-  settings.m_UpperThreshold = 80.0; 
-  settings.m_Smoothness = 3.0;
-
-  return settings;
+  // Use the min and the max of the wrapper
+  double iMin = wrapper->GetImageMinAsDouble();
+  double iMax = wrapper->GetImageMaxAsDouble();
+
+  // If the image is constant, return default settings
+  if(iMin < iMax)
+    {
+    m_ThresholdMode = TWO_SIDED;
+    m_LowerThreshold = iMin + (iMax-iMin) / 3.0;
+    m_UpperThreshold = iMin + 2.0 * (iMax-iMin) / 3.0;
+    m_Smoothness = 3.0;
+    }
+  else
+    {
+    m_ThresholdMode = LOWER;
+    m_LowerThreshold = iMin;
+    m_UpperThreshold = iMax;
+    m_Smoothness = 3.0;
+    }
+
+  m_Initialized = true;
 }
 
 ThresholdSettings
 ::ThresholdSettings()
 {
-  m_LowerThresholdEnabled = true;
-  m_UpperThresholdEnabled = true;  
+  m_ThresholdMode = TWO_SIDED;
   m_LowerThreshold = 0.0;
   m_UpperThreshold = 1.0; 
   m_Smoothness = 1.0;
+  m_Initialized = false;
 }
 
 bool
@@ -93,9 +97,85 @@ ThresholdSettings
 ::IsValid() const
 {
   if(m_Smoothness < 0.0) return false;
-  if(m_LowerThresholdEnabled && m_UpperThresholdEnabled && 
-      m_UpperThreshold <= m_LowerThreshold)
+  if(m_ThresholdMode == TWO_SIDED && m_UpperThreshold <= m_LowerThreshold)
     return false;
   return true;
 }
 
+bool
+ThresholdSettings
+::IsValidForImage(ScalarImageWrapperBase *wrapper)
+{
+  // Use the min and the max of the wrapper
+  double iMin = wrapper->GetImageMinAsDouble();
+  double iMax = wrapper->GetImageMaxAsDouble();
+
+  // Check threshold irregularities
+  if(m_ThresholdMode == TWO_SIDED || m_ThresholdMode == LOWER)
+    if(m_LowerThreshold < iMin) return false;
+
+  if(m_ThresholdMode == TWO_SIDED || m_ThresholdMode == UPPER)
+    if(m_UpperThreshold > iMax) return false;
+
+  if(m_ThresholdMode == TWO_SIDED)
+    if(m_LowerThreshold >= m_UpperThreshold) return false;
+
+  // Check smoothness
+  if(m_Smoothness < 0.0) return false;
+
+  return true;
+}
+
+void
+ThresholdSettings
+::ReadFromRegistry(Registry &registry, ScalarImageWrapperBase *wrapper)
+{
+  // Use the min and the max of the wrapper to check validity
+  double iMin = wrapper->GetImageMinAsDouble();
+  double iMax = wrapper->GetImageMaxAsDouble();
+
+  // Try reading the settings from the registry
+  float lt = registry["LowerThreshold"][m_LowerThreshold];
+  float ut = registry["UpperThreshold"][m_UpperThreshold];
+  float sm = registry["Smoothness"][m_Smoothness];
+
+  // Check that the settings are valid before proceding
+  if(iMin <= lt && lt <= ut && ut <= iMax && sm >= 0.0)
+    {
+    // Use the threshold values we read
+    m_LowerThreshold = lt;
+    m_UpperThreshold = ut;
+
+    // Read the smoothness information
+    m_Smoothness = sm;
+
+    // For backward compatibility (and out of laziness to set up an enum mapping)
+    // we store the threshold limits as a pair of bools, rather than as the enum
+    bool lower_on =
+        registry["LowerThresholdEnabled"][IsLowerThresholdEnabled()];
+
+    bool upper_on =
+        registry["UpperThresholdEnabled"][IsUpperThresholdEnabled()];
+
+    m_ThresholdMode = upper_on ?
+          (lower_on ? TWO_SIDED : UPPER) :
+          (lower_on ? LOWER : TWO_SIDED);
+
+    // Set as having been initialized
+    m_Initialized = true;
+    }
+}
+
+void
+ThresholdSettings
+::WriteToRegistry(Registry &registry)
+{
+  assert(m_Initialized);
+
+  registry["LowerThreshold"] << this->GetLowerThreshold();
+  registry["UpperThreshold"] << this->GetUpperThreshold();
+  registry["Smoothness"] << this->GetSmoothness();
+  registry["LowerThresholdEnabled"] << this->IsLowerThresholdEnabled();
+  registry["UpperThresholdEnabled"] << this->IsUpperThresholdEnabled();
+}
+
diff --git a/Logic/Preprocessing/ThresholdSettings.h b/Logic/Preprocessing/ThresholdSettings.h
index 375dd59..0932462 100644
--- a/Logic/Preprocessing/ThresholdSettings.h
+++ b/Logic/Preprocessing/ThresholdSettings.h
@@ -36,59 +36,95 @@
 #define __ThresholdSettings_h_
 
 #include "SNAPCommon.h"
+#include "itkDataObject.h"
+#include "itkObjectFactory.h"
 
 // Forward references
-class GreyImageWrapper;
+class ScalarImageWrapperBase;
+class Registry;
 
 /**
- * This class encapsulates the thresholding settings used by the program.
- * for In/Out snake initialization
- */
-class ThresholdSettings
+  This class encapsulates the thresholding settings used by the smooth 2-sided
+  threshold preprocessing option. This settings object inherits from the
+  itk::DataObject class. This makes it possible to pass the settings as an
+  input to the data processing filter, which makes sure that the filter
+  automatically recomputes in response to changes to the parameters.
+
+  The settings are meant to be passed by reference, with a single object in
+  the program owning the settings.
+*/
+class ThresholdSettings : public itk::DataObject
 {
 public:
-    virtual ~ThresholdSettings() { /*To avoid compiler warning.*/ }
-  irisGetMacro(LowerThreshold, float);
-  irisSetMacro(LowerThreshold, float);
 
-  irisGetMacro(UpperThreshold, float);
-  irisSetMacro(UpperThreshold, float);
+  irisITKObjectMacro(ThresholdSettings, itk::DataObject)
 
-  irisGetMacro(Smoothness,float);
-  irisSetMacro(Smoothness,float);
+  /** The mode for setting the threshold */
+  enum ThresholdMode { TWO_SIDED=0, LOWER, UPPER };
 
-  irisIsMacro(LowerThresholdEnabled);
-  irisSetMacro(LowerThresholdEnabled,bool);
+  itkSetMacro(LowerThreshold, float)
+  itkGetConstMacro(LowerThreshold, float)
 
-  irisIsMacro(UpperThresholdEnabled);
-  irisSetMacro(UpperThresholdEnabled,bool);
+  itkSetMacro(UpperThreshold, float)
+  itkGetConstMacro(UpperThreshold, float)
+
+  itkSetMacro(Smoothness, float)
+  itkGetConstMacro(Smoothness, float)
+
+  itkSetMacro(ThresholdMode, ThresholdMode)
+  itkGetConstMacro(ThresholdMode, ThresholdMode)
+
+  itkGetMacro(Initialized, bool)
+
+  bool IsLowerThresholdEnabled() const
+  {
+    return m_ThresholdMode != UPPER;
+  }
+
+  bool IsUpperThresholdEnabled() const
+  {
+    return m_ThresholdMode != LOWER;
+  }
 
   /** Compare two sets of settings */
   bool operator == (const ThresholdSettings &other) const;
+  bool operator != (const ThresholdSettings &other) const;
 
   /** Check if the settings are valid */
   bool IsValid() const;
 
+  /** Check validity relative to a loaded image */
+  bool IsValidForImage(ScalarImageWrapperBase *wrapper);
+
   /**
    * Create a default instance of the settings based on an image wrapper
    */
-  static ThresholdSettings MakeDefaultSettings(GreyImageWrapper *wrapper);
+  void InitializeToDefaultForImage(ScalarImageWrapperBase *wrapper);
+
+  /**
+    Read the settings from a registry, given the current grey image. This will
+    check if the settings are valid and abort if they are not
+    */
+  void ReadFromRegistry(Registry &reg, ScalarImageWrapperBase *wrapper);
 
-  /** This will create a slightly less useful settings object with thresholds
-   * at 40 and 100.  Before using them, make sure that the image is in range
-   * of 40 and 100 */
-  static ThresholdSettings MakeDefaultSettingsWithoutImage();
+  /** Write the settings to a registry */
+  void WriteToRegistry(Registry &registry);
+
+protected:
 
-  // Constructor: creates dummy settings
   ThresholdSettings();
+  virtual ~ThresholdSettings() { /*To avoid compiler warning.*/ }
 
 private:
   float m_LowerThreshold;
   float m_UpperThreshold;
   float m_Smoothness;
+
+  // Whether the settings have been initialized. When constructed, the settings
+  // are set to an uninitialized state.
+  bool m_Initialized;
   
-  bool m_UpperThresholdEnabled;
-  bool m_LowerThresholdEnabled;
+  ThresholdMode m_ThresholdMode;
 };
 
 #endif // __ThresholdSettings_h_
diff --git a/Logic/Slicing/IRISSlicer.h b/Logic/Slicing/IRISSlicer.h
index 14a8769..a2f59b2 100644
--- a/Logic/Slicing/IRISSlicer.h
+++ b/Logic/Slicing/IRISSlicer.h
@@ -54,30 +54,36 @@
  * directions, accomodating different positions of the display space origin in the
  * image space.
  */
-template <class TPixel>
+template <class TInputImage, class TOutputImage>
 class ITK_EXPORT IRISSlicer 
-: public itk::ImageToImageFilter<itk::Image<TPixel,3>, itk::Image<TPixel,2> >
+: public itk::ImageToImageFilter<TInputImage, TOutputImage>
 {
 public:
   /** Standard class typedefs. */
-  typedef IRISSlicer  Self;
-  typedef itk::Image<TPixel,3>  InputImageType;
-  typedef itk::Image<TPixel,2>  OutputImageType;
-  typedef itk::ImageToImageFilter<InputImageType,OutputImageType> Superclass;
-  typedef itk::SmartPointer<Self>   Pointer;
-  typedef itk::SmartPointer<const Self>  ConstPointer;
+  typedef IRISSlicer                                                     Self;
+  typedef itk::ImageToImageFilter<TInputImage, TOutputImage>       Superclass;
+  typedef itk::SmartPointer<Self>                                     Pointer;
+  typedef itk::SmartPointer<const Self>                          ConstPointer;
+
+  typedef TInputImage                                          InputImageType;
+  typedef typename InputImageType::ConstPointer             InputImagePointer;
+  typedef typename InputImageType::PixelType                   InputPixelType;
+  typedef typename InputImageType::InternalPixelType       InputComponentType;
+
+  typedef TOutputImage                                        OutputImageType;
+  typedef typename OutputImageType::Pointer                OutputImagePointer;
+  typedef typename OutputImageType::PixelType                 OutputPixelType;
+  typedef typename OutputImageType::InternalPixelType     OutputComponentType;
 
   /** Method for creation through the object factory. */
-  itkNewMacro(Self);
+  itkNewMacro(Self)
   
   /** Run-time type information (and related methods). */
-  itkTypeMacro(IRISSlicer, ImageToImageFilter);
+  itkTypeMacro(IRISSlicer, ImageToImageFilter)
 
-  /** Some typedefs. */
-  typedef typename InputImageType::ConstPointer  InputImagePointer;
-  typedef typename InputImageType::RegionType  InputImageRegionType; 
-  typedef typename OutputImageType::Pointer  OutputImagePointer;
-  typedef typename OutputImageType::RegionType  OutputImageRegionType;
+  /** Some more typedefs. */
+  typedef typename InputImageType::RegionType             InputImageRegionType;
+  typedef typename OutputImageType::RegionType           OutputImageRegionType;
   typedef itk::ImageSliceConstIteratorWithIndex<InputImageType>  InputIteratorType;
   typedef itk::ImageRegionIteratorWithIndex<OutputImageType>  SimpleOutputIteratorType;
   typedef itk::ImageLinearIteratorWithIndex<OutputImageType> OutputIteratorType;
@@ -106,6 +112,18 @@ public:
   itkSetMacro(PixelTraverseForward,bool);
   itkGetMacro(PixelTraverseForward,bool);
 
+  /** Add a second `preview' input to the slicer. The slicer will check if
+    the preview input is newer than the main input, and if so, will obtain
+    the data from the preview input. This is used in the speed preview
+    framework, but could also be adapted for other features. Setting the
+    preview input to NULL disables this feature. */
+  void SetPreviewInput(InputImageType *input);
+
+  /**
+    Get the preview input.
+    */
+  InputImageType *GetPreviewInput();
+
 protected:
   IRISSlicer();
   virtual ~IRISSlicer() {};
@@ -122,12 +140,20 @@ protected:
    * \sa ProcessObject::GenerateOutputInformaton()  */
   virtual void GenerateOutputInformation();
 
+  void GenerateInputRequestedRegion();
+
   /**
    * This method maps an input region to an output region
    */
   virtual void CallCopyOutputRegionToInputRegion(InputImageRegionType &destRegion,
                               const OutputImageRegionType &srcRegion);
 
+  /*
+  void BeforeThreadedGenerateData();
+  void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread,
+                            ThreadIdType threadId);
+  void AfterThreadedGenerateData();
+*/
   /** 
    * IRISSlicer is not implemented as a multithreaded filter.
    * \sa ImageToImageFilter::GenerateData()  
diff --git a/Logic/Slicing/IRISSlicer.txx b/Logic/Slicing/IRISSlicer.txx
index 4fc2486..c19dc4f 100644
--- a/Logic/Slicing/IRISSlicer.txx
+++ b/Logic/Slicing/IRISSlicer.txx
@@ -32,10 +32,21 @@
   PURPOSE.  See the above copyright notices for more information. 
 
 =========================================================================*/
-template<class TPixel> 
-IRISSlicer<TPixel>
+#include "itkDefaultPixelAccessor.h"
+#include "itkDefaultPixelAccessorFunctor.h"
+#include "itkImageAdaptor.h"
+#include "itkImage.h"
+#include "itkVectorImage.h"
+#include "itkVectorImageToImageAdaptor.h"
+
+template <class TInputImage, class TOutputImage>
+IRISSlicer<TInputImage, TOutputImage>
 ::IRISSlicer()
 {
+  // Two inputs are allowed (second being the preview input)
+  this->SetNumberOfIndexedInputs(2);
+  this->SetPreviewInput(NULL);
+
   // There is a single input to the filter
   this->SetNumberOfRequiredInputs(1);
 
@@ -54,8 +65,8 @@ IRISSlicer<TPixel>
   m_SliceIndex = 0;
 }
 
-template<class TPixel> 
-void IRISSlicer<TPixel>
+template <class TInputImage, class TOutputImage>
+void IRISSlicer<TInputImage, TOutputImage>
 ::GenerateOutputInformation()
 {
   // Get pointers to the inputs and outputs
@@ -91,8 +102,8 @@ void IRISSlicer<TPixel>
   outputPtr->SetOrigin(outputOrigin);
 }
 
-template<class TPixel>
-void IRISSlicer<TPixel>
+template <class TInputImage, class TOutputImage>
+void IRISSlicer<TInputImage, TOutputImage>
 ::CallCopyOutputRegionToInputRegion(InputImageRegionType &destRegion,
                                     const OutputImageRegionType &srcRegion)
 {
@@ -143,49 +154,177 @@ void IRISSlicer<TPixel>
     }
 }
 
+template <class TInputImage, class TOutputImage>
+void
+IRISSlicer<TInputImage, TOutputImage>
+::GenerateInputRequestedRegion()
+{
+  // If there is a preview input, and the pipeline of the preview input is
+  // older than the main input, we don't ask the preview to generate a new
+  // slice. Instead, we leave it's requested region as is, so that the
+  // preview does not actually update. This results in a selective behavior,
+  // where we choose the preview if it's newer than the main input, otherwise
+  // we choose the normal input
+
+  // Actually compute what the input region should be
+  InputImageRegionType inputRegion;
+  this->CallCopyOutputRegionToInputRegion(
+        inputRegion, this->GetOutput()->GetRequestedRegion());
+
+  // Get the main input
+  InputImageType *main = const_cast<InputImageType *>(this->GetInput(0));
+
+  // Decide if we want to use the preview input instead
+  InputImageType *preview = const_cast<InputImageType *>(this->GetInput(1));
+
+  if(preview)
+    {
+    if(preview->GetPipelineMTime() > main->GetMTime())
+      {
+      // We want the preview to be updated
+      preview->SetRequestedRegion(inputRegion);
+      }
+    else
+      {
+      // Ignore the preview, prevent it from updating itself needlessly
+      preview->SetRequestedRegion(preview->GetBufferedRegion());
+      }
+
+    main->SetRequestedRegion(inputRegion);
+    }
+}
+
+#include "itkImageLinearIteratorWithIndex.h"
+#include "itkImageRegionConstIterator.h"
+#include "itkImageConstIterator.h"
+
 /*
-template<class TPixel> 
-void IRISSlicer<TPixel>
-::GenerateData()
+template <class TInputImage, class TOutputImage>
+void
+IRISSlicer<TInputImage, TOutputImage>
+::ThreadedGenerateData(
+    const OutputImageRegionType &outputRegionForThread,
+    ThreadIdType threadId)
 {
   // Here's the input and output
-  InputImagePointer  inputPtr = this->GetInput();
-  OutputImagePointer  outputPtr = this->GetOutput();
-  
+  const InputImageType *inputPtr = this->GetInput();
+  OutputImageType *outputPtr = this->GetOutput();
+
+  // Decide if we want to use the preview input instead
+  const InputImageType *preview =
+      (InputImageType *) this->GetInputs()[1].GetPointer();
+
+  if(preview && preview->GetMTime() > inputPtr->GetMTime())
+    {
+    inputPtr = preview;
+    }
+
   // Allocate (why is this necessary?)
   this->AllocateOutputs();
 
-  // Compute the region in the image for which the slice is being extracted
-  InputImageRegionType inputRegion = inputPtr->GetRequestedRegion();
+  // Get the image dimensions
+  typename InputImageType::SizeType szVol = inputPtr->GetBufferedRegion().GetSize();
 
-  // Create an iterator that will parse the desired slice in the image
-  InputIteratorType it(inputPtr,inputRegion);
-  it.SetFirstDirection(m_PixelDirectionImageAxis);
-  it.SetSecondDirection(m_LineDirectionImageAxis);
+  // Set the strides in image coordinates
+  Vector3i stride_image(1, szVol[0], szVol[1] * szVol[0]);
+
+  // Scale the strides by the number of components. We can't get it from the
+  // image itself since the image may be an ImageAdaptor, so we need to use
+  // the pixel container's size
+  long nintpix = inputPtr->GetPixelContainer()->Size();
+  long nvoxels = szVol[2] * stride_image[2];
+  unsigned int ncomp = static_cast<unsigned int>(nintpix/nvoxels);
+  stride_image *= ncomp;
+
+  // Determine the strides for the pixel step and line step
+  int sPixel = (m_PixelTraverseForward ? 1 : -1) *
+    stride_image[m_PixelDirectionImageAxis];
+  int sLine = (m_LineTraverseForward ? 1 : -1) *
+    stride_image[m_LineDirectionImageAxis];
+
+  // We never take full line-strides, because as we iterate, we
+  // take n pixel-strides before needing to worry about changing
+  // the line. Therefore, we compute the step needed to go to the
+  // start of next line after taking n pixel-strides
+  int sRowOfPixels = sPixel * szVol[m_PixelDirectionImageAxis];
+  int sLineDelta = sLine - sRowOfPixels;
+
+  // Determine the first voxel that we will traverse
+  Vector3i xStartVoxel;
+  xStartVoxel[m_PixelDirectionImageAxis] =
+    m_PixelTraverseForward ? 0 : szVol[m_PixelDirectionImageAxis] - 1;
+  xStartVoxel[m_LineDirectionImageAxis] =
+    m_LineTraverseForward ? 0 : szVol[m_LineDirectionImageAxis] - 1;
+  xStartVoxel[m_SliceDirectionImageAxis] =
+    szVol[m_SliceDirectionImageAxis] == 1 ? 0 : m_SliceIndex;
+
+  // Get the offset of the first voxel
+  size_t iStart = dot_product(stride_image, xStartVoxel);
+
+  // Get the size of the output region (whole slice)
+  typename OutputImageType::RegionType rgn = outputPtr->GetBufferedRegion();
+  size_t nPixel = rgn.GetSize()[0], nLine = rgn.GetSize()[1];
+
+  // Get pointers to input and output data
+  const InputComponentType *pSource = inputPtr->GetBufferPointer();
+
+  // Set up the output iterator
+  typedef itk::ImageLinearIteratorWithIndex<OutputImageType> OutIterType;
+  OutIterType it_out(outputPtr, outputPtr->GetBufferedRegion());
+
+  // Get the pixel accessor functor - for unified access to voxels
+  typedef typename InputImageType::AccessorFunctorType AccessorFunctorType;
+  typedef typename InputImageType::AccessorType AccessorType;
+  typedef typename InputImageType::OffsetValueType OffsetType;
+  AccessorType accessor = inputPtr->GetPixelAccessor();
+  AccessorFunctorType accessor_functor;
+  accessor_functor.SetPixelAccessor(accessor);
+  accessor_functor.SetBegin(pSource);
+
+  // Position the source at the first component of the first voxel to traverse
+  // OffsetType offset =
+  const InputComponentType *pBegin = pSource;
+  pSource += iStart;
+
+  // Main loop: copy data from source to target
+  while(!it_out.IsAtEnd())
+    {
+    while( !it_out.IsAtEndOfLine() )
+      {
+      // Use the accessor
+      accessor_functor.SetBegin(pSource);
+      OutputPixelType val = accessor_functor.Get(*pSource);
+
+      // Set the pixel
+      it_out.Set(val);
+
+      // Go to next pixel
+      ++it_out;
+      pSource += sPixel;
+      }
+    it_out.NextLine();
+    pSource += sLineDelta;
+    }
 
-  // Copy the contents using a different method, depending on the axes directions
-  // The direction with index one is the order in which the lines are traversed and
-  // the direction with index two is the order in which the pixels are traversed.
-  if(m_PixelTraverseForward)
-    if(m_LineTraverseForward)
-      CopySliceLineForwardPixelForward(it,outputPtr);
-    else
-      CopySliceLineBackwardPixelForward(it,outputPtr);
-  else
-    if(m_LineTraverseForward)
-      CopySliceLineForwardPixelBackward(it,outputPtr);
-    else
-      CopySliceLineBackwardPixelBackward(it,outputPtr);
 }
 */
 
-template<class TPixel> 
-void IRISSlicer<TPixel>
+template <class TInputImage, class TOutputImage>
+void IRISSlicer<TInputImage, TOutputImage>
 ::GenerateData()
 {
   // Here's the input and output
-  InputImagePointer  inputPtr = this->GetInput();
-  OutputImagePointer  outputPtr = this->GetOutput();
+  const InputImageType *inputPtr = this->GetInput();
+  OutputImageType *outputPtr = this->GetOutput();
+
+  // Decide if we want to use the preview input instead
+  const InputImageType *preview =
+      (InputImageType *) this->GetInputs()[1].GetPointer();
+
+  if(preview && preview->GetMTime() > inputPtr->GetMTime())
+    {
+    inputPtr = preview;
+    }
   
   // Allocate (why is this necessary?)
   this->AllocateOutputs();
@@ -196,6 +335,14 @@ void IRISSlicer<TPixel>
   // Set the strides in image coordinates
   Vector3i stride_image(1, szVol[0], szVol[1] * szVol[0]);
 
+  // Scale the strides by the number of components. We can't get it from the
+  // image itself since the image may be an ImageAdaptor, so we need to use
+  // the pixel container's size
+  long nintpix = inputPtr->GetPixelContainer()->Size();
+  long nvoxels = szVol[2] * stride_image[2];
+  unsigned int ncomp = static_cast<unsigned int>(nintpix/nvoxels);
+  stride_image *= ncomp;
+
   // Determine the strides for the pixel step and line step
   int sPixel = (m_PixelTraverseForward ? 1 : -1) *
     stride_image[m_PixelDirectionImageAxis];
@@ -226,27 +373,49 @@ void IRISSlicer<TPixel>
   size_t nPixel = rgn.GetSize()[0], nLine = rgn.GetSize()[1];
 
   // Get pointers to input and output data
-  const TPixel *pSource = inputPtr->GetBufferPointer();
-  TPixel *pTarget = outputPtr->GetBufferPointer();
-
-  // Position the source
+  const InputComponentType *pSource = inputPtr->GetBufferPointer();
+
+  // Set up the output iterator
+  typedef itk::ImageLinearIteratorWithIndex<OutputImageType> OutIterType;
+  OutIterType it_out(outputPtr, outputPtr->GetBufferedRegion());
+
+  // Get the pixel accessor functor - for unified access to voxels
+  typedef typename InputImageType::AccessorFunctorType AccessorFunctorType;
+  typedef typename InputImageType::AccessorType AccessorType;
+  typedef typename InputImageType::OffsetValueType OffsetType;
+  AccessorType accessor = inputPtr->GetPixelAccessor();
+  AccessorFunctorType accessor_functor;
+  accessor_functor.SetPixelAccessor(accessor);
+  accessor_functor.SetBegin(pSource);
+
+  // Position the source at the first component of the first voxel to traverse
+  // OffsetType offset =
+  const InputComponentType *pBegin = pSource;
   pSource += iStart;
 
   // Main loop: copy data from source to target
-  for(size_t il = 0; il < nLine; il++)
+  while(!it_out.IsAtEnd())
     {
-    for(size_t ip = 0; ip < nPixel; ip++)
+    while( !it_out.IsAtEndOfLine() )
       {
-      *pTarget = *pSource;
-      pTarget++;
-      pSource+=sPixel;
+      // Use the accessor
+      accessor_functor.SetBegin(pSource);
+      OutputPixelType val = accessor_functor.Get(*pSource);
+
+      // Set the pixel
+      it_out.Set(val);
+
+      // Go to next pixel
+      ++it_out;
+      pSource += sPixel;
       }
+    it_out.NextLine();
     pSource += sLineDelta;
     }
 }
 
-template<class TPixel> 
-void IRISSlicer<TPixel>
+template <class TInputImage, class TOutputImage>
+void IRISSlicer<TInputImage, TOutputImage>
 ::PrintSelf(std::ostream &os, itk::Indent indent) const
 {
   Superclass::PrintSelf(os, indent);
@@ -259,208 +428,35 @@ void IRISSlicer<TPixel>
   os << indent << "Pixels Traversed Forward: " << m_PixelTraverseForward << std::endl;
 }
 
-/*
-// Traverse pixels forward and lines forward
-template<class TPixel> 
-void IRISSlicer<TPixel>
-::CopySliceLineForwardPixelForward(InputIteratorType itImage, 
-                                   OutputImageType *outputPtr)
-{  
-  // Create an simple iterator for the slice
-  SimpleOutputIteratorType itSlice(outputPtr,outputPtr->GetRequestedRegion());
-
-  // Position both iterators at the beginning
-  itSlice.GoToBegin();
-  itImage.GoToBegin();
-
-  // Parse over lines
-  while(!itSlice.IsAtEnd())
-    {
-    // Parse over pixels
-    while(!itImage.IsAtEndOfLine())
-      {  
-      itSlice.Set(itImage.Value());
-      ++itSlice;
-      ++itImage;
-      }
-
-    // Position the image iterator at the next line
-    itImage.NextLine();
-    }
-}
-
-// Traverse pixels forward and lines backward
-template<class TPixel> 
-void IRISSlicer<TPixel>
-::CopySliceLineBackwardPixelForward(InputIteratorType itImage, 
-                                    OutputImageType *outputPtr)
+template <class TInputImage, class TOutputImage>
+void IRISSlicer<TInputImage, TOutputImage>
+::SetPreviewInput(InputImageType *input)
 {
-  // Create an iterator into the slice itself
-  OutputIteratorType itSlice(outputPtr,outputPtr->GetRequestedRegion());
-  itSlice.SetDirection(0);
-
-  // Go to the last line  
-  itSlice.GoToReverseBegin();
-  itImage.GoToBegin();
-  
-  // Parse over lines
-  while(!itSlice.IsAtReverseEnd())
-    {
-    // Position the slice iterator at the first pixel of the line
-    itSlice.GoToBeginOfLine();
-
-    // Scan in forward until the end of line
-    while(!itSlice.IsAtEndOfLine())
-      {
-      itSlice.Set(itImage.Value());
-      ++itSlice;
-      ++itImage;
-      }
-
-    // Step over to the previous line
-    itSlice.PreviousLine();
-    itImage.NextLine();
-    }
+  this->SetNthInput(1, input);
 }
 
-// Traverse pixels backward and lines forward
-template<class TPixel> 
-void IRISSlicer<TPixel>
-::CopySliceLineForwardPixelBackward(InputIteratorType itImage, 
-                                    OutputImageType *outputPtr)
+template <class TInputImage, class TOutputImage>
+typename IRISSlicer<TInputImage, TOutputImage>::InputImageType *
+IRISSlicer<TInputImage, TOutputImage>
+::GetPreviewInput()
 {
-  // Create an iterator into the slice itself
-  OutputIteratorType itSlice(outputPtr,outputPtr->GetRequestedRegion());
-  itSlice.SetDirection(0);
-
-  // Go to start of the last line  
-  itSlice.GoToBegin();
-  itImage.GoToBegin();
-  
-  // Parse over lines
-  while(!itSlice.IsAtEnd())
-    {
-    // Position the slice iterator at the last pixel of the line
-    itSlice.GoToEndOfLine(); --itSlice;
-    
-    // Scan in backwards until we're past the beginning of the line
-    while(!itSlice.IsAtReverseEndOfLine())
-      {
-      itSlice.Set(itImage.Value());
-      --itSlice;
-      ++itImage;
-      }
-
-    // Step over to the next line
-    itSlice.NextLine();
-    itImage.NextLine();
-    }
+  return const_cast<InputImageType *>(this->GetInput(1));
 }
 
-// Traverse pixels backward and lines backward
-template<class TPixel> 
-void IRISSlicer<TPixel>
-::CopySliceLineBackwardPixelBackward(InputIteratorType itImage, 
-                                     OutputImageType *outputPtr)
-{  
-  // Create an simple iterator for the slice
-  SimpleOutputIteratorType itSlice(outputPtr,outputPtr->GetRequestedRegion());
-  // Position both iterators at the beginning
-  itSlice.GoToReverseBegin();
-  itImage.GoToBegin();
-
-  // Parse over lines
-  while(!itSlice.IsAtReverseEnd())
-    {
-    // Parse over pixels
-    while(!itImage.IsAtEndOfLine())
-      {  
-      itSlice.Set(itImage.Value());
-      --itSlice;
-      ++itImage;
-      }
+/*
+template <class TInputImage, class TOutputImage>
+void
+IRISSlicer<TInputImage, TOutputImage>
+::BeforeThreadedGenerateData()
+{
 
-    // Position the image iterator at the next line
-    itImage.NextLine();
-    }
 }
-*/
 
-/*
-template<class TPixel> 
-void IRISSlicer<TPixel>
-::CopySlice(InputIteratorType itImage, OutputIteratorType itSlice, 
-            int sliceDir, int lineDir)
+template <class TInputImage, class TOutputImage>
+void
+IRISSlicer<TInputImage, TOutputImage>
+::AfterThreadedGenerateData()
 {
-  if (sliceDir > 0 && lineDir > 0)
-    {
-    itImage.GoToBegin();
-    while (!itImage.IsAtEndOfSlice())
-      {
-      while (!itImage.IsAtEndOfLine())
-        {
-        itSlice.Set(itImage.Value());
-        ++itSlice;
-        ++itImage;
-        }
-      itImage.NextLine();
-      }
-    } 
-  else if (sliceDir > 0 && lineDir < 0)
-    {
-    itImage.GoToBegin();
-    while (!itImage.IsAtEndOfSlice())
-      {
-      itImage.NextLine();
-      itImage.PreviousLine();
-      while (1)
-        {
-        itSlice.Set(itImage.Value());
-        ++itSlice;
-        if (itImage.IsAtReverseEndOfLine())
-          break;
-        else
-          --itImage;
-        }
-      itImage.NextLine();
-      }
-    } 
-  else if (sliceDir < 0 && lineDir > 0)
-    {
-    itImage.GoToReverseBegin();
-    while (!itImage.IsAtReverseEndOfSlice())
-      {
-      itImage.PreviousLine();
-      itImage.NextLine();
-      while (!itImage.IsAtEndOfLine())
-        {
-        TPixel px = itImage.Value();
-        itSlice.Set(px);
-        ++itSlice;
-        ++itImage;
-        }
-      itImage.PreviousLine();
-      } 
-    } 
-  else if (sliceDir < 0 && lineDir < 0)
-    {
-    itImage.GoToReverseBegin();
-    while (1)
-      {
-      while (1)
-        {
-        itSlice.Set(itImage.Value());
-        ++itSlice;
-        if (itImage.IsAtReverseEndOfLine())
-          break;
-        else
-          --itImage;
-        }            
-      if (itImage.IsAtReverseEndOfSlice())
-        break;
-      else
-        itImage.PreviousLine();
-      } 
-    }
+
 }
 */
diff --git a/Logic/Slicing/IntensityCurveInterface.h b/Logic/Slicing/IntensityCurveInterface.h
index 2b0f1f8..7848b0e 100644
--- a/Logic/Slicing/IntensityCurveInterface.h
+++ b/Logic/Slicing/IntensityCurveInterface.h
@@ -35,24 +35,27 @@
 #ifndef __IntensityCurveInterface_h_
 #define __IntensityCurveInterface_h_
 
-#include <itkFunctionBase.h>
+#include <itkDataObject.h>
+#include <itkObjectFactory.h>
 #include <Registry.h>
+#include <SNAPEvents.h>
 
 /**
  * \class IntensityCurveInterface
  * \brief The base class for intensity mapping splines
  */
-class ITK_EXPORT IntensityCurveInterface : public itk::FunctionBase<float,float> {
+class ITK_EXPORT IntensityCurveInterface : public itk::DataObject
+{
 public:
 
   /** Standard class typedefs. */
   typedef IntensityCurveInterface Self;
-  typedef itk::FunctionBase<float,float> Superclass;
+  typedef itk::DataObject Superclass;
   typedef itk::SmartPointer<Self> Pointer;
   typedef itk::SmartPointer<const Self> ConstPointer;
 
   /** Run-time type information (and related methods). */
-  itkTypeMacro(IntensityCurveInterface,itk::FunctionBase);
+  itkTypeMacro(IntensityCurveInterface,itk::DataObject)
 
   /**
    * Initialize the spline with initial number of control points.
@@ -61,6 +64,14 @@ public:
   virtual void Initialize(unsigned int nControlPoints = 3) = 0;
 
   /**
+   * Reset to linear mapping, keeping number of points intact
+   */
+  virtual void Reset() { this->Initialize(this->GetControlPointCount()); }
+
+  // Check if the curve is in default state (linear from 0 to 1)
+  virtual bool IsInDefaultState() = 0;
+
+  /**
    * Get the value of a control point
    */
   virtual void GetControlPoint(unsigned int iControlPoint, 
@@ -96,6 +107,9 @@ public:
   /** Save the curve to a registry object */
   virtual void SaveToRegistry(Registry &registry) const = 0;
 
+  /** Evaluate the curve */
+  virtual float Evaluate(const float &t) const = 0;
+
 protected:
   IntensityCurveInterface(){};
   virtual ~IntensityCurveInterface(){};
diff --git a/Logic/Slicing/IntensityCurveVTK.cxx b/Logic/Slicing/IntensityCurveVTK.cxx
index f35b384..adb1b9b 100644
--- a/Logic/Slicing/IntensityCurveVTK.cxx
+++ b/Logic/Slicing/IntensityCurveVTK.cxx
@@ -76,6 +76,25 @@ IntensityCurveVTK
     }
 
   m_Spline->Compute();
+  this->Modified();
+}
+
+bool
+IntensityCurveVTK
+::IsInDefaultState()
+{
+  // Set up the intervals for the control points
+  float interval = 1.0 / (m_ControlPoints.size() - 1);
+  float t = 0;
+
+  for(unsigned int i=0;i<m_ControlPoints.size();i++,t+=interval)
+    {
+    const ControlPoint &cp = m_ControlPoints[i];
+    if(cp.t != t || cp.x != t)
+      return false;
+    }
+
+  return true;
 }
 
 void 
@@ -105,6 +124,7 @@ IntensityCurveVTK
     }
 
   m_Spline->Compute();
+  this->Modified();
 }
 
 bool 
@@ -155,6 +175,7 @@ IntensityCurveVTK
     }
 
   m_Spline->Compute();
+  this->Modified();
 }
 
 void
diff --git a/Logic/Slicing/IntensityCurveVTK.h b/Logic/Slicing/IntensityCurveVTK.h
index da0de42..ce74e93 100644
--- a/Logic/Slicing/IntensityCurveVTK.h
+++ b/Logic/Slicing/IntensityCurveVTK.h
@@ -54,10 +54,10 @@ public:
   typedef itk::SmartPointer<const Self> ConstPointer;
 
   /** Run-time type information (and related methods). */
-  itkTypeMacro(IntensityCurveVTK,IntensityCurveInterface);
+  itkTypeMacro(IntensityCurveVTK,IntensityCurveInterface)
 
   /** New method */
-  itkNewMacro(Self);
+  itkNewMacro(Self)
 
   // Defined in the parent class
   void Initialize(unsigned int nControlPoints = 3);
@@ -86,6 +86,9 @@ public:
   // Save the curve to a registry
   void SaveToRegistry(Registry &registry) const;
 
+  // Check if the curve is in default state (linear from 0 to 1)
+  bool IsInDefaultState();
+
 protected:
   IntensityCurveVTK();
   virtual ~IntensityCurveVTK();
diff --git a/Logic/Slicing/IntensityToColorLookupTableImageFilter.cxx b/Logic/Slicing/IntensityToColorLookupTableImageFilter.cxx
new file mode 100644
index 0000000..55d5bdb
--- /dev/null
+++ b/Logic/Slicing/IntensityToColorLookupTableImageFilter.cxx
@@ -0,0 +1,244 @@
+#include "IntensityToColorLookupTableImageFilter.h"
+#include "itkImageRegionIteratorWithIndex.h"
+
+#include "LookupTableTraits.h"
+#include "IntensityCurveInterface.h"
+#include "ColorMap.h"
+#include "itkImage.h"
+
+
+/* ===============================================================
+    AbstractLookupTableImageFilter implementation
+   =============================================================== */
+
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::AbstractLookupTableImageFilter()
+{
+  // By default not using a reference range
+  m_UseReferenceRange = false;
+  m_ImageMinInput = NULL;
+  m_ImageMaxInput = NULL;
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::SetImageMinInput(MinMaxObjectType *input)
+{
+  m_ImageMinInput = input;
+  this->SetInput("image_min", input);
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::SetImageMaxInput(MinMaxObjectType *input)
+{
+  m_ImageMaxInput = input;
+  this->SetInput("image_max", input);
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::SetReferenceIntensityRange(double min, double max)
+{
+  m_UseReferenceRange = true;
+  m_ReferenceMin = (InputComponentType) min;
+  m_ReferenceMax = (InputComponentType) max;
+  this->Modified();
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::RemoveReferenceIntensityRange()
+{
+  m_UseReferenceRange = false;
+  this->Modified();
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::GenerateOutputInformation()
+{
+  // Since this method could be called before the upstream pipeline has
+  // executed, we need to force a all to Update on the input min/max
+  m_ImageMinInput->Update();
+
+  LookupTableType *output = this->GetOutput();
+
+  // Use the type-specific traits to compute the range of the lookup table
+  typename LookupTableType::RegionType region =
+      LookupTableTraits<InputComponentType>::ComputeLUTRange(
+        m_ImageMinInput->Get(), m_ImageMaxInput->Get());
+
+  // TODO: remove
+  output->SetLargestPossibleRegion(region);
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::EnlargeOutputRequestedRegion(itk::DataObject *)
+{
+  LookupTableType *output = this->GetOutput();
+  output->SetRequestedRegion(output->GetLargestPossibleRegion());
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::GenerateInputRequestedRegion()
+{
+  // The input region is the whole image
+  InputImageType *input = const_cast<InputImageType *>(this->GetInput());
+  input->SetRequestedRegionToLargestPossibleRegion();
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::ThreadedGenerateData(const OutputImageRegionType &region,
+                       itk::ThreadIdType threadId)
+{
+  // Get the image max and min
+  InputComponentType imin = m_ImageMinInput->Get(), imax = m_ImageMaxInput->Get();
+
+  // Compute the mapping from LUT position to [0 1] range for the curve
+  float scale, shift;  
+  LookupTableTraits<InputComponentType>::ComputeLinearMappingToUnitInterval(
+        m_UseReferenceRange ? m_ReferenceMin : imin,
+        m_UseReferenceRange ? m_ReferenceMax : imax,
+        scale, shift);
+
+  // Do the actual computation of the cache
+  LookupTableType *output = this->GetOutput();
+  for(itk::ImageRegionIteratorWithIndex<LookupTableType> it(output, region);
+      !it.IsAtEnd(); ++it)
+    {
+    // Get the lookup value we are seeking
+    long pos = it.GetIndex()[0];
+
+    // Map the input value to range of 0 to 1
+    float inZeroOne = (pos - shift) * scale;
+
+    // Compute the intensity mapping
+    it.Set(this->ComputeLUTValue(inZeroOne));
+    }
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::SetFixedLookupTableRange(InputComponentType imin, InputComponentType imax)
+{
+  SmartPtr<MinMaxObjectType> omin = MinMaxObjectType::New();
+  omin->Set(imin);
+  this->SetImageMinInput(omin);
+
+  SmartPtr<MinMaxObjectType> omax = MinMaxObjectType::New();
+  omax->Set(imax);
+  this->SetImageMaxInput(omax);
+}
+
+
+/* ===============================================================
+    IntensityToColorLookupTableImageFilter implementation
+   =============================================================== */
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+typename IntensityToColorLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>::OutputPixelType
+IntensityToColorLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::ComputeLUTValue(float inZeroOne)
+{
+  // Apply the intensity curve
+  float outZeroOne = m_IntensityCurve->Evaluate(inZeroOne);
+
+  // Map the output to a RGBA pixel
+  return m_ColorMap->MapIndexToRGBA(outZeroOne);
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+IntensityToColorLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::SetIntensityCurve(IntensityCurveInterface *curve)
+{
+  m_IntensityCurve = curve;
+  this->SetInput("curve", curve);
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+IntensityToColorLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::SetColorMap(ColorMap *map)
+{
+  m_ColorMap = map;
+  this->SetInput("colormap", map);
+}
+
+
+
+/* ===============================================================
+    MultiComponentImageToScalarLookupTableImageFilter implementation
+   =============================================================== */
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+void
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::SetIntensityCurve(IntensityCurveInterface *curve)
+{
+  m_IntensityCurve = curve;
+  this->SetInput("curve", curve);
+}
+
+template<class TInputImage, class TOutputLUT, class TComponent>
+typename MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>::OutputPixelType
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+::ComputeLUTValue(float inZeroOne)
+{
+  // Compute the intensity mapping
+  float outZeroOne = m_IntensityCurve->Evaluate(inZeroOne);
+
+  // Map the output to a RGBA pixel
+  return static_cast<OutputPixelType>(255.0 * outZeroOne);
+}
+
+
+
+
+
+
+
+
+// Template instantiation
+#include "itkVectorImageToImageAdaptor.h"
+#include "VectorToScalarImageAccessor.h"
+
+typedef itk::Image<short, 3> GreyImageType;
+typedef itk::VectorImageToImageAdaptor<GreyType, 3> GreyComponentAdaptorType;
+typedef itk::Image<itk::RGBAPixel<unsigned char>, 1> LUTType;
+typedef itk::Image<unsigned char, 1> ScalarLUTType;
+typedef itk::Image<float, 3> FloatImageType;
+typedef itk::VectorImage<short, 3> AnatomicImageType;
+
+template class AbstractLookupTableImageFilter<GreyImageType, LUTType, GreyType>;
+template class AbstractLookupTableImageFilter<FloatImageType, LUTType, float>;
+template class AbstractLookupTableImageFilter<GreyComponentAdaptorType, LUTType, GreyType>;
+template class AbstractLookupTableImageFilter<GreyVectorMagnitudeImageAdaptor, LUTType, float>;
+template class AbstractLookupTableImageFilter<GreyVectorMaxImageAdaptor, LUTType, float>;
+template class AbstractLookupTableImageFilter<GreyVectorMeanImageAdaptor, LUTType, float>;
+template class AbstractLookupTableImageFilter<AnatomicImageType, ScalarLUTType, GreyType>;
+
+template class IntensityToColorLookupTableImageFilter<GreyImageType, LUTType>;
+template class IntensityToColorLookupTableImageFilter<FloatImageType, LUTType>;
+template class IntensityToColorLookupTableImageFilter<GreyComponentAdaptorType, LUTType>;
+template class IntensityToColorLookupTableImageFilter<GreyVectorMagnitudeImageAdaptor, LUTType>;
+template class IntensityToColorLookupTableImageFilter<GreyVectorMaxImageAdaptor, LUTType>;
+template class IntensityToColorLookupTableImageFilter<GreyVectorMeanImageAdaptor, LUTType>;
+
+template class MultiComponentImageToScalarLookupTableImageFilter<AnatomicImageType, ScalarLUTType>;
+
diff --git a/Logic/Slicing/IntensityToColorLookupTableImageFilter.h b/Logic/Slicing/IntensityToColorLookupTableImageFilter.h
new file mode 100644
index 0000000..09bc864
--- /dev/null
+++ b/Logic/Slicing/IntensityToColorLookupTableImageFilter.h
@@ -0,0 +1,190 @@
+#ifndef INTENSITYTOCOLORLOOKUPTABLEIMAGEFILTER_H
+#define INTENSITYTOCOLORLOOKUPTABLEIMAGEFILTER_H
+
+#include "SNAPCommon.h"
+#include <itkImageToImageFilter.h>
+#include <itkSimpleDataObjectDecorator.h>
+
+class ColorMap;
+class IntensityCurveInterface;
+
+/**
+ * This is a parent class for filters that generate a lookup table based on the
+ * intensity range of an input image. There are two subclasses in SNAP, one for
+ * LUTs that map input values to RGBA colors directly, and another that maps
+ * input values to RGB components. The class requires three inputs: the image,
+ * and objects representing the image min/max intensities. The image may be a
+ * vector image, a regular image, or an ImageAdaptor.
+ */
+template <class TInputImage, class TOutputLUT, class TComponent>
+class AbstractLookupTableImageFilter
+    : public itk::ImageToImageFilter<TInputImage, TOutputLUT>
+{
+public:
+
+  typedef AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+                                                                          Self;
+  typedef itk::ImageToImageFilter<TInputImage, TOutputLUT>          Superclass;
+  typedef SmartPtr<Self>                                               Pointer;
+  typedef SmartPtr<const Self>                                    ConstPointer;
+
+  typedef TInputImage                                          InputImageType;
+  typedef typename InputImageType::PixelType                   InputPixelType;
+  typedef TOutputLUT                                          LookupTableType;
+  typedef typename LookupTableType::PixelType                 OutputPixelType;
+
+  typedef typename Superclass::OutputImageRegionType    OutputImageRegionType;
+
+  // The type of the min/max inputs. The are usually InputPixelType, but may
+  // be different, i.e., for VectorImage it's InternalPixelType.
+  typedef TComponent                                       InputComponentType;
+  typedef itk::SimpleDataObjectDecorator<InputComponentType> MinMaxObjectType;
+
+  itkTypeMacro(AbstractLookupTableImageFilter, ImageToImageFilter)
+
+  /** Set the intensity remapping curve - for contrast adjustment */
+  virtual void SetIntensityCurve(IntensityCurveInterface *curve) = 0;
+
+  /**
+    One of the inputs to the filter is an object representing the minimum
+    value of the input image intensity range. This can be the output of an
+    itk::MinimumMaximumImageFilter, or it can just we a DataObject
+    encapsulating a constant value. The reason we use an object and not a
+    simple constant is to allow pipeline execution - for example recomputing
+    the minimum and maximum of an image, if necessary
+    */
+  void SetImageMinInput(MinMaxObjectType *input);
+
+  /** See notes for SetImageMinInput */
+  void SetImageMaxInput(MinMaxObjectType *input);
+
+  itkGetMacro(ImageMinInput, MinMaxObjectType *)
+  itkGetMacro(ImageMaxInput, MinMaxObjectType *)
+
+
+  /** Set intensity range to a pair of constants. This is useful when the
+    range of the lookup table will never change. This is an alternative to
+    calling SetImageMinInput() and SetImageMaxInput() */
+  void SetFixedLookupTableRange(InputComponentType imin, InputComponentType imax);
+
+  /**
+    It is possible to use a separate reference intensity range when mapping
+    raw intensities into the domain of the intensity curve. This is relevant
+    when working with images derived from another image.
+
+    TODO: this may not be necessary in the future
+    */
+  void SetReferenceIntensityRange(double min, double max);
+  void RemoveReferenceIntensityRange();
+
+
+  void GenerateOutputInformation();
+
+  void EnlargeOutputRequestedRegion(itk::DataObject *output);
+
+  void GenerateInputRequestedRegion();
+
+  void ThreadedGenerateData(const OutputImageRegionType &region,
+                            itk::ThreadIdType threadId);
+
+
+protected:
+
+  AbstractLookupTableImageFilter();
+  virtual ~AbstractLookupTableImageFilter() {}
+
+  // Things that affect the LUT computation
+  SmartPtr<MinMaxObjectType> m_ImageMinInput, m_ImageMaxInput;
+
+  // This method does the actual computation
+  virtual OutputPixelType ComputeLUTValue(float inZeroOne) = 0;
+
+  // Reference intensity range
+  InputComponentType m_ReferenceMin, m_ReferenceMax;
+
+  // Whether the reference intensity range is being used
+  bool m_UseReferenceRange;
+};
+
+/**
+  This filter is used to generate a color lookup table from an intensity curve,
+  color map, and information regarding the range of the input image. The actual
+  input image is not really used in the computation, but it should still be passed
+  in. The color lookup table is implemented as a 1-D image of RGBAPixel.
+  */
+template<class TInputImage, class TOutputLUT,
+         class TComponent = typename TInputImage::PixelType>
+class IntensityToColorLookupTableImageFilter
+    : public AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+{
+public:
+  typedef IntensityToColorLookupTableImageFilter<
+            TInputImage, TOutputLUT, TComponent>                          Self;
+  typedef AbstractLookupTableImageFilter<
+            TInputImage, TOutputLUT, TComponent>                    Superclass;
+  typedef SmartPtr<Self>                                               Pointer;
+  typedef SmartPtr<const Self>                                    ConstPointer;
+
+  typedef typename Superclass::OutputPixelType                 OutputPixelType;
+
+  itkTypeMacro(IntensityToColorLookupTableImageFilter,
+               AbstractLookupTableImageFilter)
+  itkNewMacro(Self)
+
+  /** Set the intensity remapping curve - for contrast adjustment */
+  void SetIntensityCurve(IntensityCurveInterface *curve);
+
+  irisGetMacro(IntensityCurve, IntensityCurveInterface *)
+
+  /** Set the color map - for mapping scalars to RGB space */
+  void SetColorMap(ColorMap *map);
+
+protected:
+
+  SmartPtr<IntensityCurveInterface> m_IntensityCurve;
+  SmartPtr<ColorMap> m_ColorMap;
+
+  virtual OutputPixelType ComputeLUTValue(float inZeroOne);
+};
+
+/**
+ * This filter creates a common lookup table shared by a set of input images.
+ * It is mainly used to map intensities in a multi-channel image to the
+ * unsigned char, before combining them into a RGBAPixel. The class admits
+ * any number of components.
+ * @see IntensityToColorLookupTableImageFilter
+ */
+template <class TInputImage, class TOutputLUT,
+          class TComponent = typename TInputImage::InternalPixelType>
+class MultiComponentImageToScalarLookupTableImageFilter
+    : public AbstractLookupTableImageFilter<TInputImage, TOutputLUT, TComponent>
+{
+public:
+  typedef MultiComponentImageToScalarLookupTableImageFilter<
+            TInputImage, TOutputLUT, TComponent>                          Self;
+  typedef AbstractLookupTableImageFilter<
+            TInputImage, TOutputLUT, TComponent>                    Superclass;
+  typedef SmartPtr<Self>                                               Pointer;
+  typedef SmartPtr<const Self>                                    ConstPointer;
+
+  typedef typename Superclass::OutputPixelType                 OutputPixelType;
+
+  itkTypeMacro(MultiComponentImageToScalarLookupTableImageFilter,
+               AbstractLookupTableImageFilter)
+  itkNewMacro(Self)
+
+  /** Set the intensity remapping curve - for contrast adjustment */
+  void SetIntensityCurve(IntensityCurveInterface *curve);
+
+  irisGetMacro(IntensityCurve, IntensityCurveInterface *)
+	
+protected:
+
+  SmartPtr<IntensityCurveInterface> m_IntensityCurve;
+
+  virtual OutputPixelType ComputeLUTValue(float inZeroOne);
+};
+
+
+
+#endif // INTENSITYTOCOLORLOOKUPTABLEIMAGEFILTER_H
diff --git a/Logic/Slicing/LookupTableIntensityMappingFilter.cxx b/Logic/Slicing/LookupTableIntensityMappingFilter.cxx
new file mode 100644
index 0000000..a4caa90
--- /dev/null
+++ b/Logic/Slicing/LookupTableIntensityMappingFilter.cxx
@@ -0,0 +1,93 @@
+#include "LookupTableIntensityMappingFilter.h"
+#include <itkImageRegionIterator.h>
+#include <itkRGBAPixel.h>
+#include "LookupTableTraits.h"
+
+template<class TInputImage, class TOutputImage>
+LookupTableIntensityMappingFilter<TInputImage, TOutputImage>
+::LookupTableIntensityMappingFilter()
+{
+  // The image and the LUT are inputs
+  this->SetNumberOfIndexedInputs(4);
+}
+
+template<class TInputImage, class TOutputImage>
+void
+LookupTableIntensityMappingFilter<TInputImage, TOutputImage>
+::SetLookupTable(LookupTableType *lut)
+{
+  m_LookupTable = lut;
+  this->SetNthInput(1, lut);
+}
+
+template<class TInputImage, class TOutputImage>
+void
+LookupTableIntensityMappingFilter<TInputImage, TOutputImage>
+::SetImageMinInput(InputPixelObject *input)
+{
+  m_InputMin = input;
+  this->SetNthInput(2, input);
+}
+
+template<class TInputImage, class TOutputImage>
+void
+LookupTableIntensityMappingFilter<TInputImage, TOutputImage>
+::SetImageMaxInput(InputPixelObject *input)
+{
+  m_InputMax = input;
+  this->SetNthInput(3, input);
+}
+
+template<class TInputImage, class TOutputImage>
+void
+LookupTableIntensityMappingFilter<TInputImage, TOutputImage>
+::ThreadedGenerateData(const OutputImageRegionType &region,
+                       itk::ThreadIdType threadId)
+{
+  // Get the input, output and the LUT
+  const InputImageType *input = this->GetInput();
+  OutputImageType *output = this->GetOutput(0);
+
+  // Get the pointer to the zero value in the LUT
+  OutputPixelType *lutp =
+      m_LookupTable->GetBufferPointer()
+      - m_LookupTable->GetLargestPossibleRegion().GetIndex()[0];
+
+  // Compute the shift and scale factors that map the input values into
+  // the LUT values. These are ignored for integral pixel types, but used
+  // for floating point types
+  float lutScale;
+  InputPixelType lutShift;
+  LookupTableTraits<InputPixelType>::ComputeLinearMappingToLUT(
+        m_InputMin->Get(), m_InputMax->Get(), lutScale, lutShift);
+
+  // Define the iterators
+  itk::ImageRegionConstIterator<TInputImage> inputIt(input, region);
+  itk::ImageRegionIterator<TOutputImage> outputIt(output, region);
+
+  // Perform the intensity mapping using the LUT (no bounds checking!)
+  while( !inputIt.IsAtEnd() )
+    {
+    // Get the input intensity
+    InputPixelType xin = inputIt.Get();
+
+    // Find the corresponding LUT offset
+    int lut_offset = LookupTableTraits<InputPixelType>::ComputeLUTOffset(
+          lutScale, lutShift, xin);
+
+    OutputPixelType xout = *(lutp + lut_offset);
+    outputIt.Set(xout);
+
+    ++inputIt;
+    ++outputIt;
+    }
+}
+
+// Declare specific instances that will exist
+template class LookupTableIntensityMappingFilter<
+    itk::Image<short, 2>, itk::Image< itk::RGBAPixel<unsigned char> > >;
+
+template class LookupTableIntensityMappingFilter<
+    itk::Image<float, 2>, itk::Image< itk::RGBAPixel<unsigned char> > >;
+
+
diff --git a/Logic/Slicing/LookupTableIntensityMappingFilter.h b/Logic/Slicing/LookupTableIntensityMappingFilter.h
new file mode 100644
index 0000000..1ea3d36
--- /dev/null
+++ b/Logic/Slicing/LookupTableIntensityMappingFilter.h
@@ -0,0 +1,63 @@
+#ifndef LOOKUPTABLEINTENSITYMAPPINGFILTER_H
+#define LOOKUPTABLEINTENSITYMAPPINGFILTER_H
+
+#include "SNAPCommon.h"
+#include <itkImageToImageFilter.h>
+#include <itkSimpleDataObjectDecorator.h>
+
+
+
+/**
+  This ITK filter uses a lookup table to map image intensities. The input
+  image should be of an integral type.
+  */
+template<class TInputImage, class TOutputImage>
+class LookupTableIntensityMappingFilter :
+    public itk::ImageToImageFilter<TInputImage, TOutputImage>
+{
+public:
+
+  typedef LookupTableIntensityMappingFilter<TInputImage, TOutputImage>   Self;
+  typedef itk::ImageToImageFilter<TInputImage, TOutputImage>       Superclass;
+  typedef itk::SmartPointer<Self>                                     Pointer;
+  typedef itk::SmartPointer<const Self>                          ConstPointer;
+
+  typedef TInputImage                                          InputImageType;
+  typedef typename InputImageType::PixelType                   InputPixelType;
+  typedef TOutputImage                                        OutputImageType;
+  typedef typename OutputImageType::PixelType                 OutputPixelType;
+
+  typedef itk::Image<OutputPixelType, 1>                      LookupTableType;
+  typedef typename Superclass::OutputImageRegionType    OutputImageRegionType;
+
+  typedef itk::SimpleDataObjectDecorator<InputPixelType>     InputPixelObject;
+
+  itkTypeMacro(LookupTableIntensityMappingFilter, ImageToImageFilter)
+  itkNewMacro(Self)
+
+  /** Set the intensity remapping curve - for contrast adjustment */
+  void SetLookupTable(LookupTableType *lut);
+
+  /**
+   * Set the range of the input image (these outputs are generated by the
+   * MaximumMinimumImageFilter)
+   */
+  void SetImageMinInput(InputPixelObject *input);
+  void SetImageMaxInput(InputPixelObject *input);
+
+  /** The actual work */
+  void ThreadedGenerateData(const OutputImageRegionType &region,
+                            itk::ThreadIdType threadId);
+
+protected:
+
+  LookupTableIntensityMappingFilter();
+  virtual ~LookupTableIntensityMappingFilter() {}
+
+  SmartPtr<InputPixelObject> m_InputMin, m_InputMax;
+
+  SmartPtr<LookupTableType> m_LookupTable;
+};
+
+
+#endif // LOOKUPTABLEINTENSITYMAPPINGFILTER_H
diff --git a/Logic/Slicing/LookupTableTraits.h b/Logic/Slicing/LookupTableTraits.h
new file mode 100644
index 0000000..ae7a4d6
--- /dev/null
+++ b/Logic/Slicing/LookupTableTraits.h
@@ -0,0 +1,114 @@
+#ifndef LOOKUPTABLETRAITS_H
+#define LOOKUPTABLETRAITS_H
+
+/**
+ * This is a traits class that modifies the behavior of this filter for
+ * integral and non-integral data types. For data types whose range is
+ * small (char/short/uchar/ushort), the lookup table assigns a color to
+ * each possible value of the input image. For data types whose range is
+ * large (int, float, double, etc), the lookup table allocates 2^16 values
+ * into which the image intensities are scaled.
+ */
+template <class TPixel>
+class SmallIntegralTypeLookupTableTraits
+{
+public:
+  typedef itk::ImageRegion<1> LUTRange;
+  static LUTRange ComputeLUTRange(TPixel imin, TPixel imax)
+  {
+    LUTRange range;
+    range.SetIndex(0, imin);
+    range.SetSize(0, 1 + imax - imin);
+    return range;
+  }
+
+  static void ComputeLinearMappingToUnitInterval(
+      TPixel imin, TPixel imax,
+      float &scale, float &shift)
+  {
+    shift = imin;
+    scale = 1.0f / (imax - imin);
+  }
+
+  static void ComputeLinearMappingToLUT(
+      TPixel imin, TPixel imax,
+      float &scale, TPixel &shift)
+  {
+    scale = 1.0;
+    shift = 0;
+  }
+
+  // Compute offset into the LUT for an input value
+  static int ComputeLUTOffset(float itkNotUsed(scale),
+                              TPixel itkNotUsed(shift),
+                              TPixel value)
+  {
+    return value;
+  }
+
+protected:
+
+};
+
+/**
+ * This is the version of the above used for types float and double. These
+ * types are always mapped to some fixed range of values. We fix this range
+ * of values at 10000 - something completely arbitrary.
+ */
+template <class TPixel>
+class RealTypeLookupTableTraits
+{
+public:
+  enum { LUT_MIN = 0, LUT_MAX = 10000 };
+  typedef itk::ImageRegion<1> LUTRange;
+  static LUTRange ComputeLUTRange(TPixel imin, TPixel imax)
+  {
+    LUTRange range;
+    range.SetIndex(0, LUT_MIN);
+    range.SetSize(0, 1 + LUT_MAX - LUT_MIN);
+    return range;
+  }
+
+  static void ComputeLinearMappingToUnitInterval(
+      TPixel, TPixel, float &scale, float &shift)
+  {
+    scale = 1.0f / (LUT_MAX - LUT_MIN);
+    shift = LUT_MIN;
+  }
+
+  static void ComputeLinearMappingToLUT(
+      TPixel imin, TPixel imax,
+      float &scale, TPixel &shift)
+  {
+    scale = (LUT_MAX - LUT_MIN) * 1.0 / (imax - imin);
+    shift = imin;
+  }
+
+  // Compute offset into the LUT for an input value
+  static int ComputeLUTOffset(float scale, TPixel shift, TPixel value)
+  {
+    return static_cast<int>((value - shift) * scale);
+  }
+
+
+};
+
+/**
+ * Link each C type to the corresponding traits
+ */
+template <typename T> class LookupTableTraits
+{
+};
+
+#define DECL_LUT_TRAITS(type,traits) \
+  template<> class LookupTableTraits<type> : public traits<type> {};
+
+DECL_LUT_TRAITS(float,          RealTypeLookupTableTraits)
+DECL_LUT_TRAITS(double,         RealTypeLookupTableTraits)
+DECL_LUT_TRAITS(short,          SmallIntegralTypeLookupTableTraits)
+DECL_LUT_TRAITS(unsigned short, SmallIntegralTypeLookupTableTraits)
+DECL_LUT_TRAITS(char,           SmallIntegralTypeLookupTableTraits)
+DECL_LUT_TRAITS(unsigned char,  SmallIntegralTypeLookupTableTraits)
+
+
+#endif // LOOKUPTABLETRAITS_H
diff --git a/Logic/Slicing/MultiComponentImageToScalarLookupTableImageFilter.cxx b/Logic/Slicing/MultiComponentImageToScalarLookupTableImageFilter.cxx
new file mode 100644
index 0000000..5863314
--- /dev/null
+++ b/Logic/Slicing/MultiComponentImageToScalarLookupTableImageFilter.cxx
@@ -0,0 +1,136 @@
+#include "MultiComponentImageToScalarLookupTableImageFilter.h"
+#include "itkVectorImage.h"
+#include "itkImageRegionIteratorWithIndex.h"
+#include "IntensityCurveInterface.h"
+
+template<class TInputImage, class TOutputLUT>
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT>
+::MultiComponentImageToScalarLookupTableImageFilter()
+{
+
+}
+
+template<class TInputImage, class TOutputLUT>
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT>
+::~MultiComponentImageToScalarLookupTableImageFilter()
+{
+
+}
+
+template<class TInputImage, class TOutputLUT>
+void
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT>
+::SetMultiComponentImage(InputImageType *image)
+{
+  // Figure out how many components we have
+  this->SetNumberOfIndexedInputs(4);
+
+  // Set the first input
+  this->SetNthInput(0, image);
+}
+
+template<class TInputImage, class TOutputLUT>
+void
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT>
+::SetIntensityCurve(IntensityCurveInterface *curve)
+{
+  m_IntensityCurve = curve;
+  this->SetNthInput(1, curve);
+}
+
+template<class TInputImage, class TOutputLUT>
+void
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT>
+::SetImageMinInput(InputPixelObject *input)
+{
+  m_InputMin = input;
+  this->SetNthInput(2, input);
+}
+
+template<class TInputImage, class TOutputLUT>
+void
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT>
+::SetImageMaxInput(InputPixelObject *input)
+{
+  m_InputMax = input;
+  this->SetNthInput(3, input);
+}
+
+template<class TInputImage, class TOutputLUT>
+void
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT>
+::GenerateOutputInformation()
+{
+  // We need to compute a global max/min
+  InputComponentType gmin = m_InputMin.Get();
+  InputComponentType gmax = m_InputMax.Get();
+
+  LookupTableType *output = this->GetOutput();
+  typename LookupTableType::IndexType idx = {{gmin}};
+  typename LookupTableType::SizeType sz = {{1 + gmax - gmin}};
+  typename LookupTableType::RegionType region(idx, sz);
+  output->SetLargestPossibleRegion(region);
+}
+
+template<class TInputImage, class TOutputLUT>
+void
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT>
+::EnlargeOutputRequestedRegion(itk::DataObject *)
+{
+  LookupTableType *output = this->GetOutput();
+  output->SetRequestedRegion(output->GetLargestPossibleRegion());
+}
+
+template<class TInputImage, class TOutputLUT>
+void
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT>
+::GenerateInputRequestedRegion()
+{
+  // The input region is the whole image
+  InputImageType *input = const_cast<InputImageType *>(this->GetInput());
+  input->SetRequestedRegionToLargestPossibleRegion();
+}
+
+
+template<class TInputImage, class TOutputLUT>
+void
+MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT>
+::ThreadedGenerateData(const OutputImageRegionType &region,
+                       itk::ThreadIdType threadId)
+{
+  if(threadId == 0)
+    std::cout << "Computing LUT " << region << std::endl;
+
+  InputComponentType gmin = m_InputMin.Get();
+  InputComponentType gmax = m_InputMax.Get();
+
+  // Set the intensity mapping for the functor
+  float scale, shift;
+  shift = gmin;
+  scale = 1.0f / (gmax - gmin);
+
+  // Do the actual computation of the cache
+  LookupTableType *output = this->GetOutput();
+  for(itk::ImageRegionIteratorWithIndex<LookupTableType> it(output, region);
+      !it.IsAtEnd(); ++it)
+    {
+    // Get the lookup value we are seeking
+    long pos = it.GetIndex()[0];
+
+    // Map the input value to range of 0 to 1
+    float inZeroOne = (pos - shift) * scale;
+
+    // Compute the intensity mapping
+    float outZeroOne = m_IntensityCurve->Evaluate(inZeroOne);
+
+    // Map the output to a RGBA pixel
+    it.Set(static_cast<OutputPixelType>(255.0 * outZeroOne));
+    }
+}
+
+// Template instantiation
+typedef itk::VectorImage<short, 3> AnatomicImageType;
+typedef itk::Image<unsigned char, 1> LUTType;
+template class MultiComponentImageToScalarLookupTableImageFilter<AnatomicImageType, LUTType>;
+
+
diff --git a/Logic/Slicing/MultiComponentImageToScalarLookupTableImageFilter.h b/Logic/Slicing/MultiComponentImageToScalarLookupTableImageFilter.h
new file mode 100644
index 0000000..02068b0
--- /dev/null
+++ b/Logic/Slicing/MultiComponentImageToScalarLookupTableImageFilter.h
@@ -0,0 +1,81 @@
+#ifndef MULTICOMPONENTIMAGETOSCALARLOOKUPTABLEIMAGEFILTER_H
+#define MULTICOMPONENTIMAGETOSCALARLOOKUPTABLEIMAGEFILTER_H
+
+#include "SNAPCommon.h"
+#include <itkImageToImageFilter.h>
+#include <itkSimpleDataObjectDecorator.h>
+
+class IntensityCurveInterface;
+
+/**
+ * This filter creates a common lookup table shared by a set of input images.
+ * It is mainly used to map intensities in a multi-channel image to the
+ * unsigned char, before combining them into a RGBAPixel. The class admits
+ * any number of components.
+ * @see IntensityToColorLookupTableImageFilter
+ */
+template <class TInputImage, class TOutputLUT>
+class MultiComponentImageToScalarLookupTableImageFilter
+    : public itk::ImageToImageFilter<TInputImage, TOutputLUT>
+{
+public:
+
+  typedef MultiComponentImageToScalarLookupTableImageFilter<TInputImage, TOutputLUT>
+                                                                          Self;
+  typedef itk::ImageToImageFilter<TInputImage, TOutputLUT>          Superclass;
+  typedef SmartPtr<Self>                                               Pointer;
+  typedef SmartPtr<const Self>                                    ConstPointer;
+
+  typedef TInputImage                                          InputImageType;
+  typedef typename InputImageType::InternalPixelType       InputComponentType;
+  typedef TOutputLUT                                          LookupTableType;
+  typedef typename LookupTableType::PixelType                 OutputPixelType;
+
+  typedef itk::SimpleDataObjectDecorator<InputComponentType>
+                                                         InputComponentObject;
+  typedef typename Superclass::OutputImageRegionType    OutputImageRegionType;
+
+  itkTypeMacro(IntensityToColorLookupTableImageFilter, ImageToImageFilter)
+  itkNewMacro(Self)
+
+  /** Set the intensity remapping curve - for contrast adjustment */
+  void SetIntensityCurve(IntensityCurveInterface *curve);
+
+  /** Get the intensity curve */
+  irisGetMacro(IntensityCurve, IntensityCurveInterface *)
+
+  /** Set the main input - this should be a multi-component image. This
+   * should be set before all of the other inputs */
+  void SetMultiComponentImage(InputImageType *image);
+
+  /**
+    One of the inputs to the filter is an object representing the minimum
+    value of the input image intensity range over all the components.
+    */
+  void SetImageMinInput(InputPixelObject *input);
+
+  /** See notes for SetImageMinInput */
+  void SetImageMaxInput(InputPixelObject *input);
+
+  void GenerateOutputInformation();
+
+  void EnlargeOutputRequestedRegion(itk::DataObject *output);
+
+  void GenerateInputRequestedRegion();
+
+  void ThreadedGenerateData(const OutputImageRegionType &region,
+                            itk::ThreadIdType threadId);
+
+protected:
+
+  MultiComponentImageToScalarLookupTableImageFilter();
+  ~MultiComponentImageToScalarLookupTableImageFilter();
+
+  // Things that affect the LUT computation
+  SmartPtr<IntensityCurveInterface> m_IntensityCurve;
+
+  // Overall min/max over all the components
+  SmartPtr<InputPixelObject> m_InputMin, m_InputMax;
+};
+
+#endif // MULTICOMPONENTIMAGETOSCALARLOOKUPTABLEIMAGEFILTER_H
diff --git a/Logic/Slicing/RGBALookupTableIntensityMappingFilter.cxx b/Logic/Slicing/RGBALookupTableIntensityMappingFilter.cxx
new file mode 100644
index 0000000..bbd62e8
--- /dev/null
+++ b/Logic/Slicing/RGBALookupTableIntensityMappingFilter.cxx
@@ -0,0 +1,66 @@
+#include "RGBALookupTableIntensityMappingFilter.h"
+#include "itkImageRegionIterator.h"
+
+template<class TInputImage>
+RGBALookupTableIntensityMappingFilter<TInputImage>
+::RGBALookupTableIntensityMappingFilter()
+{
+  // Multiple images and the LUT are inputs
+  this->SetNumberOfIndexedInputs(4);
+}
+
+template<class TInputImage>
+void
+RGBALookupTableIntensityMappingFilter<TInputImage>
+::SetLookupTable(LookupTableType *lut)
+{
+  m_LookupTable = lut;
+  this->SetNthInput(3, lut);
+}
+
+template<class TInputImage>
+void
+RGBALookupTableIntensityMappingFilter<TInputImage>
+::ThreadedGenerateData(const OutputImageRegionType &region,
+                       itk::ThreadIdType threadId)
+{
+  // Get all the inputs
+  std::vector<const InputImageType *> inputs(3);
+  for(int d = 0; d < 3; d++)
+    inputs[d] = this->GetInput(d);
+
+  // Get the output
+  OutputImageType *output = this->GetOutput(0);
+
+  // Get the pointer to the zero value in the LUT
+  OutputComponentType *lutp =
+      m_LookupTable->GetBufferPointer()
+      - m_LookupTable->GetLargestPossibleRegion().GetIndex()[0];
+
+  // Define the iterators
+  typedef itk::ImageRegionConstIterator<InputImageType> InputIteratorType;
+  std::vector<InputIteratorType> inputIt;
+  for(int d = 0; d < 3; d++)
+    inputIt.push_back(InputIteratorType(inputs[d], region));
+  itk::ImageRegionIterator<OutputImageType> outputIt(output, region);
+
+  // Perform the intensity mapping using the LUT (no bounds checking!)
+  while( !outputIt.IsAtEnd() )
+    {
+    OutputPixelType xout;
+    for(int d = 0; d < 3; d++)
+      {
+      InputPixelType xin = inputIt[d].Get();
+      xout[d] = *(lutp + xin);
+      ++inputIt[d];
+      }
+
+    xout[3] = 255; // alpha = 1
+    outputIt.Set(xout);
+    ++outputIt;
+    }
+}
+
+// Declare specific instances that will exist
+template class RGBALookupTableIntensityMappingFilter< itk::Image<short, 2> >;
+
diff --git a/Logic/Slicing/RGBALookupTableIntensityMappingFilter.h b/Logic/Slicing/RGBALookupTableIntensityMappingFilter.h
new file mode 100644
index 0000000..6d98b09
--- /dev/null
+++ b/Logic/Slicing/RGBALookupTableIntensityMappingFilter.h
@@ -0,0 +1,55 @@
+#ifndef MULTICHANNELLUTINTENSITYMAPPINGFILTER_H
+#define MULTICHANNELLUTINTENSITYMAPPINGFILTER_H
+
+#include "SNAPCommon.h"
+#include "itkRGBAPixel.h"
+#include <itkImageToImageFilter.h>
+
+
+/**
+ * This filter takes multiple input channels and a common lookup table, and
+ * generates an image of pixels of a certain vector type, e.g., RGBAPixel.
+ */
+template<class TInputImage>
+class RGBALookupTableIntensityMappingFilter :
+    public itk::ImageToImageFilter<TInputImage,
+                                   itk::Image<itk::RGBAPixel<unsigned char>, 2> >
+{
+public:
+
+  typedef typename itk::RGBAPixel<unsigned char>              OutputPixelType;
+  typedef itk::Image<OutputPixelType, 2>                      OutputImageType;
+
+  typedef RGBALookupTableIntensityMappingFilter<TInputImage>             Self;
+  typedef itk::ImageToImageFilter<TInputImage, OutputImageType>    Superclass;
+  typedef itk::SmartPointer<Self>                                     Pointer;
+  typedef itk::SmartPointer<const Self>                          ConstPointer;
+
+  typedef TInputImage                                          InputImageType;
+  typedef typename InputImageType::PixelType                   InputPixelType;
+
+  typedef typename OutputPixelType::ComponentType         OutputComponentType;
+
+  typedef itk::Image<OutputComponentType, 1>                  LookupTableType;
+  typedef typename Superclass::OutputImageRegionType    OutputImageRegionType;
+
+  itkTypeMacro(RGBALookupTableIntensityMappingFilter, ImageToImageFilter)
+  itkNewMacro(Self)
+
+  /** Set the intensity remapping curve - for contrast adjustment */
+  void SetLookupTable(LookupTableType *lut);
+
+  /** The actual work */
+  void ThreadedGenerateData(const OutputImageRegionType &region,
+                            itk::ThreadIdType threadId);
+
+protected:
+
+  RGBALookupTableIntensityMappingFilter();
+  virtual ~RGBALookupTableIntensityMappingFilter() {}
+
+  SmartPtr<LookupTableType> m_LookupTable;
+};
+
+
+#endif // MULTICHANNELLUTINTENSITYMAPPINGFILTER_H
diff --git a/Logic/Slicing/UnaryFunctorCache.h b/Logic/Slicing/UnaryFunctorCache.h
deleted file mode 100644
index 1b8c7b2..0000000
--- a/Logic/Slicing/UnaryFunctorCache.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: UnaryFunctorCache.h,v $
-  Language:  C++
-  Date:      $Date: 2009/09/16 20:03:13 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __UnaryFunctorCache_h_
-#define __UnaryFunctorCache_h_
-
-#include <assert.h>
-#include <stdio.h>
-
-#include "SNAPCommon.h"
-#include "itkMacro.h"
-#include "itkProcessObject.h"
-
-// Forward references
-// template <class TInput, class TOutput, class TFunctor> class UnaryFunctorCache;
-template <class TInput, class TOutput, class TFunctor> 
-  class CachingUnaryFunctor;
-
-/**
- * \class UnaryFunctorCache
- * \brief A cache for unary functors operating on types like short and char.
- *
- * This object wraps around a Functor and remembers the output values for 
- * the input values that is receives.  Do not use this class with non-integral
- * types and with types like int and long, or you will run out of memory!
- */
-template <class TInput, class TOutput, class TFunctor> 
-class ITK_EXPORT UnaryFunctorCache : public itk::Object
-{
-public:
-
-  /** Standard class typedefs. */
-  typedef UnaryFunctorCache Self;
-  typedef itk::Object Superclass;
-  typedef itk::SmartPointer<Self> Pointer;
-  typedef itk::SmartPointer<const Self> ConstPointer;
-
-  // Caching functor typedef
-  typedef CachingUnaryFunctor<TInput,TOutput,TFunctor> CachingFunctor;
-
-  /** New macro */
-  itkNewMacro(Self);
-
-  /** Run-time type information (and related methods). */
-  itkTypeMacro(UnaryFunctorCache,itk::Object);
-
-  /** Evaluate the function using cache lookup */
-  TOutput Evaluate(const TInput &in) 
-    {
-    if(m_Modified)
-      this->ComputeCache();
-    return m_Cache[in - m_CacheBegin];
-    }
-
-  /**
-   * Set the function instance to call evaluate on
-   */
-  void SetInputFunctor(TFunctor *functor)
-    {
-    this->m_InputFunctor = functor;
-    m_Modified = true;
-    }
-
-  /**
-   * Get the function instance
-   */
-  irisGetMacro(InputFunctor,TFunctor *);
-
-  /**
-   * Set the evaluation bounds, if you use these and these are small enough,
-   * you can use int or long as template parameters.
-   */
-  void SetEvaluationRange(TInput begin, TInput end) 
-  {
-    m_CacheBegin = begin;
-
-    // This code makes sure that if 'end' is the maximum value of TInput type, 
-    // the length is still valid
-    m_CacheLength = end;
-    m_CacheLength += 1;
-    m_CacheLength -= begin;
-
-    m_Modified = true;
-  }
-
-  /** Compute the cache */
-  void ComputeCache();
-
-  /**
-   * This method returns the lightweight functor (it can be copied)
-   */
-  irisGetMacro(CachingFunctor,const CachingFunctor &);
-
-protected:
-
-  UnaryFunctorCache();
-  virtual ~UnaryFunctorCache();
-  void PrintSelf(std::ostream &s, itk::Indent indent) const;
-
-  /**
-   * The function being cached
-   */
-  TFunctor *m_InputFunctor;
-
-  /**
-   * The storage for the cache
-   */
-  TOutput *m_Cache;
-
-  /**
-   * The bounds of the cache
-   */
-  TInput m_CacheBegin;
-  
-  /** The length of the cache */
-  unsigned int m_CacheLength, m_CacheAllocatedLength;
-  bool m_Modified;
-
-
-  /**
-   * The functor
-   */
-  CachingUnaryFunctor<TInput,TOutput,TFunctor> m_CachingFunctor;
-};
-
-/**
- * \class CachingUnaryFunctor
- * \brief A functor that works with UnaryFunctorCache to return precomputed 
- * values
- */
-template <class TInput, class TOutput, class TFunctor> 
-class CachingUnaryFunctor 
-{
-public:
-  // Typedef to the cache that updates this object
-  typedef CachingUnaryFunctor<TInput,TOutput,TFunctor> Self;
-  typedef UnaryFunctorCache<TInput,TOutput,TFunctor> CacheType;
-  typedef typename itk::SmartPointer<CacheType> CachePointer;
-
-  /** Perform an evaluation using the cache */
-  TOutput operator()(const TInput &in) { return m_Parent->Evaluate(in); }
-
-  /** Initialize with a cache object */
-  CachingUnaryFunctor(CacheType *parent) 
-    { m_Parent = parent; }
-
-  /** Default constructor */
-  CachingUnaryFunctor() 
-    { m_Parent = NULL; }
-
-  /** Comparison operator necessitated by ITK */
-  bool operator == (const Self &z) const 
-    { return m_Parent == z.m_Parent; }
-
-  /** Comparison operator necessitated by ITK */
-  bool operator != (const Self &z) const 
-    { return !(*this == z); }
-
-private:
-  /** Pointer to the cache */
-  CachePointer m_Parent;
-};
-
-#ifndef ITK_MANUAL_INSTANTIATION
-#include "UnaryFunctorCache.txx"
-#endif
-
-#endif // __UnaryFunctorCache_h_
diff --git a/Logic/Slicing/UnaryFunctorCache.txx b/Logic/Slicing/UnaryFunctorCache.txx
deleted file mode 100644
index 4885865..0000000
--- a/Logic/Slicing/UnaryFunctorCache.txx
+++ /dev/null
@@ -1,103 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: UnaryFunctorCache.txx,v $
-  Language:  C++
-  Date:      $Date: 2009/09/19 07:47:03 $
-  Version:   $Revision: 1.5 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "UnaryFunctorCache.h"
-#include "itkSimpleFastMutexLock.h"
-
-template <class TInput, class TOutput, class TFunctor>
-UnaryFunctorCache<TInput,TOutput,TFunctor>
-::UnaryFunctorCache() 
-: m_CachingFunctor(this)
-{
-  m_InputFunctor = NULL;
-  m_Cache = NULL;
-  m_CacheBegin = 0;
-  m_CacheLength = 0;
-  m_CacheAllocatedLength = 0;
-  m_Modified = false;
-}
-
-template <class TInput, class TOutput, class TFunctor>
-UnaryFunctorCache<TInput,TOutput,TFunctor>
-::~UnaryFunctorCache() 
-{
-  if(m_Cache)
-    delete[] m_Cache;
-}
-
-template <class TInput, class TOutput, class TFunctor>
-void 
-UnaryFunctorCache<TInput,TOutput,TFunctor>
-::ComputeCache() 
-{
-  // Can't have this running in a thread
-  static itk::SimpleFastMutexLock mutex;
-  mutex.Lock();
-
-  // Functor must be declared and cache length must be non-zero
-  assert(m_InputFunctor && m_CacheLength > 0);
-
-  // Allocate the cache, but only if the length changed
-  if(m_CacheAllocatedLength != m_CacheLength)
-    {
-    if(m_Cache) 
-      delete m_Cache;
-    m_Cache = new TOutput[m_CacheLength];
-    m_CacheAllocatedLength = m_CacheLength;
-    }
-    
-  // Compute the cache elements
-  int iFunc = m_CacheBegin;
-  for(unsigned int iCache = 0; iCache < m_CacheLength; iCache++)
-    {
-    m_Cache[iCache] = (*m_InputFunctor)(iFunc++);
-    }
-
-  m_Modified = false;
-
-  // Back to thread safety
-  mutex.Unlock();
-}
-
-template <class TInput, class TOutput, class TFunctor>
-void 
-UnaryFunctorCache<TInput,TOutput,TFunctor>
-::PrintSelf(std::ostream &os, itk::Indent indent) const
-{
-  Superclass::PrintSelf(os, indent);
-
-  os << indent << "Cache Start: " << m_CacheBegin << std::endl;
-  os << indent << "Cache Length: " << m_CacheLength << std::endl;
-}
-
diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt
index 06db427..6515d90 100644
--- a/ReleaseNotes.txt
+++ b/ReleaseNotes.txt
@@ -1,21 +1,255 @@
 ======================================
  InsightSNAP Release Notes
- Version 2.2.0
+ Version 3.2.0
 ======================================
 
-
 -----------------
 1. New Features
 -----------------
 
-1.1. New in Version 2.2.0
+1.1. New in Version 3.2.0
+----------------------------------------------
+
+The main new feature introduced in this release is supervised classification.
+The release also is built against Qt5 (3.0 used Qt4.8), which resulted in a lot
+of changes to compilation and packaging. Quite a few bugs have been fixed and
+the release should be more stable than 3.0.
+
+1.1.1. New functionality in this release
+
+ -  Added a supervised classification presegmentation mode. This mode allows
+    the user to compute the speed image by marking examples of two or more
+    tissue classes in an image with the paintbrush or polygon tools. The mode
+    works with multi-component data and multiple image layers.
+
+ -  Redesigned the semi-automatic segmentation GUI to be simpler to use. Now
+    the presegmentation can be done without bringing up a separate dialog.
+    Also the speed image is immediately computed for most presegmentation
+    modes. Overall, semi-automatic segmentation should be much easier to use
+    than in the past.
+
+ -  ITK-SNAP can now read 4D datasets. Previously such datasets would have to
+    be converted to a multi-component 3D dataset by the user. Now working with
+    dynamic datasets is much easier.
+
+ -  Added a label palette control for faster selection of labels
+
+ -  Added a 'flip' button for the 3D scalpel tool
+
+ -  Added support for syncing camera state between multiple SNAP sessions
+
+ -  Significantly improved behavior of open/save dialogs throughout the code.
+    All dialogs now use the same code and open in a sensible place.
+
+ -  Added option to auto-adjust image contrast on load
+
+ -  Improved volumes & statistics computation speed and display formatting
+
+
+1.1.2. Bug Fixes
+ 
+ -  Fixed a bug with small bubbles not growing in snake mode.
+
+ -  Refactored the DICOM input code and fixed several errors in the process.
+
+ -  Fixed numerous problems on Retina displays
+
+ -  Modified the clustering code to use Eigendecomposition for increased
+    robusness, particularly when applied to binary and multi-label images.
+
+ -  Fixed several dozen smaller bugs
+
+
+1.1.3. Programmatic Improvements
+
+ -  Migrated to Qt5 as well as up to date versions of ITK (4.5) and VTK (6.1)
+
+ -  Added scripted GUI testing functionality. This allows interactions to be
+    recorded and played back on different platforms and is great for
+    regression testing. Four tests are in this release, and more will be
+    developed soon.
+
+
+
+1.2. New in Version 3.0.0
+----------------------------------------------
+
+This is a major new release of ITK-SNAP. The user interface has been completely
+rewritten using the Qt platform, and new functionality for multi-modal image
+segmentation has been added.
+
+1.2.1. New functionality for multi-modality image segmentation
+
+ -  SNAP is no longer limited to just scalar-valued and RGB-valued images. An
+    image with any number of components can be loaded into SNAP. The GUI provides
+    widgets for selecting the currently shown component, deriving scalar images
+    from the components (magnitude, maximum, average), and for three-component
+    images, rendering them as color RGB images. It is also possible to animate
+    components, e.g., for time-varying image data. Multi-component images enjoy
+    access to the same features as scalar images, such as curve-based contrast
+    adjustment, colormaps, etc.
+
+ -  When multiple layers are loaded into SNAP, the user has a new option to
+    tile the layers in each of the 2D slice views. This greatly simplifies
+    working with multiple overlays. This also carries over to the automatic
+    segmentation mode, where the speed image can now be displayed side by side
+    with the anatomical images. It can also aid manual segmentation of
+    multi-modality data. During manual segmentation, polygon outlines are traced
+    on top of each of the tiled views.
+
+ -  Automatic segmentation (using active contours) can now be performed in
+    multi-modality images. Multiple image layers, each of which may have
+    multiple components (e.g., RGB, complex or tensor data), can be passed to
+    the auto-segmentation mode. Once there, the user can use the new clustering
+    preprocessing mode to derive a speed image from this multi-variate input.
+    The current implementation of clustering uses Gaussian Mixture Modeling.
+    The user selects the desired number of clusters (i.e., tissue classes) and
+    once the clusters are initialized, chooses the cluster of interest.
+
+1.2.2. New features in the Qt-based GUI
+
+ -  The graphical user interface (GUI) uses Qt, a much more powerful toolkit
+    than the FLTK toolkit in the previous versions. The new GUI is much richer
+    with multiple access paths to common functions (such as choosing the active
+    label or changing the color map for an overlay). There are fewer 'apply'
+    buttons to press, as most of the time, the program reacts immediately to
+    user input into the widgets. More features are available in the left-side
+    panel, and these features are organized more logically than before.
+
+ -  New functionality for saving and opening workspaces. A workspace represents
+    the state of ITK-SNAP at a given moment, including all the images currently
+    loaded in an ITK-SNAP window, as well as associated settings and parameters.
+    Workspaces are saved in the XML format. They can be packaged together with
+    the images to which they refer and shared with other users.
+
+ -  The layer inspector dialog is greatly improved, with new features for
+    reordering layers, quickly changing their visibility, applying a colormap,
+    adjusting contrast, saving, etc. The speed image and level set image,
+    created by the program during automatic segmentation, are now accessible
+    in the layer inspector, so the user can change their color maps as well.
+    In the future, the layer inspector will provide access to much more
+    functionality, such as applying image processing operations (smoothing,
+    feature extraction, bias field correction) to individual layers.
+
+ -  The various plots in the GUI now use the vtkChart library in VTK. This
+    provides richer visualization capabilities than the old version in which
+    all the plots were rendered using custom OpenGL code. This is particularly
+    noticable in the contrast adjustment page of the layer inspector and in
+    the preprocessing dialog in auto-segmentation mode.
+
+ -  The window shown at startup shows a graphical list of recently opened images
+    and workspaces. This makes it easier to quickly load an image, and keeps the
+    GUI clean during startup.
+
+ -  SNAP recognizes pinch gestures (tested on the Mac) for zoom. This should
+    make interaction easier for trackpad users.
+
+ -  Layers can be assigned nicknames, such as "T1".
+
+ -  Unicode support. Filenames and user-entered data can now be in any language.
+
+ -  The label editor has new features, such as resetting all labels do defaults,
+    filtering labels by name, assinging foreground/background labels directly
+    from the dialog.
+
+1.2.3. Improvements to 3D rendering window
+
+ -  The 3D rendering window now uses the VTK toolkit for rendering. This will
+    make it easier to introduce new functionality (such as volume rendering)
+    in future versions.
+
+ -  The 3D rendering pipeline is much smarter than before. It detects changes
+    to individual labels in the segmentation, so each paint operation no longer
+    requires the entire set of 3D meshes to be recomputed. Rendering is
+    significantly faster than before.
+
+ -  There is a new option to automatically render meshes in a background thread.
+    When enabled, the mesh updates itself in response to polygon and paintbrush
+    operations. This works well even for large and complex segmentations. However,
+    this is still an experimental feature and may lead to occasional weird crashes
+    due to multi-threading issues.
+
+ -  The scalpel tool uses VTK's 3D cutplane widget that can be rotated and moved
+    after the cut has been drawn.
+
+1.2.4. Other new features
+
+ -  Reduced memory footprint for large images. The previous version of SNAP
+    would allocate on the order of 6 bytes for every voxel in the main image.
+    Two bytes were used to store the grayscale image intensity, two for the
+    segmentation, and two for the segmentation undo buffer. The undo buffer is
+    now stored in a compressed format, reducing the required memory by almost
+    one third. In the future, we also plan to compress the segmentation itself,
+    which will cut the memory use by another 2 bytes per voxel.
+
+ -  Improved support for reading/parsing DICOM data. When the user opens a file
+    in a directory containing DICOM images, SNAP parses this directory
+    much faster than in previous versions (especially when data is on CDs) and
+    lists all the series with their dimensions and other meta-data, making it
+    easier to determine which series one wishes to load.
+
+1.2.5. Programmatic improvements
+
+ -  The SNAP code has been extensively refactored. There is a new "model" layer
+    separating the Qt GUI from the "logic" layer. This layer is agnostic to the
+    type of GUI toolkit used, and implements generic GUI logic. This design
+    minimizes the amount of Qt code, so that swapping Qt versions or even
+    porting to a different toolkit will be easier in the future. Unlike the old
+    FLTK code, which had huge numbers callbacks, the new code relies on a
+    widget-model coupling mechanism. This makes the code more robust and
+    reduces the amount of Qt-aware code.
+
+
+1.3. New in Version 2.4.0
+----------------------------------------------
+
+This is the last planned release of the FLTK-based version of ITK-SNAP. It adds
+minimal new functionality and addressed a number of bugs reported in the last
+year. The subsequent releases of ITK-SNAP will be based on the Qt platform and
+will have the 3.x version number.
+
+1.3.1. New Features and UI Improvements
+
+ -  Ported the dependency on ITK 3.20.1 to ITK 4.2 on all operating systems:
+    Mac OS X, Linux, and Windows.
+
+ -  ITK-SNAP can read and write MRC images now.
+
+1.3.2. Bug Fixes and Stability Improvements
+
+ -  Fixed a problem with the RAI code which was not updating after reorienting.
+
+ -  Fixed bug ID: 3371200: The saving of the preprocessed image was failing.
+
+ -  Fixed bug ID: 3309784 and 3415653: Windows file browser broken and enable
+    all document setting not available in version 2.2.0.
+
+ -  Fixed bug ID: 3415681 It was not possible to update the mesh when working
+    with volumes of one slice. An exception is thrown and catch with fl_alert.
+
+ -  Fixed bug ID: 3323300 BYU mesh saving was save-able, while the internal
+    data was not prepared  for this saving. The user interface is correctly
+    updated now. In addition, the BYU writer save geometric data as well.
+
+ -  Fixed: bug ID: 3023489: When running from command line with -o flag,
+    there was no check to see if images are same size. Two asserts were
+    changed in exception throwing.
+
+ -  Fixes for building with different releases of fltk 1.3.
+
+ -  Corrected a bug in the code with SparseLevelSet filter being used
+    instead of ParallelSparse.
+
+======================================
+
+1.4. New in Version 2.2.0
 ----------------------------------------------
 
 This is largely a maintenance release, with a few usability enhancements based
 on user feedback. The main change programmatically is 64 bit support on Linux,
 MacOS and Windows.
 
-1.1.1. New Features and UI Improvements
+1.4.1. New Features and UI Improvements
 
  -  64 bit versions of the software are available for Linux, Windows and Mac.
     These versions are now built nightly and will be distributed on
@@ -34,7 +268,7 @@ MacOS and Windows.
     includes the Fl_Table widget.
 
  -  A new tab on the layer inspector displaying image metadata, particularly
-    useful for DICOM files. 
+    useful for DICOM files.
 
  -  Several changes to the polygon drawing interface. The buttons at the
     bottom of the slice window are now shown dynamically, based on what the
@@ -61,11 +295,11 @@ MacOS and Windows.
     for sagittal or 'c' for coronal. You can restore default SNAP layout using
     Ctrl-F3 (Command-F3 on the Mac) or using the toolbar button that pops up.
 
- -  Also added command line options --zoom and --help 
+ -  Also added command line options --zoom and --help
 
  -  The 'reset view' button under the slice windows has been renamed 'zoom to
     fit' and it behaves more sensibly when zoom is linked across the slice
-    views. 
+    views.
 
  -  Improved integration with MacOS and Windows operating systems. On both
     MacOS and Windows, you can drag and drop a file into an open SNAP window
@@ -78,14 +312,14 @@ MacOS and Windows.
 
  -  Ability to save segmentation mesh in active contour mode
 
-1.1.2. Bug Fixes and Stability Improvements
+1.4.2. Bug Fixes and Stability Improvements
 
  -  Fixed a problem with certain operations being very slow because of the way
     the progress bars were displayed. Preprocessing, mesh rendering and mesh
     IO will now be much faster
 
  -  Fixed problems with the snake parameter dialog. The images are now
-    properly displayed and animation works. 
+    properly displayed and animation works.
 
  -  Fixed problems with automatic panning in crosshairs mode. Also added a
     button to enable this feature; it is disabled by default.
@@ -96,33 +330,33 @@ MacOS and Windows.
 
  -  Fixed problem with bubbles not being spherical for certain image orientations
 
-1.2. New in Version 2.0
+1.5. New in Version 2.0
 ----------------------------------------------
 
-1.2.1. New Features and UI Improvements
+1.5.1. New Features and UI Improvements
 
  -  Support for multiple image layers. Users can now load gray and RGB images
     as overlays on top of the main image layer. For example, one can display a
-    statistical map as an overlay over an anatomical image. As of version 
+    statistical map as an overlay over an anatomical image. As of version
     1.9.8, overlays must have the same dimensions as the main image.
 
- -  A new layer inspector window. Each layer in SNAP (main image and each of the 
+ -  A new layer inspector window. Each layer in SNAP (main image and each of the
     overlays) can be examined using the layer inspector. Currently there are three
-    tabs: one for setting the intensity mapping of the layer (i.e., mapping from 
+    tabs: one for setting the intensity mapping of the layer (i.e., mapping from
     image intensity to display intensity); one for selecting and editing the color
-    map and transparency of the layer; and one providing information about the layer. 
+    map and transparency of the layer; and one providing information about the layer.
     The layer inspector replaces the old "Image Information" and "Intensity Curve"
     windows. The color bar editor is only partially functional as of 1.9.9.
 
  -  Hiding the UI. Using the 'F3' key, users can toggle certain user interface elements
     on and off. Press 'F3' once, and the left sidebar and the menu bar disappear.
     Press 'F3' twice, and all the UI elements disappear, so you are looking just at the
-    image. Press 'F3' again, and the UI is restored to the original state. This 
+    image. Press 'F3' again, and the UI is restored to the original state. This
     feature works well with the '+' buttons on the slice windows. It's intended for
     multi-session SNAP users, so that the screen real estate can be used more efficiently
     by multiple SNAP sessions.
 
- -  Because now the most common SNAP commands have a shortcut, you will be able to 
+ -  Because now the most common SNAP commands have a shortcut, you will be able to
     do a lot with the UI hidden. Select 'Help->Keyboard Shortcuts' to see a listing.
 
  -  Fullscreen mode. Press 'F4' to toggle fullscreen SNAP. Use it with 'F3' to let the
@@ -136,22 +370,22 @@ MacOS and Windows.
     file chooser can be further enhanced by installing the DTI-TK Quick Look
     plugin that supports NIfTI/Analyze image preview (www.nitrc.org/projects/dtitk)
 
- -  When launched from command line, SNAP can automatically determine whether an 
+ -  When launched from command line, SNAP can automatically determine whether an
     image is a 3-component RGB image or a grayscale image. To use this functionality,
     users must run SNAP without "-g" or "-rgb" options:
 
         itksnap image.nii
 
     This feature is ideal for users who want to associate ITK-SNAP with certain 3D image
-    types in their operating system (in Finder or Windows Explorer). 
+    types in their operating system (in Finder or Windows Explorer).
 
  -  Automatic check for software update. Users can enable automatic update checking.
 
- -  External web browser support. Help and other HTML pages are now displayed in the 
-    operating system's own web browser, from itksnap.org. This may displease users 
+ -  External web browser support. Help and other HTML pages are now displayed in the
+    operating system's own web browser, from itksnap.org. This may displease users
     connected to the internet, but this makes managing documentation a lot easier and
     hopefully will allow us to keep the documentation up to date with the features.
-    
+
  -  Crash recovery. When an out-of-memory or other crash occurs, ITK-SNAP will ask you
     if you want to save the segmentation image before exiting. Of course this may not
     always work, but it should make a lot of frustrated users a little less frustrated.
@@ -160,21 +394,21 @@ MacOS and Windows.
     ITK-SNAP requires 6 bytes per voxel in manual segmentation mode. More memory is needed for
     mesh rendering, and a lot more for automatic segmentation. When loading images in 32-bit
     or 64-bit formats, more memory may be required at the time of image IO. That is because
-    ITK NIFTI reader (and maybe other readers) keeps a second copy of the image in memory 
-    during IO. This memory is immediately deallocated though.  
-	
- -  Unified navigation modes. The crosshair mode allows zoom and pan (RMB/MMB), and has an 
+    ITK NIFTI reader (and maybe other readers) keeps a second copy of the image in memory
+    during IO. This memory is immediately deallocated though.
+
+ -  Unified navigation modes. The crosshair mode allows zoom and pan (RMB/MMB), and has an
     auto-pan feature when you move the crosshair close to the edge of the slice window.
     The zoom/pan mode is redundant, but we left it in place for backward compatibility.
     In the zoom/pan mode, zoom is RMB, pan is LMB, crosshair motion is MMB. In all other
     modes, crosshair motion is accessible through MMB as well.
-    
 
-1.2.2. Bug Fixes
+
+1.5.2. Bug Fixes
 
  -  Fixed an issue with SNAP reading certain types of image twice from disc. This should
     speed up the reading of floating point images, for example.
-    
+
  -  Color map cache is now computed on the fly. This makes interaction with the intensity
     curve and color map more real-time.
 
@@ -182,25 +416,25 @@ MacOS and Windows.
     nothing. Did not know how to fix it correctly, so replaced the parallel
     sparse field solver with the non-parallel one. This may slow down
     automatic segmentation on some machines, so this is an outstanding issue.
-    
+
  -  Found a bug that caused images with unusual coordinate orientations to be incorrectly
     displayed (wrong coordinate labels assigned). This was caused by incorrect mapping of
     ITK direction matrix to "RAI" codes in SNAP. This affects display of NIFTI, DICOM and
     other image files. It also affects the behavior of the Reorient Image dialog.
-    
+
  -  Please see the bug tracker on itksnap.org for the full listing of bug fixes.
- 
-1.2.3. Website Changes
 
- -  The itksnap.org website has been Wikified. Content can now be edited on the fly. 
+1.5.3. Website Changes
+
+ -  The itksnap.org website has been Wikified. Content can now be edited on the fly.
 
 
 
-1.3. New in Version 1.8
+1.6. New in Version 1.8
 ----------------------------------------------
 
-1.3.1. New Features and UI Improvements
- 
+1.6.1. New Features and UI Improvements
+
  -  Support for reading floating point images of arbitrary range. SNAP still
     represents gray images internally as signed short, but now it can load a
     floating point image and remap its intensity range to signed shorts. When
@@ -224,7 +458,7 @@ MacOS and Windows.
     ITK-SNAP. Let us know if this feature works for you. Potentially, we may add
     other algorithms in the future, including running the level set inside of
     the brush.
-    
+
  -  Support for image orientation. This is a major step towards NIFTI
     compatibility (part of our R03 effort) and something many users should find
     helpful. Formats such as NIFTI, DICOM, and a couple others encode the
@@ -238,13 +472,13 @@ MacOS and Windows.
  -  A new 'reorient image' dialog has been added, so that if the orientation
     information in the header is wrong, you can change the orientation and save
     the image. For now, the user can only specify reorientations that are
-    parallel to the anatomical axes. 
+    parallel to the anatomical axes.
 
  -  World cursor coordinates (under image information) are now displayed in
     NIFTI / MNI coordinates as well as ITK coordinates. The difference is that
     the NIFTI coordinates incorporate orientation and are in the (L->R, P->A,
     I->S) coordinate frame. ITK coordinates are (x * spacing + origin), and
-    ignore orientation. 
+    ignore orientation.
 
  -  3D Meshes generated and rendered by SNAP are now represented in NIFTI world
     coordinates. Previously, the coordinates were computed using the formula
@@ -258,7 +492,7 @@ MacOS and Windows.
     This means that the meshes output by earlier versions of SNAP may be
     translated and rotated relative to the meshes output by version 1.8. This will
     not affect users who simply view meshes in SNAP; however users who export
-    meshes to other programs will be affected. 
+    meshes to other programs will be affected.
 
  -  Multisession cursor (similar to yoking in MRIcro) now uses these NIFTI
     coordinates rather than ITK coordinates. This is a key feature because it
@@ -272,7 +506,7 @@ MacOS and Windows.
     voxel. If in session A you move your cursor, the cursor in session B will
     move to the voxel center closest to the physical position referenced by the
     cursor in session A.
-    
+
  -  A new multi-session zoom feature. Similar to the multi-session cursor, this
     allows the zoom level to be maintained across multiple SNAP sessions. Useful
     if you do a lot of zooming in and out when working with a pair of scans.
@@ -297,7 +531,7 @@ MacOS and Windows.
     feature is useful when comparing two segmentations of the same image.
 
  -  A new ruler display in slice windows. Can be disabled or modified on the
-    display options dialog. 
+    display options dialog.
 
  -  Much better tracking of changes to the segmentation image and better
     promting to save changes before quitting or loading a new image. The title
@@ -327,7 +561,7 @@ MacOS and Windows.
  -  Documented existing keyboard shortcuts and added some new ones. Available
     shortcuts can be listed by selecting Help->Shortcuts.
 
-1.3.2. Programmatic/Distribution Changes
+1.6.2. Programmatic/Distribution Changes
 
  -  SNAP is now built against ITK 3.8, offering several improvements, especially
     in how image orientation is handled.
@@ -340,26 +574,26 @@ MacOS and Windows.
     Some people complained about the latter. We can also make .rpm and .deb
     packages although these won't be posted for public download yet.
 
-1.3.3. Bug Fixes
+1.6.3. Bug Fixes
 
  -  Level set fix for ITK 3.8 fixes automatic segmentation's weird behavior
 
-1.4. New in Version 1.6.0.1
+1.7. New in Version 1.6.0.1
 ---------------------------
 
-1.4.1. Bug Fixes
+1.7.1. Bug Fixes
 
- -  Major bug in release 1.6.0 involving disabled cursor movement in snake 
+ -  Major bug in release 1.6.0 involving disabled cursor movement in snake
     segmentation mode has been resolved.
 
 
-1.5. New in Version 1.6.0
+1.8. New in Version 1.6.0
 -------------------------
 
-1.5.1. New Features and UI Improvements
+1.8.1. New Features and UI Improvements
 
  -  You can now save a sequence of all axial, coronal or sagittal slices with
-    overlays as PNG files (File->Save->Screenshot Series). 
+    overlays as PNG files (File->Save->Screenshot Series).
 
  -  Automatic window and level computation based on the image histogram. The
     window and level are set to the 1st and 99th percentiles of the intensity
@@ -367,17 +601,17 @@ MacOS and Windows.
     hyper-intensity in medical imaging data. The feature is accessed in the
     "Options->Image Contrast" menu (or hit Alt-I in the main window).
 
- -  Cursor synchronization across multiple SNAP sessions (similar to the Yoke 
+ -  Cursor synchronization across multiple SNAP sessions (similar to the Yoke
     feature in MRIcro). The mechanism uses POSIX shared memory. Can be turned
-    off using the 'Synchronize Cursor' checkbox. Currently, only enabled in 
+    off using the 'Synchronize Cursor' checkbox. Currently, only enabled in
     manual segmentation mode; probably will enable in snake mode in the near
     future.
 
         --- NOTE FOR MacOS Users ---
-        MacOS doesn't allow you double-click the application icon to open a 
-        new instance. To open multiple instances of ITK-SNAP, you need to launch 
+        MacOS doesn't allow you double-click the application icon to open a
+        new instance. To open multiple instances of ITK-SNAP, you need to launch
         it from the command line.
-        ----------------------------    
+        ----------------------------
 
  -  SNAP will prompt you before closing if there are unsaved changes.
 
@@ -385,31 +619,31 @@ MacOS and Windows.
     segmentation.
 
  -  Support for RGB (color) images in SNAP. This is great for segmenting in DTI
-    data (manually, for the time being). RGB images can be loaded as the base 
+    data (manually, for the time being). RGB images can be loaded as the base
     image or as an overlay over the gray. To create these RGB images, use the new
     DTI-TK developed by Hui (Gary) Zhang, available from
 
         http://www.picsl.upenn.edu/resources_dtitk.aspx
 
- -  Segmentations can be exported as VTK meshes (for example, for loading in 
+ -  Segmentations can be exported as VTK meshes (for example, for loading in
     ParaView).
 
  -  Multilevel undo/redo functionality for all segmentation operations (polygon,
     paintbrush, freehand, 3D segmentation, 3D cutplane). Undo memory is
     preserved when loading new segmentation images.
 
- -  Freehand drawing support in polygon mode (hold and drag the mouse button). 
+ -  Freehand drawing support in polygon mode (hold and drag the mouse button).
     This feature is especially useful for using SNAP on a tablet.
 
  -  Added keyboard shortcuts 'a','s','d' for the opacity slider
 
  -  Shortened/simplified some of the menu items
 
-1.5.2. Bug Fixes
+1.8.2. Bug Fixes
 
  -  Various bugs have been fixed :)
 
-1.5.3. Distribution Changes
+1.8.3. Distribution Changes
 
  -  SNAP website fully migrated to sourceforge.net
 
@@ -419,10 +653,10 @@ MacOS and Windows.
  -  Linux binaries will be available starting with 1.6.0
 
 
-1.6. New in Version 1.4.1
+1.9. New in Version 1.4.1
 -------------------------
 
-1.6.1. New Features and UI Improvements
+1.9.1. New Features and UI Improvements
 
  -  Added paintbrush tool to the main toolbar. Paintbrush can be used to quickly
     touch up segmentations. Left mouse button paints with selected label, right
@@ -441,9 +675,9 @@ MacOS and Windows.
     different segmentation from the same viewpoint. Press 's' in the 3D window
     to save the camera state and 'r' to restore it.
 
-1.6.2. Bug Fixes
+1.9.2. Bug Fixes
 
- -  MAJOR: fixed bug that was causing crashes on Win32 during polygon drawing 
+ -  MAJOR: fixed bug that was causing crashes on Win32 during polygon drawing
     (thanks to Jeff Tsao for this bug fix!)
 
  -  Fixed problems with the getsnap.sh linux script
@@ -456,14 +690,14 @@ MacOS and Windows.
 
  -  Fixed problem where the screen was blank after loading preprocessed image
 
- -  Fixed crash when changing bubble radius and then going back to 
+ -  Fixed crash when changing bubble radius and then going back to
     preprocessing mode
 
-1.6.3. Distribution Changes 
+1.9.3. Distribution Changes
 
  -  Interim SNAP releases are now hosted on SourceForge. ITK repository will only
     be used to host major releases (like 1.6). This allows us to check stuff in
-    independently of the ITK code freezes. It also makes it easier to add new 
+    independently of the ITK code freezes. It also makes it easier to add new
     developers.
 
  -  SNAP CMake files should automatically detect when SNAP is being built
@@ -471,10 +705,10 @@ MacOS and Windows.
     own and the download size is reduced
 
 
-1.7. New in Version 1.4
+1.10. New in Version 1.4
 -----------------------
 
-1.7.1. New Features and User Interface Improvements
+1.10.1. New Features and User Interface Improvements
 
  -  New and improved label editor. You can easily switch between labels while in
     the editor and the interface for adding new labels is more intuitive. You
@@ -482,24 +716,24 @@ MacOS and Windows.
 
  -  New and improved interface for intensity reparameterization. The histogram
     display is more visible and you have more control over the number of bins in
-    the histogram and the scaling of the bars (linear or log). 
+    the histogram and the scaling of the bars (linear or log).
 
  -  SNAP remembers all settings associated with loading an image. This means that
-    any image loaded previously can be reloaded without going throught the 
-    wizard. 
+    any image loaded previously can be reloaded without going throught the
+    wizard.
 
  -  We've added File->Load Previous menu to let you load images quickly
 
- -  SNAP can now read DICOM file series (experimental support) and it can read 
+ -  SNAP can now read DICOM file series (experimental support) and it can read
     and write VoxBo CUB image files.
 
  -  SNAP remembers more image-associated settings from session to session. For
     example, it will remember the intensity reparameterization that you last
     used. SNAP will also remember the orientation ("RAI" code) that was last
-    used to read each image. 
+    used to read each image.
 
  -  New Image Information window is available under the File menu. It displays
-    the size of the image and the current cursor position. 
+    the size of the image and the current cursor position.
 
  -  A color map feature has been added in the automatic segmentation mode. The
     color map lets you select different color schemes for displaying the
@@ -513,7 +747,7 @@ MacOS and Windows.
 
  -  The tutorial has been updated to reflect the new features.
 
-1.7.2. Bug Fixes.
+1.10.2. Bug Fixes.
 
  -  SNAP should crash a lot less than before
 
@@ -529,40 +763,40 @@ MacOS and Windows.
 
  -  Lots of other small bugs have been fixed!
 
-1.7.3. Programmatic Enhancements
+1.10.3. Programmatic Enhancements
 
  -  SNAP and IRIS now share the sameset of OpenGL windows. This should prevent
     crashes on some platforms.
 
-1.7.4. Other
+1.10.4. Other
 
  -  SNAP available as a universal (Intel/PPC) binary for MacOS at itksnap.org
 
 
-1.8. New in Version 1.2
+1.11. New in Version 1.2
 -----------------------
 
-1.8.1. User Interface Improvements
+1.11.1. User Interface Improvements
 
- -  The ability to switch between 4-view mode and single view mode. Each of the 
+ -  The ability to switch between 4-view mode and single view mode. Each of the
     slice views and the 3D view can be expanded to occupy the entire SNAP window.
 
- -  A zoom thumbnail is now displayed when a slice view is zoomed in. The thumbnail 
+ -  A zoom thumbnail is now displayed when a slice view is zoomed in. The thumbnail
     view can be used to pan the slice.
 
- -  User can specify whether he/she prefers to start in linked zoom mode or in 
+ -  User can specify whether he/she prefers to start in linked zoom mode or in
     unlinked zoom mode.
 
  -  User can change the appearance of various display elements, including the
     crosshairs, the region of interest selection box, the window background and
-    more. 
+    more.
 
  -  SNAP automatically determines the image orientation (RAI) when that information
     is available in the image file
 
  -  SNAP remembers the last ROI used for each image.
 
-1.8.2. Programmatic Improvements
+1.11.2. Programmatic Improvements
 
  -  The level set segmentation pipeline has been rewritten, taking advantage of
     the stop and go functionality of ITK finite difference filters. This means
@@ -572,7 +806,7 @@ MacOS and Windows.
     machine automatically activates and deactivates UI widgets based on a set of
     flags. Rules such as Flag A => Flag B can be added to the state machine.
 
-1.8.3 Bug Fixes
+1.11.3. Bug Fixes
 
  -  Slice views update correctly when the SNAP window is resized
 
@@ -582,12 +816,18 @@ MacOS and Windows.
     advection term.
 
 
-2. Known Issues
+3. Known Issues
 -----------------
- -  
 
+ -  Some advanced features (annotation mode, label editor advanced tools) have
+    not yet been ported to Qt. They will be ported in future versions, and
+    expanded in the process. There is a plan to integrate SNAP and C3D which
+    will provide much richer image processing support for images and segmentations.
+
+ -  The cutplane in the scalpel tool is too big when the camera is zoomed in and
+    it needs a flip button. Also with dark labels you can't see the handle.
 
-3. Wish List
+4. Wish List
 -----------------
  -  The ability to perform 2D level set segmentation in each slice view.
 
diff --git a/Testing/GUI/Qt/SNAPTestQt.cxx b/Testing/GUI/Qt/SNAPTestQt.cxx
new file mode 100644
index 0000000..3adcec2
--- /dev/null
+++ b/Testing/GUI/Qt/SNAPTestQt.cxx
@@ -0,0 +1,481 @@
+#include "SNAPTestQt.h"
+#include "MainImageWindow.h"
+
+#include <QAction>
+#include <QLineEdit>
+#include <QFile>
+#include <QTextStream>
+#include <QQmlEngine>
+#include <QDebug>
+#include <QPushButton>
+#include <QTimer>
+#include <QThread>
+#include <QRegExp>
+#include <QApplication>
+#include "SNAPQtCommon.h"
+
+using namespace std;
+
+SNAPTestQt::SNAPTestQt(MainImageWindow *win,
+    std::string datadir, double accel_factor)
+  : m_Acceleration(accel_factor)
+{
+  // We need a dummy parent to prevent self-deletion
+  m_DummyParent = new QObject();
+  this->setParent(m_DummyParent);
+
+  // Create the script engine
+  m_ScriptEngine = new QJSEngine();
+
+  // Assign the window as a variable in the script engine
+  QJSValue mwin = m_ScriptEngine->newQObject(win);
+  m_ScriptEngine->globalObject().setProperty("mainwin", mwin);
+
+  // Provide a pointer to the engine
+  QJSValue vthis = m_ScriptEngine->newQObject(this);
+  m_ScriptEngine->globalObject().setProperty("engine", vthis);
+
+  QJSValue test = m_ScriptEngine->newQObject(win->findChild<QPushButton *>("btnLoadMain"));
+  m_ScriptEngine->globalObject().setProperty("btn", test);
+
+  // Assign the data directory to the script engine
+  m_ScriptEngine->globalObject().setProperty("datadir", from_utf8(datadir));
+}
+
+SNAPTestQt::~SNAPTestQt()
+{
+  delete m_ScriptEngine;
+  setParent(NULL);
+  delete m_DummyParent;
+}
+
+#include <QFileInfo>
+
+void
+SNAPTestQt::LaunchTest(std::string test)
+{
+  // Special case: listing all tests
+  if(test == "list")
+    {
+    ListTests();
+    ::exit(SUCCESS);
+    }
+
+  // Create and run the thread
+  TestWorker *worker = new TestWorker(this, from_utf8(test), m_ScriptEngine, m_Acceleration);
+  connect(worker, &TestWorker::finished, worker, &QObject::deleteLater);
+  worker->start();
+}
+
+QObject *SNAPTestQt::findChild(QObject *parent, QString child)
+{
+  return parent->findChild<QObject *>(child);
+}
+
+QWidget *SNAPTestQt::findWidget(QString widgetName)
+{
+  foreach(QWidget *w, QApplication::allWidgets())
+    if(w->objectName() == widgetName)
+      return w;
+
+  return NULL;
+}
+
+#include <QAbstractItemView>
+
+QVariant SNAPTestQt::tableItemText(QObject *table, int row, int col)
+{
+  QAbstractItemView *view = dynamic_cast<QAbstractItemView *>(table);
+  if(view)
+    {
+    QAbstractItemModel *model = view->model();
+    return model->data(model->index(row, col));
+    }
+
+  return QVariant();
+}
+
+#include <QComboBox>
+
+QModelIndex SNAPTestQt::findItem(QObject *container, QVariant text)
+{
+  QAbstractItemModel *model = NULL;
+
+  // Is it a combo box?
+  if(QComboBox *combo = dynamic_cast<QComboBox *>(container))
+    model = combo->model();
+
+  // Is it an item view?
+  else if(QAbstractItemView *itemview = dynamic_cast<QAbstractItemView *>(container))
+    model = itemview->model();
+
+  // Find the item
+  if(model)
+    {
+    QModelIndexList found = model->match(model->index(0,0),Qt::DisplayRole,text);
+    if(found.size())
+      return found.at(0);
+    }
+
+  return QModelIndex();
+}
+
+
+
+QVariant SNAPTestQt::findItemRow(QObject *container, QVariant text)
+{
+  QModelIndex idx = findItem(container, text);
+  if(idx.isValid())
+    return idx.row();
+
+  return QVariant();
+}
+
+QVariant SNAPTestQt::findItemColumn(QObject *container, QVariant text)
+{
+  QModelIndex idx = findItem(container, text);
+  if(idx.isValid())
+    return idx.column();
+
+  return QVariant();
+}
+
+
+void SNAPTestQt::print(QString text)
+{
+  qDebug() << text;
+}
+
+void SNAPTestQt::printChildrenRecursive(QObject *parent, QString offset, const char *className)
+{
+  if(parent)
+    {
+    if(!className || parent->inherits(className))
+      {
+      QString line = QString("%1%2 : %3").arg(offset,parent->metaObject()->className(),parent->objectName());
+      qDebug() << line;
+      }
+
+    foreach (QObject* child, parent->children())
+      {
+      QWidget *widget = dynamic_cast<QWidget *>(child);
+      if(widget)
+        printChildrenRecursive(child, offset + "  ", className);
+      }
+    }
+  else
+    {
+    qDebug() << "NULL passed to printChild";
+    }
+}
+
+void SNAPTestQt::printChildren(QObject *parent)
+{
+  printChildrenRecursive(parent, "");
+}
+
+void SNAPTestQt::printChildren(QObject *parent, QString className)
+{
+  const char *cn = NULL;
+  if(!className.isNull())
+    {
+    QByteArray ba = className.toLocal8Bit();
+    cn = ba.data();
+    }
+  printChildrenRecursive(parent, "", cn);
+}
+
+void SNAPTestQt::validateValue(QVariant v1, QVariant v2)
+{
+  // Validation involves checking if the values are equal. If not,
+  // the program should be halted
+  if(v1 != v2)
+    {
+    // Validation failed!
+    qWarning() << QString("Validation %1 == %2 failed!").arg(v1.toString(),v2.toString());
+
+    // Exit with code corresponding to test failure
+    ::exit(REGRESSION_TEST_FAILURE);
+    }
+  else
+    {
+    // Validation failed!
+    qDebug() << QString("Validation %1 == %2 ok!").arg(v1.toString(),v2.toString());
+    }
+
+}
+
+void SNAPTestQt::validateFloatValue(double v1, double v2, double precision)
+{
+  // Validation involves checking if the values are equal. If not,
+  // the program should be halted
+  if(fabs(v1 - v2) > precision)
+    {
+    // Validation failed!
+    qWarning() << QString("Validation %1 == %2 (with precision %3) failed!").arg(v1).arg(v2).arg(precision);
+
+    // Exit with code corresponding to test failure
+    ::exit(REGRESSION_TEST_FAILURE);
+    }
+  else
+    {
+    // Validation failed!
+    qDebug() << QString("Validation %1 == %2 (with precision %3) ok!").arg(v1).arg(v2).arg(precision);
+    }
+}
+
+void SNAPTestQt::testFailed(QString reason)
+{
+  qWarning() << reason;
+  ::exit(REGRESSION_TEST_FAILURE);
+}
+
+#include <QMouseEvent>
+#include <QApplication>
+
+void SNAPTestQt::postMouseEvent(QObject *object, double rel_x, double rel_y, QString eventType, QString button)
+{
+  // Special case handlers
+  if(eventType == "click")
+    {
+    postMouseEvent(object, rel_x, rel_y, "press", button);
+    postMouseEvent(object, rel_x, rel_y, "release", button);
+    return;
+    }
+
+  QWidget *widget = dynamic_cast<QWidget *>(object);
+  if(widget)
+    {
+    QSize size = widget->size();
+    QPoint point((int)(size.width() * rel_x), (int)(size.height() * rel_y));
+
+    Qt::MouseButton btn = Qt::NoButton;
+    if(button == "left")
+      btn = Qt::LeftButton;
+    else if(button == "right")
+      btn = Qt::RightButton;
+    else if(button == "middle")
+      btn = Qt::MidButton;
+
+    QEvent::Type type = QEvent::None;
+    if(eventType == "press")
+      type = QEvent::MouseButtonPress;
+    else if(eventType == "release")
+      type = QEvent::MouseButtonRelease;
+
+    QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonPress, point, btn, btn, Qt::NoModifier);
+    QApplication::postEvent(widget, event);
+    }
+}
+
+#include <QKeySequence>
+void SNAPTestQt::postKeyEvent(QObject *object, QString key)
+{
+  QWidget *widget = dynamic_cast<QWidget *>(object);
+  if(widget)
+    {
+    QKeySequence seq(key);
+    if(seq.count() == 1)
+      {
+      int code = seq[0];
+      int key = code & 0x01ffffff;
+      int mod = code & 0xfe000000;
+      Qt::KeyboardModifiers mods;
+
+      if(mod & Qt::ShiftModifier)
+        mods |= Qt::ShiftModifier;
+      if(mod & Qt::ControlModifier)
+        mods |= Qt::ControlModifier;
+
+      QKeyEvent *ev = new QKeyEvent(QEvent::KeyPress, key, mods);
+      QApplication::postEvent(widget, ev);
+      }
+    }
+}
+
+SNAPTestQt::ReturnCode
+SNAPTestQt::ListTests()
+{
+  cout << "Available Tests" << endl;
+  cout << "  SnakeThreshQt    : Test segmentation with thresholding option" << endl;
+  return SUCCESS;
+}
+
+
+TestWorker::TestWorker(QObject *parent, QString script, QJSEngine *engine, double accel_factor)
+  : QThread(parent)
+{
+  m_MainScript = script;
+  m_Engine = engine;
+  m_Acceleration = accel_factor > 0.0 ? accel_factor : 1.0;
+}
+
+
+
+void TestWorker::processDirective(QString line)
+{
+  // If the line is a command, process the command
+  QRegExp rxSleep("//---\\s+sleep\\s+(\\d+)");
+  QRegExp rxSource("//---\\s+source\\s+(\\w+)");
+
+  if(rxSleep.indexIn(line) >= 0)
+    {
+    // Sleeping
+    int ms = rxSleep.cap(1).toInt() * m_Acceleration;
+    qDebug() << QString("Sleeping for %1 ms").arg(ms);
+    msleep(ms);
+    }
+
+  else if(rxSource.indexIn(line) >= 0)
+    {
+    // Sleeping
+    QString file = rxSource.cap(1);
+    this->runScript(file);
+    }
+
+  else
+    {
+    // Unknown directive
+    qDebug() << "Unknown directive" << line;
+    }
+}
+
+void TestWorker::executeScriptlet(QString scriptlet)
+{
+  QJSValue rc = m_Engine->evaluate(scriptlet);
+  if(rc.isError())
+    {
+    qWarning() << "JavaScript exception:" << rc.toString();
+    ::exit(SNAPTestQt::REGRESSION_TEST_FAILURE);
+    }
+}
+
+
+void TestWorker::runScript(QString script_url)
+{
+  // The test may be a path to an actual file
+  if(!QFileInfo(script_url).isReadable())
+    script_url = QString(":/scripts/Scripts/test_%1.js").arg(script_url);
+
+  // Report which test we are accessing
+  qDebug() << "Running test " << script_url;
+
+  // Find the script file corresponding to the test
+  QFile file(script_url);
+  if(!file.open(QIODevice::ReadOnly))
+    {
+    qWarning() << QString("Unable to read test script %1").arg(script_url);
+    ::exit(SNAPTestQt::NO_SUCH_TEST);
+    }
+
+  // Read the script
+  QTextStream stream(&file);
+
+  // Break the script into pieces that should be sent to the processor
+  QString scriptlet;
+  while(true)
+    {
+    // Read a line of the script
+    QString line = stream.readLine();
+
+    // Is the line an interpreter command or a script line?
+    if(line.isNull() || line.startsWith("//---"))
+      {
+      // The current scriptlet has ended. Time to execute!
+      this->executeScriptlet(scriptlet);
+
+      // Reset the scriptlet
+      scriptlet = QString();
+
+      // If the line is null (eof) break
+      if(line.isNull())
+        break;
+
+      // Otherwise, it's a directive
+      this->processDirective(line);
+      }
+    else
+      {
+      // Append the line to the current scriptlent
+      scriptlet.append(line);
+      scriptlet.append('\n');
+      }
+    }
+
+  // That's it - the script is finished
+}
+
+void TestWorker::run()
+{
+  // Add ourselves to the engine
+  QJSValue mwin = m_Engine->newQObject(this);
+  m_Engine->globalObject().setProperty("thread", mwin);
+
+  // Make sure full output is captured
+  qDebug() << "CTEST_FULL_OUTPUT";
+
+  // Run the top-level script
+  // runScript(m_MainScript);
+  source(m_MainScript);
+
+  // Once the test has completed, we can exit the application
+  ::exit(SNAPTestQt::SUCCESS);
+}
+
+void TestWorker::wait(unsigned int msec)
+{
+  msleep(msec);
+}
+
+void TestWorker::source(QString script_url)
+{
+  // The test may be a path to an actual file
+  if(!QFileInfo(script_url).isReadable())
+    script_url = QString(":/scripts/Scripts/test_%1.js").arg(script_url);
+
+  // Report which test we are accessing
+  qDebug() << "Running test " << script_url;
+
+  // Find the script file corresponding to the test
+  QFile file(script_url);
+  if(!file.open(QIODevice::ReadOnly))
+    {
+    qWarning() << QString("Unable to read test script %1").arg(script_url);
+    ::exit(SNAPTestQt::NO_SUCH_TEST);
+    }
+
+  // Read the script
+  QTextStream stream(&file);
+  QString script;
+
+  // Read the script line by line, making substitutions
+  while(!stream.atEnd())
+    {
+    QString line = stream.readLine();
+    QRegExp rxSleep("^\\s*$");
+    QRegExp rxComment("//===\\s+(\\w+.*)");
+
+    if(rxSleep.indexIn(line) >= 0)
+      {
+      line = QString("thread.wait(500)");
+      }
+    else if(rxComment.indexIn(line) >= 0)
+      {
+      line = QString("engine.print(\"%1\")").arg(rxComment.cap(1));
+      }
+
+    script += line;
+    script += "\n";
+    }
+
+  // Close the file
+  file.close();
+
+  // Execute it
+  QJSValue rc = m_Engine->evaluate(script);
+  if(rc.isError())
+    {
+    qWarning() << "JavaScript exception:" << rc.toString();
+    ::exit(SNAPTestQt::REGRESSION_TEST_FAILURE);
+    }
+}
diff --git a/Testing/GUI/Qt/SNAPTestQt.h b/Testing/GUI/Qt/SNAPTestQt.h
new file mode 100644
index 0000000..424cea7
--- /dev/null
+++ b/Testing/GUI/Qt/SNAPTestQt.h
@@ -0,0 +1,118 @@
+#ifndef SNAPTESTQT_H
+#define SNAPTESTQT_H
+
+#include <SNAPCommon.h>
+#include <QObject>
+#include <QTimer>
+#include <QStringList>
+#include <QThread>
+#include <QVariant>
+
+class MainImageWindow;
+class GlobalUIModel;
+class QJSEngine;
+class QQmlEngine;
+class QTimer;
+class QStringList;
+
+
+class TestWorker : public QThread
+{
+  Q_OBJECT
+
+public:
+  TestWorker(QObject *parent, QString script, QJSEngine *engine, double accel_factor);
+
+  void run();
+
+public slots:
+
+  void wait(unsigned int msec);
+  void source(QString script_url);
+
+protected:
+  QString m_MainScript;
+  QJSEngine *m_Engine;
+
+  // Acceleration factor
+  double m_Acceleration;
+
+  void runScript(QString script_url);
+  void executeScriptlet(QString scriptlet);
+  void processDirective(QString line);
+};
+
+class SNAPTestQt : public QObject
+{
+  Q_OBJECT
+
+public:
+
+  enum ReturnCode {
+    SUCCESS = 0,
+    EXCEPTION_CAUGHT,
+    REGRESSION_TEST_FAILURE,
+    NO_SUCH_TEST,
+    UNKNOWN_ERROR
+    };
+
+
+  SNAPTestQt(MainImageWindow *win, std::string datadir, double accel_factor);
+  ~SNAPTestQt();
+
+  void LaunchTest(std::string test);
+
+public slots:
+
+  // Find a child of an object visible to the script
+  QObject *findChild(QObject *parent, QString child);
+
+  // Find a widget by name globally
+  QWidget *findWidget(QString widgetName);
+
+  // Return the contents of an item in a table
+  QVariant tableItemText(QObject *table, int row, int col);
+
+  // Find the index of an item in a widget (combo, list)
+  QVariant findItemRow(QObject *container, QVariant text);
+
+  // Find the index of an item in a widget (combo, list)
+  QVariant findItemColumn(QObject *container, QVariant text);
+
+  void print(QString text);
+
+  void printChildren(QObject *parent);
+
+  void printChildren(QObject *parent, QString className);
+
+  void testFailed(QString reason);
+
+  void validateValue(QVariant v1, QVariant v2);
+
+  void validateFloatValue(double v1, double v2, double precision);
+
+  void postMouseEvent(QObject *widget, double rel_x, double rel_y, QString eventType, QString button);
+
+  void postKeyEvent(QObject *object, QString key);
+protected:
+
+  ReturnCode ListTests();
+
+  // The data directory for testing
+  std::string m_DataDir;
+
+  // We own a script engine
+  QJSEngine *m_ScriptEngine;
+
+  // A dummy parent object for this object
+  QObject *m_DummyParent;
+
+  // Acceleration factor
+  double m_Acceleration;
+
+  // Helper functions
+  QModelIndex findItem(QObject *container, QVariant text);
+  void printChildrenRecursive(QObject *parent, QString offset, const char *className=NULL);
+};
+
+#endif // SNAPTESTQT_H
diff --git a/Testing/GUI/Qt/Scripts/test_Library.js b/Testing/GUI/Qt/Scripts/test_Library.js
new file mode 100644
index 0000000..2805dd9
--- /dev/null
+++ b/Testing/GUI/Qt/Scripts/test_Library.js
@@ -0,0 +1,101 @@
+function setCursor(x, y, z)
+{
+  engine.print("Setting cursor position to " + x + ", " + y + ", " + z);
+  engine.findChild(mainwin, "inCursorX").value = x;
+  engine.findChild(mainwin, "inCursorY").value = y;
+  engine.findChild(mainwin, "inCursorZ").value = z;
+  thread.wait(200);
+}
+
+function openMainImage(name)
+{
+  //=== Opening Dialog
+  engine.findChild(mainwin,"actionOpenMain").trigger();
+
+  //=== Entering Text
+  var dialog = engine.findChild(mainwin, "wizImageIO");
+  engine.findChild(dialog, "inFilename").text = datadir + "/" + name;
+
+  //=== Pressing the 'next' button
+  engine.findChild(dialog, "qt_wizard_commit").click();
+  thread.wait(1000);
+
+  //=== Pressing the 'finish' button
+  engine.findChild(dialog, "qt_wizard_finish").click();
+  thread.wait(1000);
+}
+
+function openWorkspace(name)
+{
+  //=== Opening Dialog
+  engine.findChild(mainwin,"actionOpenWorkspace").trigger();
+
+  //=== Entering Text
+  var dialog = engine.findChild(mainwin, "dlgSimpleFile");
+  engine.findChild(dialog, "inFilename").text = datadir + "/" + name;
+
+  //=== Accepting text
+  dialog.accept();
+  thread.wait(1000);
+}
+
+function enterSnakeMode(pos_x, pos_y, pos_z, size_x, size_y, size_z)
+{
+  //=== Entering snake mode
+  engine.findChild(mainwin,"actionSnake").trigger();
+
+  var roipanel = engine.findChild(mainwin, "pageSnakeTool");
+
+  //=== Setting ROI dimensions
+  engine.findChild(roipanel,"inIndexX").value = pos_x;
+  engine.findChild(roipanel,"inIndexY").value = pos_y;
+  engine.findChild(roipanel,"inIndexZ").value = pos_z;
+  engine.findChild(roipanel,"inSizeX").value = size_x;
+  engine.findChild(roipanel,"inSizeY").value = size_y;
+  engine.findChild(roipanel,"inSizeZ").value = size_z;
+
+  //=== Pushing the Segment3D button
+  engine.findChild(roipanel,"btnAuto").click();
+  thread.wait(1000);
+}
+
+function enterSnakeModeFullROI()
+{
+  //=== Entering snake mode
+  engine.findChild(mainwin,"actionSnake").trigger();
+
+  var roipanel = engine.findChild(mainwin, "pageSnakeTool");
+
+  //=== Resetting ROI
+  engine.findChild(roipanel,"btnResetROI").click();
+
+  //=== Pushing the Segment3D button
+  engine.findChild(roipanel,"btnAuto").click();
+  thread.wait(1000);
+}
+
+function readVoxelIntensity(layer_row)
+{
+  var voxtable = engine.findChild(mainwin, "tableVoxelUnderCursor");
+  value = engine.tableItemText(voxtable, layer_row, 1);
+
+  return value;
+}
+
+function setForegroundLabel(label_text)
+{
+  var combo = engine.findChild(mainwin,"inForeLabel");
+  var index = engine.findItemRow(combo,label_text);
+  engine.print("Setting foreground label to " + label_text + " at pos " + index)
+  combo.setCurrentIndex(index);
+
+}
+
+function setBackgroundLabel(label_text)
+{
+  var combo = engine.findChild(mainwin,"inBackLabel");
+  var index = engine.findItemRow(combo,label_text);
+  engine.print("Setting background label to " + label_text + " at pos " + index)
+  combo.setCurrentIndex(index);
+
+}
diff --git a/Testing/GUI/Qt/Scripts/test_ProbeIntensity.js b/Testing/GUI/Qt/Scripts/test_ProbeIntensity.js
new file mode 100644
index 0000000..562f09b
--- /dev/null
+++ b/Testing/GUI/Qt/Scripts/test_ProbeIntensity.js
@@ -0,0 +1,16 @@
+// This script positions the cursor and checks image intensity
+
+// Call the open image script
+thread.source("Library")
+
+// Open the test image
+openMainImage("MRIcrop-orig.gipl.gz");
+
+// Put cursor somewhere
+setCursor(75,6,27);
+
+// Check the image intensity
+var value = readVoxelIntensity(0);
+
+// Validate
+engine.validateValue(value, 54)
diff --git a/Testing/GUI/Qt/Scripts/test_RandomForest.js b/Testing/GUI/Qt/Scripts/test_RandomForest.js
new file mode 100644
index 0000000..c16d4e1
--- /dev/null
+++ b/Testing/GUI/Qt/Scripts/test_RandomForest.js
@@ -0,0 +1,89 @@
+// Read the function library
+thread.source("Library");
+
+// Open the test workspace
+openWorkspace("tensor.itksnap");
+
+// Enter snake mode
+enterSnakeModeFullROI();
+
+//=== Entering classification mode
+var snakepanel = engine.findChild(mainwin,"SnakeWizardPanel");
+var combo = engine.findChild(snakepanel,"inPreprocessMode");
+var index = engine.findItemRow(combo,"Classification");
+combo.setCurrentIndex(index);
+
+//=== Show just the axial view
+engine.findChild(mainwin, "btnAxial").click();
+
+// Get the axial panel
+var panel0 = engine.findChild(mainwin,"panel0");
+var sliceView0 = engine.findChild(panel0,"sliceView");
+
+//=== Enter paintbrush mode
+engine.findChild(mainwin,"actionPaintbrush").trigger();
+
+//=== Paint with foreground label
+setForegroundLabel("Label 1");
+setCursor(20,8,13);
+engine.postKeyEvent(sliceView0, "Space");
+
+//=== Paint with background label
+setForegroundLabel("Label 2");
+setCursor(10,24,13);
+engine.postKeyEvent(sliceView0, "Space");
+
+//=== Paint with background label
+setForegroundLabel("Label 3");
+setCursor(26,28,13);
+engine.postKeyEvent(sliceView0, "Space");
+
+//=== Perform classification
+engine.findChild(snakepanel,"btnClassifyTrain").click();
+
+//=== Clear segmentation
+engine.findChild(snakepanel,"btnClassifyClearExamples").click();
+
+//=== Go to bubble mode
+engine.findChild(snakepanel,"btnNextPreproc").click();
+thread.wait(1000);
+
+//=== Go back to the first seed 
+setCursor(20,8,13);
+
+//=== Validating speed image
+engine.validateFloatValue(readVoxelIntensity(4), 0.8, 0.4)
+
+//=== Add a bubble
+engine.findChild(snakepanel,"btnAddBubble").click();
+
+//=== Set bubble radius
+engine.findChild(snakepanel,"inBubbleRadius").value = 4;
+
+//=== Go to snake mode
+engine.findChild(snakepanel,"btnBubbleNext").click();
+thread.wait(1000);
+
+//=== Set step size
+engine.findChild(snakepanel,"inStepSize").value = 10;
+
+//=== Run snake 100 iter
+for(var i = 0; i < 10; i++)
+{
+  engine.findChild(snakepanel,"btnSingleStep").click();
+  
+}
+
+//=== Finish snake mode
+engine.findChild(snakepanel,"btnEvolutionNext").click()
+thread.wait(1000)
+
+//=== Open volumes and statistics
+engine.findChild(mainwin,"actionVolumesAndStatistics").trigger();
+
+//=== Check the value
+var dialog = engine.findChild(mainwin, "dlgStatistics");
+var table =  engine.findChild(dialog, "tvVolumes");
+var value =  engine.tableItemText(table,1,1);
+engine.validateFloatValue(value, 1200, 600);
+
diff --git a/Testing/GUI/Qt/Scripts/test_RegionCompetition.js b/Testing/GUI/Qt/Scripts/test_RegionCompetition.js
new file mode 100644
index 0000000..4bf967a
--- /dev/null
+++ b/Testing/GUI/Qt/Scripts/test_RegionCompetition.js
@@ -0,0 +1,56 @@
+// Read the function library
+thread.source("Library");
+
+// Open the test image
+openMainImage("MRIcrop-orig.gipl.gz");
+
+// Enter snake mode
+enterSnakeMode(10, 10, 10, 32, 32, 32);
+
+//=== Entering thresholding mode
+var snakepanel = engine.findChild(mainwin,"SnakeWizardPanel");
+var combo = engine.findChild(snakepanel,"inPreprocessMode");
+var index = engine.findItemRow(combo,"Thresholding");
+combo.setCurrentIndex(index);
+
+//=== Setting thresholds
+engine.findChild(snakepanel,"inThreshLowerSpin").value = 24.0;
+engine.findChild(snakepanel,"inThreshUpperSpin").value = 57.0;
+
+//=== Validating speed image
+setCursor(17, 15, 20);
+engine.validateFloatValue(readVoxelIntensity(1), -0.2263, 0.0001)
+
+//=== Go to bubble mode
+engine.findChild(snakepanel,"btnNextPreproc").click();
+thread.wait(1000);
+
+//=== Add a bubble
+engine.findChild(snakepanel,"btnAddBubble").click();
+
+//=== Go to snake mode
+engine.findChild(snakepanel,"btnBubbleNext").click();
+thread.wait(1000);
+
+//=== Validating level set image
+engine.validateValue(readVoxelIntensity(2), -4);
+
+//=== Set step size
+engine.findChild(snakepanel,"inStepSize").value = 10;
+
+//=== Run snake one iter
+engine.findChild(snakepanel,"btnSingleStep").click();
+
+//=== Run snake one iter
+engine.findChild(snakepanel,"btnSingleStep").click();
+
+//=== Validating level set image
+setCursor(16, 15, 20);
+engine.validateFloatValue(readVoxelIntensity(2), -0.9371, 0.2)
+
+//=== Finish snake mode
+engine.findChild(snakepanel,"btnEvolutionNext").click()
+
+//=== Validate segmentation
+value = engine.findChild(mainwin, "outLabelId").value
+engine.validateValue(value, 1)
diff --git a/Testing/GUI/Qt/Scripts/test_Workspace.js b/Testing/GUI/Qt/Scripts/test_Workspace.js
new file mode 100644
index 0000000..c5465ac
--- /dev/null
+++ b/Testing/GUI/Qt/Scripts/test_Workspace.js
@@ -0,0 +1,40 @@
+// Read the function library
+thread.source("Library");
+
+// Open the test workspace
+openWorkspace("tensor.itksnap");
+
+//=== Show the layer inspector
+engine.findChild(mainwin,"actionLayerInspector").trigger();
+
+//=== Select a specific overlay
+var layerdialog = engine.findChild(mainwin,"dlgLayerInspector");
+var rowdelegate = engine.findChild(layerdialog, "wgtRowDelegate_0003");
+rowdelegate.setSelected(true);
+
+//=== Toggle the layout
+engine.findChild(layerdialog, "actionLayoutToggle").trigger();
+
+//=== Go to the color map widget
+var cmpcolormap = engine.findChild(layerdialog, "cmpColorMap");
+engine.findChild(layerdialog, "tabWidget").setCurrentWidget(cmpcolormap);
+
+//=== Select the color map preset we want
+var inpreset = engine.findChild(cmpcolormap, "inPreset");
+inpreset.setCurrentText("Summer");
+
+//=== Close the inspector dialog
+layerdialog.close();
+
+//=== Trigger the unload all action
+engine.findChild(mainwin,"actionUnload_All").trigger();
+
+//=== Check that the unsaved changes dialog is open
+var savedialog = engine.findWidget("dlgSaveModified");
+if(!savedialog.visible)
+    engine.testFailed("Saved dialog was not shown")
+
+//=== Count the number of entries in the dialog
+var layertable = engine.findChild(savedialog, "tableLayers");
+var entry = engine.tableItemText(layertable, 0, 0);
+engine.validateValue(entry, "Workspace");
diff --git a/Testing/GUI/Qt/TestingScripts.qrc b/Testing/GUI/Qt/TestingScripts.qrc
new file mode 100644
index 0000000..f6deb02
--- /dev/null
+++ b/Testing/GUI/Qt/TestingScripts.qrc
@@ -0,0 +1,9 @@
+<RCC>
+    <qresource prefix="/scripts">
+      <file>Scripts/test_Library.js</file>
+      <file>Scripts/test_ProbeIntensity.js</file>
+      <file>Scripts/test_RegionCompetition.js</file>
+      <file>Scripts/test_RandomForest.js</file>
+      <file>Scripts/test_Workspace.js</file>
+    </qresource>
+</RCC>
diff --git a/Testing/Logic/SNAPTestDriver.cxx b/Testing/Logic/SNAPTestDriver.cxx
new file mode 100644
index 0000000..125d07f
--- /dev/null
+++ b/Testing/Logic/SNAPTestDriver.cxx
@@ -0,0 +1,256 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: SNAPTestDriver.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/14 18:09:25 $
+  Version:   $Revision: 1.5 $
+  Copyright (c) 2003 Insight Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even 
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     PURPOSE.  See the above copyright notices for more information.
+=========================================================================*/
+#include "SNAPTestDriver.h"
+#include "TestImageWrapper.h"
+#include "GreyImageWrapper.h"
+#include "LabelImageWrapper.h"
+#include "SpeedImageWrapper.h"
+
+
+#include "CommandLineArgumentParser.h"
+#include <iostream>
+#include <iomanip>
+
+using namespace std;
+
+const unsigned int SNAPTestDriver::NUMBER_OF_TESTS = 4;
+const char *SNAPTestDriver::m_TestNames[] = { "ImageWrapper",
+  "IRISImageData","SNAPImageData","Preprocessing" };
+const bool SNAPTestDriver::m_TestTemplated[] = { true, false, false, false };
+
+void
+SNAPTestDriver
+::PrintUsage()
+{
+  std::cerr << "SNAP Test Driver Usage:" << std::endl;
+  std::cerr << "  SNAPTest list" << std::endl;
+  std::cerr << "or " << std::endl;
+  std::cerr << "  SNAPTest help NAME " << std::endl;
+  std::cerr << "or " << std::endl;
+  std::cerr << "  SNAPTest test NAME [type TYPE] [options]" << std::endl;
+  std::cerr << "Commands :" << std::endl;
+  std::cerr << "  list                List all known tests" << std::endl;
+  std::cerr << "  help NAME           Provide help on test 'NAME'" << std::endl;
+  std::cerr << "  test NAME           Run test 'NAME'" << std::endl;
+  std::cerr << "  type TYPE           Specify template parameter of test" << std::endl;    
+  std::cerr << "                      (e.g., unsigned_short)" << std::endl;      
+}
+
+template <class TPixel> 
+SNAPTestDriver::TemplatedTestCreator<TPixel>
+::TemplatedTestCreator(const char *name)
+{
+  string strName = name;
+
+  if(strName == "ImageWrapper")
+    {
+    if(typeid(TPixel) == typeid(GreyType))
+      m_Test = new TestImageWrapper<GreyType, GreyImageWrapper<GreyType> >();
+    else if(typeid(TPixel) == typeid(LabelType))
+      m_Test = new TestImageWrapper<LabelType, LabelImageWrapper>();
+    else if(typeid(TPixel) == typeid(float))
+      m_Test = new TestImageWrapper<float, SpeedImageWrapper>();
+    else
+      m_Test = NULL;
+    }
+  else
+    m_Test = NULL;
+}
+
+template <class TPixel> 
+TestBase *
+SNAPTestDriver::TemplatedTestCreator<TPixel>
+::GetTest()
+{
+  return m_Test;
+}
+  
+TestBase *
+SNAPTestDriver
+::CreateNonTemplateTest(const char *name)
+{
+  string strName = name;
+  TestBase *test = NULL;
+ 
+  return test;
+}
+
+TestBase *
+SNAPTestDriver
+::CreateTestInstance(const char *name)
+{
+  TestBase *test = CreateNonTemplateTest(name);
+  if(!test)
+    test = TemplatedTestCreator<unsigned char>(name).GetTest();
+  return test;
+}
+
+void
+SNAPTestDriver
+::Run(int argc, char *argv[])
+{
+  // Configure the command line
+  CommandLineArgumentParser clap;
+  clap.AddOption("help",1);
+  clap.AddOption("list",0);
+  clap.AddOption("test",1);
+  clap.AddOption("type",1);
+
+  // Parse the command line
+  CommandLineArgumentParseResult parms;
+  if(!clap.TryParseCommandLine(argc,argv,parms,false))
+    {
+    PrintUsage();
+    return;
+    }
+
+  // Check if the user wants help
+  if(parms.IsOptionPresent("help"))
+    {
+    // Get the file name
+    const char *name = parms.GetOptionParameter("help");
+    
+    // Create a test instance, ingoring type
+    TestBase *test = CreateTestInstance(name);
+
+    // Print test usage
+    if(test)
+      {
+      std::cout << "SNAPTests " << name << " options" << std::endl;
+      std::cout << "Options: " << std::endl;
+      test->PrintUsage();
+      }
+      
+    else
+      std::cerr << "Unknown test name: " << name << std::endl;
+    }
+
+  else if(parms.IsOptionPresent("list"))
+    {
+    // Print out a header
+    std::cout << std::setw(20) << std::ios::left << "Test Name";
+    std::cout << std::setw(12) << std::ios::left << "Templated";
+    std::cout << "Description" << std::endl;
+    
+    // Go through the list of known tests
+    for(unsigned int i=0;i<NUMBER_OF_TESTS;i++)
+      {
+      TestBase *test = CreateTestInstance(m_TestNames[i]);
+
+      if(test) 
+        {
+        // Print out test info
+        std::cout << std::setw(20) << std::ios::left << m_TestNames[i];
+        std::cout << std::setw(12) << std::ios::left << (m_TestTemplated[i] ? "Yes" : "No");
+        std::cout << test->GetDescription() << std::endl;
+        }
+      }
+    }
+  else if(parms.IsOptionPresent("test"))
+    {
+    // Get the file name
+    const char *name = parms.GetOptionParameter("test");
+  
+    // Check if the test can be created without a template parameter
+    TestBase *test = CreateNonTemplateTest(name);
+
+    // If that failed, check if the test can be created using a template 
+    // parameter
+    if(!test && (test = TemplatedTestCreator<unsigned char>(name).GetTest()))
+      {
+      // Get the template type or a blank string
+      string type = parms.IsOptionPresent("type") ? 
+        parms.GetOptionParameter("type") : "";
+
+      // Instantiate the template test of the right type
+      if(type == "char")      
+        test = TemplatedTestCreator<char>(name).GetTest();
+      else if(type == "unsigned_char") 
+        test = TemplatedTestCreator<unsigned char>(name).GetTest();
+      if(type == "short")      
+        test = TemplatedTestCreator<short>(name).GetTest();
+      else if(type == "unsigned_short") 
+        test = TemplatedTestCreator<unsigned short>(name).GetTest();
+      if(type == "int")      
+        test = TemplatedTestCreator<int>(name).GetTest();
+      else if(type == "unsigned_int") 
+        test = TemplatedTestCreator<unsigned int>(name).GetTest();
+      if(type == "long")      
+        test = TemplatedTestCreator<long>(name).GetTest();
+      else if(type == "unsigned_long") 
+        test = TemplatedTestCreator<unsigned long>(name).GetTest();
+      if(type == "float")      
+        test = TemplatedTestCreator<float>(name).GetTest();
+      else if(type == "double") 
+        test = TemplatedTestCreator<double>(name).GetTest();
+      else
+        {
+        std::cerr << "Missing or invalid or missing type parameter.  Using default (char)" << std::endl;
+        std::cerr << "Should be one of: " << std::endl;
+        std::cerr << "  char, unsigned_char," << std::endl;
+        std::cerr << "  short, unsigned_short," << std::endl;
+        std::cerr << "  int, unsigned_int," << std::endl;
+        std::cerr << "  long, unsigned_long," << std::endl;
+        std::cerr << "  float, " << std::endl;
+        std::cerr << "  double." << std::endl;
+        }
+      }
+
+    // See if a test has been created after all
+    if(test) 
+      {
+      try 
+        {
+        // Configure the parameters of the test
+        test->ConfigureCommandLineParser(clap);
+
+        // Get the command line result
+        CommandLineArgumentParseResult testParms;
+        if(clap.TryParseCommandLine(argc,argv,testParms,false))
+          {
+          test->SetCommandLineParameters(testParms);
+          test->Run();
+          }
+        else
+          {
+          test->PrintUsage();
+          }
+        
+        delete test;
+        }
+      catch(TestUsageException)
+        {
+        test->PrintUsage();
+        }
+      catch(itk::ExceptionObject &exc)
+        {
+        std::cerr << "ITK Exception: " << std::endl << exc << std::endl;
+        }
+      catch(...)
+        {
+        std::cerr << "Unknowm Exception!" << std::endl;
+        }
+      }
+    else
+      {
+      std::cerr << "Could not create test!" << std::endl;
+      PrintUsage();
+      }    
+    }
+  else
+    {
+    PrintUsage();
+    }
+}
diff --git a/Testing/SNAPTestDriver.h b/Testing/Logic/SNAPTestDriver.h
similarity index 100%
rename from Testing/SNAPTestDriver.h
rename to Testing/Logic/SNAPTestDriver.h
diff --git a/Testing/TestBase.h b/Testing/Logic/TestBase.h
similarity index 100%
rename from Testing/TestBase.h
rename to Testing/Logic/TestBase.h
diff --git a/Testing/TestCompareLevelSets.cxx b/Testing/Logic/TestCompareLevelSets.cxx
similarity index 100%
rename from Testing/TestCompareLevelSets.cxx
rename to Testing/Logic/TestCompareLevelSets.cxx
diff --git a/Testing/TestCompareLevelSets.h b/Testing/Logic/TestCompareLevelSets.h
similarity index 100%
rename from Testing/TestCompareLevelSets.h
rename to Testing/Logic/TestCompareLevelSets.h
diff --git a/Testing/Logic/TestImageWrapper.h b/Testing/Logic/TestImageWrapper.h
new file mode 100644
index 0000000..9c93882
--- /dev/null
+++ b/Testing/Logic/TestImageWrapper.h
@@ -0,0 +1,93 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: TestImageWrapper.h,v $
+  Language:  C++
+  Date:      $Date: 2009/11/14 16:19:56 $
+  Version:   $Revision: 1.3 $
+  Copyright (c) 2003 Insight Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even 
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     PURPOSE.  See the above copyright notices for more information.
+=========================================================================*/
+#ifndef __TestImageWrapper_h_
+#define __TestImageWrapper_h_
+
+#include "TestBase.h"
+#include "ScalarImageWrapper.h"
+#include "GreyImageWrapper.h"
+#include "LabelImageWrapper.h"
+
+/**
+ * This class is used to test the functionality in the ImageWrapper class
+ */
+template<class TPixel, class TWrapper>
+class TestImageWrapper : public TestBaseOneImage<TPixel>
+{
+public:
+  typedef TestBaseOneImage<TPixel> Superclass;
+  typedef TWrapper WrapperType;
+
+  void PrintUsage();
+  void Run();
+    
+  const char *GetTestName() 
+  { 
+    return "ImageWrapper"; 
+  }
+  
+  const char *GetDescription()
+  { 
+    return "A suite of ImageWrapper tests"; 
+  }
+};
+
+template<class TPixel, class TWrapper> 
+void TestImageWrapper<TPixel, TWrapper> 
+::PrintUsage() 
+{
+  // Run the parent's part of the test
+  Superclass::PrintUsage();
+
+  // RAI may be passed to this test
+  std::cout << "  rai CODE : Pass in an RAI anatomy-image code" << std::endl;
+}
+
+template<class TPixel, class TWrapper> 
+void TestImageWrapper<TPixel, TWrapper> 
+::Run() 
+{
+  // Run the parent's part of the test (loads image)
+  Superclass::Run();
+
+  // Do the rest
+  std::cout << "Testing code in ImageWrapper.h" << std::endl;
+
+  // Create an image wrapper
+  WrapperType *wrapper = new WrapperType();
+
+  // Insert image into the wrapper
+  wrapper->SetImage(this->m_Image);
+  
+  // Set the cursor position in the slice wrapper
+  wrapper->SetSliceIndex(wrapper->GetSize() / ((unsigned int)2));
+
+  // Create a transform that specifies the image-slice geometry
+  ImageCoordinateTransform ict;
+  ict.SetTransform(Vector3i(-2,1,-3),wrapper->GetSize());
+  
+  // Report min/max intensities
+  std::cout << "Max intensity: " << wrapper->GetImageMax() << std::endl;
+  std::cout << "Min intensity: " << wrapper->GetImageMin() << std::endl;
+
+  // We are finished testing
+  std::cout << "Testing complete" << std::endl;
+}
+
+#endif //__TestImageWrapper_h_
+
+
+
+
diff --git a/Testing/TestMain.cxx b/Testing/Logic/TestMain.cxx
similarity index 100%
rename from Testing/TestMain.cxx
rename to Testing/Logic/TestMain.cxx
diff --git a/Testing/TutorialTest.cxx b/Testing/Logic/TutorialTest.cxx
similarity index 100%
rename from Testing/TutorialTest.cxx
rename to Testing/Logic/TutorialTest.cxx
diff --git a/Testing/SNAPTestDriver.cxx b/Testing/SNAPTestDriver.cxx
deleted file mode 100644
index 26f8d3a..0000000
--- a/Testing/SNAPTestDriver.cxx
+++ /dev/null
@@ -1,256 +0,0 @@
-/*=========================================================================
-
-  Program:   Insight Segmentation & Registration Toolkit
-  Module:    $RCSfile: SNAPTestDriver.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/14 18:09:25 $
-  Version:   $Revision: 1.5 $
-  Copyright (c) 2003 Insight Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-#include "SNAPTestDriver.h"
-#include "TestImageWrapper.h"
-#include "GreyImageWrapper.h"
-#include "LabelImageWrapper.h"
-#include "SpeedImageWrapper.h"
-
-
-#include "CommandLineArgumentParser.h"
-#include <iostream>
-#include <iomanip>
-
-using namespace std;
-
-const unsigned int SNAPTestDriver::NUMBER_OF_TESTS = 4;
-const char *SNAPTestDriver::m_TestNames[] = { "ImageWrapper",
-  "IRISImageData","SNAPImageData","Preprocessing" };
-const bool SNAPTestDriver::m_TestTemplated[] = { true, false, false, false };
-
-void
-SNAPTestDriver
-::PrintUsage()
-{
-  std::cerr << "SNAP Test Driver Usage:" << std::endl;
-  std::cerr << "  SNAPTest list" << std::endl;
-  std::cerr << "or " << std::endl;
-  std::cerr << "  SNAPTest help NAME " << std::endl;
-  std::cerr << "or " << std::endl;
-  std::cerr << "  SNAPTest test NAME [type TYPE] [options]" << std::endl;
-  std::cerr << "Commands :" << std::endl;
-  std::cerr << "  list                List all known tests" << std::endl;
-  std::cerr << "  help NAME           Provide help on test 'NAME'" << std::endl;
-  std::cerr << "  test NAME           Run test 'NAME'" << std::endl;
-  std::cerr << "  type TYPE           Specify template parameter of test" << std::endl;    
-  std::cerr << "                      (e.g., unsigned_short)" << std::endl;      
-}
-
-template <class TPixel> 
-SNAPTestDriver::TemplatedTestCreator<TPixel>
-::TemplatedTestCreator(const char *name)
-{
-  string strName = name;
-
-  if(strName == "ImageWrapper")
-    {
-    if(typeid(TPixel) == typeid(GreyType))
-      m_Test = new TestImageWrapper<GreyType, GreyImageWrapper>();
-    else if(typeid(TPixel) == typeid(LabelType))
-      m_Test = new TestImageWrapper<LabelType, LabelImageWrapper>();
-    else if(typeid(TPixel) == typeid(float))
-      m_Test = new TestImageWrapper<float, SpeedImageWrapper>();
-    else
-      m_Test = NULL;
-    }
-  else
-    m_Test = NULL;
-}
-
-template <class TPixel> 
-TestBase *
-SNAPTestDriver::TemplatedTestCreator<TPixel>
-::GetTest()
-{
-  return m_Test;
-}
-  
-TestBase *
-SNAPTestDriver
-::CreateNonTemplateTest(const char *name)
-{
-  string strName = name;
-  TestBase *test = NULL;
- 
-  return test;
-}
-
-TestBase *
-SNAPTestDriver
-::CreateTestInstance(const char *name)
-{
-  TestBase *test = CreateNonTemplateTest(name);
-  if(!test)
-    test = TemplatedTestCreator<unsigned char>(name).GetTest();
-  return test;
-}
-
-void
-SNAPTestDriver
-::Run(int argc, char *argv[])
-{
-  // Configure the command line
-  CommandLineArgumentParser clap;
-  clap.AddOption("help",1);
-  clap.AddOption("list",0);
-  clap.AddOption("test",1);
-  clap.AddOption("type",1);
-
-  // Parse the command line
-  CommandLineArgumentParseResult parms;
-  if(!clap.TryParseCommandLine(argc,argv,parms,false))
-    {
-    PrintUsage();
-    return;
-    }
-
-  // Check if the user wants help
-  if(parms.IsOptionPresent("help"))
-    {
-    // Get the file name
-    const char *name = parms.GetOptionParameter("help");
-    
-    // Create a test instance, ingoring type
-    TestBase *test = CreateTestInstance(name);
-
-    // Print test usage
-    if(test)
-      {
-      std::cout << "SNAPTests " << name << " options" << std::endl;
-      std::cout << "Options: " << std::endl;
-      test->PrintUsage();
-      }
-      
-    else
-      std::cerr << "Unknown test name: " << name << std::endl;
-    }
-
-  else if(parms.IsOptionPresent("list"))
-    {
-    // Print out a header
-    std::cout << std::setw(20) << std::ios::left << "Test Name";
-    std::cout << std::setw(12) << std::ios::left << "Templated";
-    std::cout << "Description" << std::endl;
-    
-    // Go through the list of known tests
-    for(unsigned int i=0;i<NUMBER_OF_TESTS;i++)
-      {
-      TestBase *test = CreateTestInstance(m_TestNames[i]);
-
-      if(test) 
-        {
-        // Print out test info
-        std::cout << std::setw(20) << std::ios::left << m_TestNames[i];
-        std::cout << std::setw(12) << std::ios::left << (m_TestTemplated[i] ? "Yes" : "No");
-        std::cout << test->GetDescription() << std::endl;
-        }
-      }
-    }
-  else if(parms.IsOptionPresent("test"))
-    {
-    // Get the file name
-    const char *name = parms.GetOptionParameter("test");
-  
-    // Check if the test can be created without a template parameter
-    TestBase *test = CreateNonTemplateTest(name);
-
-    // If that failed, check if the test can be created using a template 
-    // parameter
-    if(!test && (test = TemplatedTestCreator<unsigned char>(name).GetTest()))
-      {
-      // Get the template type or a blank string
-      string type = parms.IsOptionPresent("type") ? 
-        parms.GetOptionParameter("type") : "";
-
-      // Instantiate the template test of the right type
-      if(type == "char")      
-        test = TemplatedTestCreator<char>(name).GetTest();
-      else if(type == "unsigned_char") 
-        test = TemplatedTestCreator<unsigned char>(name).GetTest();
-      if(type == "short")      
-        test = TemplatedTestCreator<short>(name).GetTest();
-      else if(type == "unsigned_short") 
-        test = TemplatedTestCreator<unsigned short>(name).GetTest();
-      if(type == "int")      
-        test = TemplatedTestCreator<int>(name).GetTest();
-      else if(type == "unsigned_int") 
-        test = TemplatedTestCreator<unsigned int>(name).GetTest();
-      if(type == "long")      
-        test = TemplatedTestCreator<long>(name).GetTest();
-      else if(type == "unsigned_long") 
-        test = TemplatedTestCreator<unsigned long>(name).GetTest();
-      if(type == "float")      
-        test = TemplatedTestCreator<float>(name).GetTest();
-      else if(type == "double") 
-        test = TemplatedTestCreator<double>(name).GetTest();
-      else
-        {
-        std::cerr << "Missing or invalid or missing type parameter.  Using default (char)" << std::endl;
-        std::cerr << "Should be one of: " << std::endl;
-        std::cerr << "  char, unsigned_char," << std::endl;
-        std::cerr << "  short, unsigned_short," << std::endl;
-        std::cerr << "  int, unsigned_int," << std::endl;
-        std::cerr << "  long, unsigned_long," << std::endl;
-        std::cerr << "  float, " << std::endl;
-        std::cerr << "  double." << std::endl;
-        }
-      }
-
-    // See if a test has been created after all
-    if(test) 
-      {
-      try 
-        {
-        // Configure the parameters of the test
-        test->ConfigureCommandLineParser(clap);
-
-        // Get the command line result
-        CommandLineArgumentParseResult testParms;
-        if(clap.TryParseCommandLine(argc,argv,testParms,false))
-          {
-          test->SetCommandLineParameters(testParms);
-          test->Run();
-          }
-        else
-          {
-          test->PrintUsage();
-          }
-        
-        delete test;
-        }
-      catch(TestUsageException)
-        {
-        test->PrintUsage();
-        }
-      catch(itk::ExceptionObject &exc)
-        {
-        std::cerr << "ITK Exception: " << std::endl << exc << std::endl;
-        }
-      catch(...)
-        {
-        std::cerr << "Unknowm Exception!" << std::endl;
-        }
-      }
-    else
-      {
-      std::cerr << "Could not create test!" << std::endl;
-      PrintUsage();
-      }    
-    }
-  else
-    {
-    PrintUsage();
-    }
-}
diff --git a/Testing/TestData/MRIcrop-orig.gipl.gz b/Testing/TestData/MRIcrop-orig.gipl.gz
new file mode 100644
index 0000000..c7c724b
Binary files /dev/null and b/Testing/TestData/MRIcrop-orig.gipl.gz differ
diff --git a/Testing/TestData/MRIcrop-seg.gipl.gz b/Testing/TestData/MRIcrop-seg.gipl.gz
new file mode 100644
index 0000000..0bb2908
Binary files /dev/null and b/Testing/TestData/MRIcrop-seg.gipl.gz differ
diff --git a/Testing/TestData/MRIcrop-seg.label b/Testing/TestData/MRIcrop-seg.label
new file mode 100644
index 0000000..b90494f
--- /dev/null
+++ b/Testing/TestData/MRIcrop-seg.label
@@ -0,0 +1,13 @@
+# IDX   -R-  -G-  -B-  -A--  VIS MSH  LABEL
+    0     0    0    0  0.00  0   0    "Clear"
+    1     0   30  255  1.00  1   1    "vent-lat"
+    2     0  175  255  1.00  1   1    "vent-3rd"
+    3    74    0  255  1.00  1   1    "vent-4th"
+    4   255  255    0  1.00  1   1    "hippo-R"
+    5   145  255   11  1.00  1   1    "hippo-L"
+    6     0  228  255  1.00  1   1    "vent-temp"
+    7   255    0   13  1.00  1   1    "caudates"
+    8   255    8  186  1.00  1   1    "corpus-callosum"
+    9   128   75  113  1.00  1   1    "AC"
+   10   128   64  100  1.00  1   1    "PC"
+   11     4    0  128  1.00  1   1    "arteries"
diff --git a/Testing/TestData/tensor.itksnap b/Testing/TestData/tensor.itksnap
new file mode 100644
index 0000000..532b939
--- /dev/null
+++ b/Testing/TestData/tensor.itksnap
@@ -0,0 +1,338 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--ITK-SNAP (itksnap.org) Project File
+
+This file can be moved/copied along with the images that it references
+as long as the relative location of the images to the project file is 
+the same. Do not modify the SaveLocation entry, or this will not work.
+-->
+<!DOCTYPE registry [
+<!ELEMENT registry (entry*,folder*)>
+<!ELEMENT folder (entry*,folder*)>
+<!ELEMENT entry EMPTY>
+<!ATTLIST folder key CDATA #REQUIRED>
+<!ATTLIST entry key CDATA #REQUIRED>
+<!ATTLIST entry value CDATA #REQUIRED>
+]>
+<registry>
+  <entry key="SaveLocation" value="/Users/pauly/tk/snapdata/newdatarep/diffusion" />
+  <entry key="Version" value="20140108" />
+  <folder key="Layers" >
+    <folder key="Layer[000]" >
+      <entry key="AbsolutePath" value="/Users/pauly/tk/snapdata/newdatarep/diffusion/tensor_t1.nii.gz" />
+      <entry key="Role" value="MainRole" />
+      <folder key="LayerMetaData" >
+        <entry key="Alpha" value="255" />
+        <entry key="CustomNickName" value="T1 MRI" />
+        <entry key="Sticky" value="0" />
+        <folder key="DisplayMapping" >
+          <folder key="ColorMap" >
+            <entry key="Preset" value="Grayscale" />
+          </folder>
+          <folder key="Curve" >
+            <entry key="NumberOfControlPoints" value="3" />
+            <folder key="ControlPoint[0]" >
+              <entry key="tValue" value="0" />
+              <entry key="xValue" value="0" />
+            </folder>
+            <folder key="ControlPoint[1]" >
+              <entry key="tValue" value="0.275" />
+              <entry key="xValue" value="0.5" />
+            </folder>
+            <folder key="ControlPoint[2]" >
+              <entry key="tValue" value="0.55" />
+              <entry key="xValue" value="1" />
+            </folder>
+          </folder>
+        </folder>
+      </folder>
+      <folder key="ProjectMetaData" >
+        <entry key="GaussianBlurScale" value="1" />
+        <entry key="RemappingExponent" value="2" />
+        <entry key="RemappingSteepness" value="0.1" />
+        <folder key="Files" >
+          <folder key="Grey" >
+            <entry key="Dimensions" value="112 112 60" />
+            <entry key="Orientation" value="RPI" />
+          </folder>
+        </folder>
+        <folder key="IRIS" >
+          <entry key="SliceViewLayerLayout" value="Tiled" />
+          <folder key="BoundingBox" >
+            <entry key="InterpolationMethod" value="TriLinear" />
+            <entry key="ResampleDimensions" value="112 112 60" />
+            <folder key="ROIBox[0]" >
+              <entry key="Index" value="0" />
+              <entry key="Size" value="112" />
+            </folder>
+            <folder key="ROIBox[1]" >
+              <entry key="Index" value="0" />
+              <entry key="Size" value="112" />
+            </folder>
+            <folder key="ROIBox[2]" >
+              <entry key="Index" value="0" />
+              <entry key="Size" value="60" />
+            </folder>
+          </folder>
+          <folder key="DisplayMapping" >
+            <folder key="ColorMap" >
+              <entry key="Preset" value="Grayscale" />
+            </folder>
+            <folder key="Curve" >
+              <entry key="NumberOfControlPoints" value="3" />
+              <folder key="ControlPoint[0]" >
+                <entry key="tValue" value="0" />
+                <entry key="xValue" value="0" />
+              </folder>
+              <folder key="ControlPoint[1]" >
+                <entry key="tValue" value="0.275" />
+                <entry key="xValue" value="0.5" />
+              </folder>
+              <folder key="ControlPoint[2]" >
+                <entry key="tValue" value="0.55" />
+                <entry key="xValue" value="1" />
+              </folder>
+            </folder>
+          </folder>
+          <folder key="LabelState" >
+            <entry key="CoverageMode" value="OverAll" />
+            <entry key="DrawingLabel" value="1" />
+            <entry key="OverwriteLabel" value="0" />
+            <entry key="PolygonInvert" value="0" />
+            <entry key="SegmentationAlpha" value="0.5" />
+          </folder>
+          <folder key="LabelTable" >
+            <entry key="NumberOfElements" value="6" />
+            <folder key="Element[0]" >
+              <entry key="Alpha" value="255" />
+              <entry key="Color" value="255 0 0" />
+              <entry key="Flags" value="1 1" />
+              <entry key="Index" value="1" />
+              <entry key="Label" value="Label 1" />
+            </folder>
+            <folder key="Element[1]" >
+              <entry key="Alpha" value="255" />
+              <entry key="Color" value="0 255 0" />
+              <entry key="Flags" value="1 1" />
+              <entry key="Index" value="2" />
+              <entry key="Label" value="Label 2" />
+            </folder>
+            <folder key="Element[2]" >
+              <entry key="Alpha" value="255" />
+              <entry key="Color" value="0 0 255" />
+              <entry key="Flags" value="1 1" />
+              <entry key="Index" value="3" />
+              <entry key="Label" value="Label 3" />
+            </folder>
+            <folder key="Element[3]" >
+              <entry key="Alpha" value="255" />
+              <entry key="Color" value="255 255 0" />
+              <entry key="Flags" value="1 1" />
+              <entry key="Index" value="4" />
+              <entry key="Label" value="Label 4" />
+            </folder>
+            <folder key="Element[4]" >
+              <entry key="Alpha" value="255" />
+              <entry key="Color" value="0 255 255" />
+              <entry key="Flags" value="1 1" />
+              <entry key="Index" value="5" />
+              <entry key="Label" value="Label 5" />
+            </folder>
+            <folder key="Element[5]" >
+              <entry key="Alpha" value="255" />
+              <entry key="Color" value="255 0 255" />
+              <entry key="Flags" value="1 1" />
+              <entry key="Index" value="6" />
+              <entry key="Label" value="Label 6" />
+            </folder>
+          </folder>
+          <folder key="MeshOptions" >
+            <entry key="DecimateFeatureAngle" value="45" />
+            <entry key="DecimateMaximumError" value="0.002" />
+            <entry key="DecimatePreserveTopology" value="1" />
+            <entry key="DecimateTargetReduction" value="0.95" />
+            <entry key="GaussianError" value="0.04" />
+            <entry key="GaussianStandardDeviation" value="0.8" />
+            <entry key="MeshSmoothingBoundarySmoothing" value="0" />
+            <entry key="MeshSmoothingConvergence" value="0" />
+            <entry key="MeshSmoothingFeatureAngle" value="45" />
+            <entry key="MeshSmoothingFeatureEdgeSmoothing" value="0" />
+            <entry key="MeshSmoothingIterations" value="200" />
+            <entry key="MeshSmoothingRelaxationFactor" value="0.01" />
+            <entry key="UseDecimation" value="0" />
+            <entry key="UseGaussianSmoothing" value="1" />
+            <entry key="UseMeshSmoothing" value="0" />
+          </folder>
+        </folder>
+        <folder key="SNAP" >
+          <folder key="SnakeParameters" >
+            <entry key="AdvectionSpeedExponent" value="0" />
+            <entry key="AdvectionWeight" value="0" />
+            <entry key="AutomaticTimeStep" value="1" />
+            <entry key="Clamp" value="1" />
+            <entry key="CurvatureSpeedExponent" value="-1" />
+            <entry key="CurvatureWeight" value="0.2" />
+            <entry key="Ground" value="5" />
+            <entry key="LaplacianSpeedExponent" value="0" />
+            <entry key="LaplacianWeight" value="0" />
+            <entry key="PropagationWeight" value="1" />
+            <entry key="SnakeType" value="RegionCompetition" />
+            <entry key="SolverAlgorithm" value="ParallelSparseField" />
+            <entry key="TimeStepFactor" value="1" />
+          </folder>
+        </folder>
+      </folder>
+    </folder>
+    <folder key="Layer[001]" >
+      <entry key="AbsolutePath" value="/Users/pauly/tk/snapdata/newdatarep/diffusion/tensor_rgb.nii.gz" />
+      <entry key="Role" value="OverlayRole" />
+      <folder key="LayerMetaData" >
+        <entry key="Alpha" value="1" />
+        <entry key="CustomNickName" value="Principal Direction" />
+        <entry key="Sticky" value="0" />
+        <folder key="DisplayMapping" >
+          <entry key="SelectedComponent" value="0" />
+          <entry key="SelectedScalarRep" value="Component" />
+          <entry key="UseRGB" value="1" />
+          <folder key="Average" >
+            <folder key="ColorMap" >
+              <entry key="Preset" value="Jet" />
+            </folder>
+            <folder key="Curve" >
+              <entry key="NumberOfControlPoints" value="3" />
+              <folder key="ControlPoint[0]" >
+                <entry key="tValue" value="0" />
+                <entry key="xValue" value="0" />
+              </folder>
+              <folder key="ControlPoint[1]" >
+                <entry key="tValue" value="0.5" />
+                <entry key="xValue" value="0.5" />
+              </folder>
+              <folder key="ControlPoint[2]" >
+                <entry key="tValue" value="1" />
+                <entry key="xValue" value="1" />
+              </folder>
+            </folder>
+          </folder>
+          <folder key="Component" >
+            <folder key="ColorMap" >
+              <entry key="Preset" value="Jet" />
+            </folder>
+            <folder key="Curve" >
+              <entry key="NumberOfControlPoints" value="3" />
+              <folder key="ControlPoint[0]" >
+                <entry key="tValue" value="0" />
+                <entry key="xValue" value="0" />
+              </folder>
+              <folder key="ControlPoint[1]" >
+                <entry key="tValue" value="0.349999" />
+                <entry key="xValue" value="0.5" />
+              </folder>
+              <folder key="ControlPoint[2]" >
+                <entry key="tValue" value="0.7" />
+                <entry key="xValue" value="1" />
+              </folder>
+            </folder>
+          </folder>
+          <folder key="Magnitude" >
+            <folder key="ColorMap" >
+              <entry key="Preset" value="Jet" />
+            </folder>
+            <folder key="Curve" >
+              <entry key="NumberOfControlPoints" value="3" />
+              <folder key="ControlPoint[0]" >
+                <entry key="tValue" value="0" />
+                <entry key="xValue" value="0" />
+              </folder>
+              <folder key="ControlPoint[1]" >
+                <entry key="tValue" value="0.5" />
+                <entry key="xValue" value="0.5" />
+              </folder>
+              <folder key="ControlPoint[2]" >
+                <entry key="tValue" value="1" />
+                <entry key="xValue" value="1" />
+              </folder>
+            </folder>
+          </folder>
+          <folder key="Maximum" >
+            <folder key="ColorMap" >
+              <entry key="Preset" value="Jet" />
+            </folder>
+            <folder key="Curve" >
+              <entry key="NumberOfControlPoints" value="3" />
+              <folder key="ControlPoint[0]" >
+                <entry key="tValue" value="0" />
+                <entry key="xValue" value="0" />
+              </folder>
+              <folder key="ControlPoint[1]" >
+                <entry key="tValue" value="0.5" />
+                <entry key="xValue" value="0.5" />
+              </folder>
+              <folder key="ControlPoint[2]" >
+                <entry key="tValue" value="1" />
+                <entry key="xValue" value="1" />
+              </folder>
+            </folder>
+          </folder>
+        </folder>
+      </folder>
+    </folder>
+    <folder key="Layer[002]" >
+      <entry key="AbsolutePath" value="/Users/pauly/tk/snapdata/newdatarep/diffusion/tensor_fa.nii.gz" />
+      <entry key="Role" value="OverlayRole" />
+      <folder key="LayerMetaData" >
+        <entry key="Alpha" value="0.53" />
+        <entry key="CustomNickName" value="Fractional Anisotropy" />
+        <entry key="Sticky" value="0" />
+        <folder key="DisplayMapping" >
+          <folder key="ColorMap" >
+            <entry key="Preset" value="Jet" />
+          </folder>
+          <folder key="Curve" >
+            <entry key="NumberOfControlPoints" value="3" />
+            <folder key="ControlPoint[0]" >
+              <entry key="tValue" value="0" />
+              <entry key="xValue" value="0" />
+            </folder>
+            <folder key="ControlPoint[1]" >
+              <entry key="tValue" value="0.4875" />
+              <entry key="xValue" value="0.5" />
+            </folder>
+            <folder key="ControlPoint[2]" >
+              <entry key="tValue" value="0.975" />
+              <entry key="xValue" value="1" />
+            </folder>
+          </folder>
+        </folder>
+      </folder>
+    </folder>
+    <folder key="Layer[003]" >
+      <entry key="AbsolutePath" value="/Users/pauly/tk/snapdata/newdatarep/diffusion/tensor_tr.nii.gz" />
+      <entry key="Role" value="OverlayRole" />
+      <folder key="LayerMetaData" >
+        <entry key="Alpha" value="0.5" />
+        <entry key="CustomNickName" value="Trace" />
+        <entry key="Sticky" value="0" />
+        <folder key="DisplayMapping" >
+          <folder key="ColorMap" >
+            <entry key="Preset" value="Hot" />
+          </folder>
+          <folder key="Curve" >
+            <entry key="NumberOfControlPoints" value="3" />
+            <folder key="ControlPoint[0]" >
+              <entry key="tValue" value="0.15" />
+              <entry key="xValue" value="0" />
+            </folder>
+            <folder key="ControlPoint[1]" >
+              <entry key="tValue" value="0.5" />
+              <entry key="xValue" value="0.5" />
+            </folder>
+            <folder key="ControlPoint[2]" >
+              <entry key="tValue" value="0.85" />
+              <entry key="xValue" value="1" />
+            </folder>
+          </folder>
+        </folder>
+      </folder>
+    </folder>
+  </folder>
+</registry>
diff --git a/Testing/TestData/tensor_fa.nii.gz b/Testing/TestData/tensor_fa.nii.gz
new file mode 100644
index 0000000..1a67ad2
Binary files /dev/null and b/Testing/TestData/tensor_fa.nii.gz differ
diff --git a/Testing/TestData/tensor_rgb.nii.gz b/Testing/TestData/tensor_rgb.nii.gz
new file mode 100644
index 0000000..f2ab33b
Binary files /dev/null and b/Testing/TestData/tensor_rgb.nii.gz differ
diff --git a/Testing/TestData/tensor_t1.nii.gz b/Testing/TestData/tensor_t1.nii.gz
new file mode 100644
index 0000000..8af9247
Binary files /dev/null and b/Testing/TestData/tensor_t1.nii.gz differ
diff --git a/Testing/TestData/tensor_tr.nii.gz b/Testing/TestData/tensor_tr.nii.gz
new file mode 100644
index 0000000..dba1424
Binary files /dev/null and b/Testing/TestData/tensor_tr.nii.gz differ
diff --git a/Testing/TestImageWrapper.h b/Testing/TestImageWrapper.h
deleted file mode 100644
index 716724e..0000000
--- a/Testing/TestImageWrapper.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*=========================================================================
-
-  Program:   Insight Segmentation & Registration Toolkit
-  Module:    $RCSfile: TestImageWrapper.h,v $
-  Language:  C++
-  Date:      $Date: 2009/11/14 16:19:56 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2003 Insight Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-#ifndef __TestImageWrapper_h_
-#define __TestImageWrapper_h_
-
-#include "TestBase.h"
-#include "ScalarImageWrapper.h"
-#include "ScalarImageWrapper.txx"
-#include "GreyImageWrapper.h"
-#include "LabelImageWrapper.h"
-
-/**
- * This class is used to test the functionality in the ImageWrapper class
- */
-template<class TPixel, class TWrapper>
-class TestImageWrapper : public TestBaseOneImage<TPixel>
-{
-public:
-  typedef TestBaseOneImage<TPixel> Superclass;
-  typedef TWrapper WrapperType;
-
-  void PrintUsage();
-  void Run();
-    
-  const char *GetTestName() 
-  { 
-    return "ImageWrapper"; 
-  }
-  
-  const char *GetDescription()
-  { 
-    return "A suite of ImageWrapper tests"; 
-  }
-};
-
-template<class TPixel, class TWrapper> 
-void TestImageWrapper<TPixel, TWrapper> 
-::PrintUsage() 
-{
-  // Run the parent's part of the test
-  Superclass::PrintUsage();
-
-  // RAI may be passed to this test
-  std::cout << "  rai CODE : Pass in an RAI anatomy-image code" << std::endl;
-}
-
-template<class TPixel, class TWrapper> 
-void TestImageWrapper<TPixel, TWrapper> 
-::Run() 
-{
-  // Run the parent's part of the test (loads image)
-  Superclass::Run();
-
-  // Do the rest
-  std::cout << "Testing code in ImageWrapper.h" << std::endl;
-
-  // Create an image wrapper
-  WrapperType *wrapper = new WrapperType();
-
-  // Insert image into the wrapper
-  wrapper->SetImage(this->m_Image);
-  
-  // Set the cursor position in the slice wrapper
-  wrapper->SetSliceIndex(wrapper->GetSize() / ((unsigned int)2));
-
-  // Create a transform that specifies the image-slice geometry
-  ImageCoordinateTransform ict;
-  ict.SetTransform(Vector3i(-2,1,-3),wrapper->GetSize());
-  
-  // Get a slice in the z-direction in the image
-  typename WrapperType::SlicePointer slice = wrapper->GetSlice(0);
-
-  // Report min/max intensities
-  std::cout << "Max intensity: " << wrapper->GetImageMax() << std::endl;
-  std::cout << "Min intensity: " << wrapper->GetImageMin() << std::endl;
-
-  // We are finished testing
-  std::cout << "Testing complete" << std::endl;
-}
-
-#endif //__TestImageWrapper_h_
-
-
-
-
diff --git a/UserInterface/BasicComponents/ColorMapBox.cxx b/UserInterface/BasicComponents/ColorMapBox.cxx
deleted file mode 100644
index d76487f..0000000
--- a/UserInterface/BasicComponents/ColorMapBox.cxx
+++ /dev/null
@@ -1,96 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ColorMapBox.cxx,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:15 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "ColorMapBox.h"
-#include "SNAPOpenGL.h"
-
-ColorMapBox
-::ColorMapBox(int x,int y,int w,int h,const char *label)
-  : FLTKCanvas(x, y, w, h, label)
-{
-  m_RangeStart = 0.0;
-  m_RangeEnd = 0.0;
-}
-
-void
-ColorMapBox
-::draw()
-{
-  // The standard 'valid' business
-  if(!valid())
-    {
-    // Set up the basic projection with a small margin
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    gluOrtho2D(-0.005,1.005,-0.05,1.05);
-    glViewport(0,0,w(),h());
-
-    // Establish the model view matrix
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();    
-    }
-    
-  // Clear the viewport
-  glClearColor(0.0, 0.0, 0.0, 1.0);
-  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
-
-  // Push the related attributes
-  glPushAttrib(GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT | GL_LINE_BIT);
-
-  // Disable lighting
-  glDisable(GL_LIGHTING);
-
-  // Draw the color map
-  glBegin(GL_QUAD_STRIP);
-
-  // Get the colors
-  unsigned int n = 256;
-  for(unsigned int i = 0; i <= n; i++)
-    {
-    double u = i * 1.0 / n;
-    double t = m_RangeStart + u * (m_RangeEnd - m_RangeStart);
-    SpeedColorMap::OutputType xColor = m_ColorMap(t);
-    
-    glColor3ub(xColor[0], xColor[1], xColor[2]);    
-    glVertex2d(u, 0.0); glVertex2d(u, 1.0);
-    }
-  
-  glEnd();
-
-  // Pop the attributes
-  glPopAttrib();
-
-  // Done
-  glFlush();
-}
diff --git a/UserInterface/BasicComponents/ColorMapBox.h b/UserInterface/BasicComponents/ColorMapBox.h
deleted file mode 100644
index 643f0a7..0000000
--- a/UserInterface/BasicComponents/ColorMapBox.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ColorMapBox.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:15 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __ColorMapBox_h_
-#define __ColorMapBox_h_
-
-#include "FLTKCanvas.h"
-#include "SpeedColorMap.h"
-
-/**
- * \class ColorMapBox
- * \brief An FLTK Box used to display a color map
- */
-class ColorMapBox : public FLTKCanvas
-{
-public:
-  /** The standard FLTK window constructor */
-  ColorMapBox(int x,int y,int w,int h,const char *label=NULL);
-
-  /** Set the current color map functor */
-  void SetColorMap(const SpeedColorMap &map)
-    { m_ColorMap = map; redraw(); }
-
-  /** Set the range for the color map */
-  void SetRange(double x0, double x1)
-    { m_RangeStart = x0; m_RangeEnd = x1; }
-  
-  /** The draw method */
-  void draw();
-
-private:
-  SpeedColorMap m_ColorMap;
-  double m_RangeStart, m_RangeEnd;
-};
-
-#endif
diff --git a/UserInterface/BasicComponents/ColorMapWidget.cxx b/UserInterface/BasicComponents/ColorMapWidget.cxx
deleted file mode 100644
index 5c5e700..0000000
--- a/UserInterface/BasicComponents/ColorMapWidget.cxx
+++ /dev/null
@@ -1,420 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ColorMapWidget.cxx,v $
-  Language:  C++
-  Date:      $Date: 2009/09/16 20:03:13 $
-  Version:   $Revision: 1.7 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "ColorMapWidget.h"
-#include "SNAPOpenGL.h"
-#include "LayerInspectorUILogic.h"
-
-ColorMapWidget
-::ColorMapWidget(int x,int y,int w,int h,const char *label)
-  : FLTKCanvas(x, y, w, h, label)
-{
-  m_TextureId = 0xffffffff;
-  m_Interactor = new ColorMapInteraction(this);
-  this->PushInteractionMode(m_Interactor);
-
-  m_Parent = NULL;
-  m_SelectedCMPoint = -1;
-  m_SelectedSide = BOTH;
-}
-
-ColorMapWidget
-::~ColorMapWidget()
-{
-  delete m_Interactor;
-}
-
-void
-ColorMapWidget
-::gl_draw_circle_with_border(double x, double y, double r, bool select)
-{
-  static std::vector<double> cx, cy;
-  if(cx.size() == 0)
-    {
-    for(double a = 0; a < 2 * vnl_math::pi - 1.0e-6; a += vnl_math::pi / 20)
-      {
-      cx.push_back(cos(a));
-      cy.push_back(sin(a));
-      }
-    }
-
-  glPushMatrix();
-  glTranslated(x, y, 0.0);
-  glScaled(1.2 / this->w(), 1.2 / this->h(), 1.0);
-
-  glBegin(GL_TRIANGLE_FAN);
-  glVertex2d(0, 0);
-  for(size_t i = 0; i < cx.size(); i++)
-    glVertex2d(r * cx[i], r * cy[i]);
-  glVertex2d(r, 0);
-  glEnd();
-
-  if(select)
-    glColor3ub(0xff,0x00,0xff);
-  else
-    glColor3ub(0x00,0x00,0x00);
-  
-  glBegin(GL_LINE_LOOP);
-  for(size_t i = 0; i < cx.size(); i++)
-    glVertex2d(r * cx[i], r * cy[i]);
-  glEnd();
-
-  glPopMatrix();
-}
-
-bool
-ColorMapWidget
-::SetSelection(int pt, Side side)
-{
-  bool changed = (m_SelectedCMPoint != pt) || (m_SelectedSide != side);
-  m_SelectedCMPoint = pt;
-  m_SelectedSide = side;
-  if(changed)
-    {
-    this->redraw();
-    m_Parent->OnColorMapSelectedPointUpdate();
-    }
-  return changed;
-}
-
-
-void ColorMapWidget
-::SetSelectedCMPoint(int pt)
-{
-  this->SetSelection(pt, m_SelectedSide);
-}
-
-void ColorMapWidget
-::SetSelectedSide(Side side)
-{
-  this->SetSelection(m_SelectedCMPoint, side);
-}
-
-void
-ColorMapWidget
-::draw()
-{
-  // The standard 'valid' business
-  if(!valid())
-    {
-    // Set up the basic projection with a small margin
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    gluOrtho2D(-0.1,1.1,-0.1,1.1);
-    glViewport(0,0,w(),h());
-
-    // Establish the model view matrix
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();    
-    }
-    
-  // Clear the viewport
-  glClearColor(1.0, 1.0, 1.0, 1.0);
-  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
-
-  // Push the related attributes
-  glPushAttrib(GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT | GL_LINE_BIT | GL_TEXTURE_BIT);
-
-  // Disable lighting
-  glEnable(GL_TEXTURE_2D);
-
-  // Generate the texture for the background
-  const GLsizei boxw = 16;
-  if(m_TextureId == 0xffffffff)
-    {
-    // Create a checkerboard    
-    unsigned char *boxarr = new unsigned char[boxw * boxw], *p = boxarr;
-    for(GLsizei i = 0; i < boxw; i++) 
-      for(GLsizei j = 0; j < boxw; j++)
-        if((i < boxw / 2 && j < boxw / 2) || (i > boxw / 2 && j > boxw / 2))
-          *p++ = 0xef;
-        else
-          *p++ = 0xff;
-
-    glGenTextures(1, &m_TextureId);
-    glBindTexture(GL_TEXTURE_2D, m_TextureId);
-
-    // Properties for the texture
-    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
-    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-
-    // Turn off modulo-4 rounding in GL
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-    glPixelStorei(GL_PACK_ALIGNMENT, 1);
-
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, boxw, boxw, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, boxarr);
-    delete boxarr;
-    }
-
-  // Draw the background pattern
-  glBindTexture(GL_TEXTURE_2D, m_TextureId);
-
-  glColor3ub(0xff,0xff,0xff);
-
-  glBegin(GL_QUADS);
-  double tx = this->w() * 1.0 / boxw;
-  double ty = this->h() * 1.0 / boxw;
-  glTexCoord2d(0.0, 0.0); glVertex2d(-0.1, -0.1);
-  glTexCoord2d(tx, 0.0); glVertex2d(1.1, -0.1);
-  glTexCoord2d(tx, ty); glVertex2d(1.1, 1.1);
-  glTexCoord2d(0.0, ty); glVertex2d(-0.1, 1.1);
-  glEnd();
-
-  glDisable(GL_LIGHTING);
-  glDisable(GL_TEXTURE_2D);
-
-  // Turn on alpha blending
-  glEnable(GL_BLEND);
-  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
-
-  // Get the starting and ending color values
-  ColorMap::RGBAType v0 = m_ColorMap.MapIndexToRGBA(-0.1);
-  ColorMap::RGBAType v1 = m_ColorMap.MapIndexToRGBA(1.1);
-
-  // Draw the actual texture
-  glBegin(GL_QUADS);
-  
-  // Draw the color before 0.0
-  glColor4ub(v0[0], v0[1], v0[2], 0x00); glVertex2d(-0.1,0.0);
-  glColor4ub(v0[0], v0[1], v0[2], 0xff); glVertex2d(-0.1,1.0);
-
-  /*
-  // Draw each of the points
-  for(size_t i = 0; i < m_ColorMap.GetNumberOfCMPoints(); i++)
-    {
-    ColorMap::CMPoint p = m_ColorMap.GetCMPoint(i);
-    glColor4ub(p.m_RGBA[0][0], p.m_RGBA[0][1], p.m_RGBA[0][2], 0xff); 
-    glVertex2d(p.m_Index, 1.0);
-    glColor4ub(p.m_RGBA[0][0], p.m_RGBA[0][1], p.m_RGBA[0][2], 0x00); 
-    glVertex2d(p.m_Index, 0.0);
-    glColor4ub(p.m_RGBA[1][0], p.m_RGBA[1][1], p.m_RGBA[1][2], 0x00); 
-    glVertex2d(p.m_Index, 0.0);
-    glColor4ub(p.m_RGBA[1][0], p.m_RGBA[1][1], p.m_RGBA[1][2], 0xff); 
-    glVertex2d(p.m_Index, 1.0);
-    }
-  */
-  for(size_t i = 0; i < 512; i++)
-    {
-    double t = i / 511.0;
-    ColorMap::RGBAType rgba = m_ColorMap.MapIndexToRGBA(t);
-
-    glColor4ub(rgba[0], rgba[1], rgba[2], 0xff); 
-    glVertex2d(t, 1.0);
-    glColor4ub(rgba[0], rgba[1], rgba[2], 0x00); 
-    glVertex2d(t, 0.0);
-    glColor4ub(rgba[0], rgba[1], rgba[2], 0x00); 
-    glVertex2d(t, 0.0);
-    glColor4ub(rgba[0], rgba[1], rgba[2], 0xff); 
-    glVertex2d(t, 1.0);
-
-    }
-
-  // Draw the color after 1.0
-  glColor4ub(v1[0], v1[1], v1[2], 0xff); glVertex2d(1.1,1.0);
-  glColor4ub(v1[0], v1[1], v1[2], 0x00); glVertex2d(1.1,0.0);
-  
-  // Done drawing
-  glEnd();
-
-  // Draw the gridlines
-  glBegin(GL_LINES);
-  glColor4ub(0x80, 0x80, 0x80, 0xff);
-
-  // Horizontal gridlines
-  glVertex2d(-0.1, 0.0); glVertex2d( 1.1, 0.0);
-  glVertex2d(-0.1, 0.5); glVertex2d( 1.1, 0.5);
-  glVertex2d(-0.1, 1.0); glVertex2d( 1.1, 1.0);
-
-  // Vertical gridlines
-  glVertex2d(0.0, -0.1); glVertex2d(0.0, 1.1);
-  glVertex2d(0.25, -0.1); glVertex2d(0.25, 1.1);
-  glVertex2d(0.5, -0.1); glVertex2d(0.5, 1.1);
-  glVertex2d(0.75, -0.1); glVertex2d(0.75, 1.1);
-  glVertex2d(1.0, -0.1); glVertex2d(1.0, 1.1);
-
-  glEnd();
-
-  // Draw the Alpha curve
-  glEnable(GL_LINE_SMOOTH);
-  glLineWidth(3.0);
-
-  glBegin(GL_LINE_STRIP);
-  glColor4ub(0x00,0x00,0x00,0xff);
-  glVertex2d(-0.1, v0[3] / 255.0);
-  for(size_t i = 0; i < m_ColorMap.GetNumberOfCMPoints(); i++)
-    {
-    ColorMap::CMPoint p = m_ColorMap.GetCMPoint(i);
-    glVertex2d(p.m_Index, p.m_RGBA[0][3] / 255.0);
-    glVertex2d(p.m_Index, p.m_RGBA[1][3] / 255.0);
-    }
-  glVertex2d(1.1, v1[3] / 255.0);
-  glEnd();
-
-  // Draw circles around the points
-  glLineWidth(1.0);
-  for(size_t i = 0; i < m_ColorMap.GetNumberOfCMPoints(); i++)
-    {
-    ColorMap::CMPoint p = m_ColorMap.GetCMPoint(i);
-
-    glColor3ub(p.m_RGBA[0][0],p.m_RGBA[0][1],p.m_RGBA[0][2]);
-    bool select = ((int)i == m_SelectedCMPoint) && (m_SelectedSide != RIGHT);
-    gl_draw_circle_with_border(p.m_Index, p.m_RGBA[0][3] / 255.0, 5.0, select);
-
-    if(p.m_RGBA[0][3] != p.m_RGBA[1][3])
-      {
-      glColor3ub(p.m_RGBA[1][0],p.m_RGBA[1][1],p.m_RGBA[1][2]);
-      bool select = ((int)i == m_SelectedCMPoint) && (m_SelectedSide != LEFT);
-      gl_draw_circle_with_border(p.m_Index, p.m_RGBA[1][3] / 255.0, 5.0, select);
-      }
-    }
-
-
-  // Pop the attributes
-  glPopAttrib();
-
-  // Done
-  glFlush();
-}
-
-
-int 
-ColorMapInteraction
-::OnMousePress(const FLTKEvent &e)
-{
-  // Reference to the color map  
-  ColorMap &cm = m_Parent->m_ColorMap;
-  
-  // Check if the press occurs near a control point
-  for(size_t i = 0; i < cm.GetNumberOfCMPoints(); i++)
-    {
-    ColorMap::CMPoint p = cm.GetCMPoint(i);
-    double dx = fabs(e.XSpace[0] - p.m_Index);
-    double dy0 = fabs(e.XSpace[1] - p.m_RGBA[0][3] / 255.0);
-    double dy1 = fabs(e.XSpace[1] - p.m_RGBA[1][3] / 255.0);
-
-    if(dx / 1.2 < 5.0 / m_Parent->w())
-      {
-      if(dy0 / 1.2 < 5.0 / m_Parent->h())
-        {
-        // We return 0 when the selected point changes to avoid dragging
-        if(p.m_Type == ColorMap::CONTINUOUS)
-          m_Parent->SetSelection(i, ColorMapWidget::BOTH);
-        else
-          m_Parent->SetSelection(i, ColorMapWidget::LEFT);
-        return 1;
-        }
-      else if (dy1 / 1.2 < 5.0 / m_Parent->h())
-        {
-        m_Parent->SetSelection(i, ColorMapWidget::RIGHT);
-        return 1;
-        }
-      }
-    }
-
-  // No selection has been made, so we insert a new point
-  if(e.XSpace[0] > 0.0 && e.XSpace[0] < 1.0)
-    {
-    size_t sel = cm.InsertInterpolatedCMPoint(e.XSpace[0]);
-    m_Parent->SetSelection(sel, ColorMapWidget::BOTH);
-    return 1;
-    }
-
-  return 0;
-}
-
-int 
-ColorMapInteraction
-::OnMouseDrag(const FLTKEvent &e, const FLTKEvent &pe)
-{
-  // Reference to the color map  
-  ColorMap &cm = m_Parent->m_ColorMap;
-  int isel = m_Parent->m_SelectedCMPoint;
-
-  // Nothing happens if zero is selected
-  if(isel < 0) return 0;
-
-  ColorMap::CMPoint psel = cm.GetCMPoint(isel);
-
-  // Get the new alpha and index
-  double j = e.XSpace[0];
-  double a = e.XSpace[1] * 255;
-
-  // Clip the new index
-  if(isel == 0 || isel == (int)cm.GetNumberOfCMPoints()-1)
-    {
-    // The first and last point can not be moved left or right
-    j = psel.m_Index;
-    }
-  else
-    {
-    // Other points are constrained by neighbors
-    ColorMap::CMPoint p0 = cm.GetCMPoint(isel-1);
-    ColorMap::CMPoint p1 = cm.GetCMPoint(isel+1);
-    if(j < p0.m_Index) j = p0.m_Index;
-    if(j > p1.m_Index) j = p1.m_Index;
-    }
-
-  // Update the index of the point
-  psel.m_Index = j;
-
-  // Clip the new alpha
-  if(a < 0) a = 0;
-  if(a > 255) a = 255;
-
-  // Assign the alpha
-  if(m_Parent->m_SelectedSide != ColorMapWidget::RIGHT)
-    psel.m_RGBA[0][3] = (unsigned char) a;
-  if(m_Parent->m_SelectedSide != ColorMapWidget::LEFT)
-    psel.m_RGBA[1][3] = (unsigned char) a;
-
-  // Redraw
-  cm.UpdateCMPoint(isel, psel);
-  m_Parent->redraw();
-
-  // Fire the update event
-  m_Parent->GetParent()->OnColorMapChange();
-
-  return 1;
-}
-
-
-int 
-ColorMapInteraction
-::OnMouseRelease(const FLTKEvent &e, const FLTKEvent &pe)
-{
-  return 1;
-  // return 0; 
-  // this->OnMouseDrag(e,pe);
-}
diff --git a/UserInterface/BasicComponents/ColorMapWidget.h b/UserInterface/BasicComponents/ColorMapWidget.h
deleted file mode 100644
index 9c34064..0000000
--- a/UserInterface/BasicComponents/ColorMapWidget.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ColorMapWidget.h,v $
-  Language:  C++
-  Date:      $Date: 2009/09/16 20:03:13 $
-  Version:   $Revision: 1.6 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __ColorMapWidget_h_
-#define __ColorMapWidget_h_
-
-#include "FLTKCanvas.h"
-#include "ColorMap.h"
-
-class LayerInspectorUILogic;
-class ColorMapInteraction;
-
-/**
- * \class ColorMapWidget
- * \brief An FLTK Box used to display a color map
- */
-class ColorMapWidget : public FLTKCanvas
-{
-public:
-  /** The standard FLTK window constructor */
-  ColorMapWidget(int x,int y,int w,int h,const char *label=NULL);
-  virtual ~ColorMapWidget();
-
-  /** Set the current color map functor */
-  void SetColorMap(const ColorMap &map)
-    { m_ColorMap = map; redraw(); }
-
-  /** Get the current color map functor */
-  ColorMap &GetColorMap()
-    { return m_ColorMap; }
-
-  // Get/set the parent object
-  irisGetMacro(Parent,LayerInspectorUILogic *);
-  irisSetMacro(Parent,LayerInspectorUILogic *);
-
-  /** The draw method */
-  void draw();
-
-  enum Side {LEFT, RIGHT, BOTH};
-
-  irisGetMacro(SelectedSide, Side);
-  irisGetMacro(SelectedCMPoint, int);
-  void SetSelectedCMPoint(int pt);
-  void SetSelectedSide(Side side);
-
-  /** Sets selected point and side, returns true if changed */
-  bool SetSelection(int pt, Side side);
-
-private:
-  ColorMap m_ColorMap;
-
-  unsigned int m_TextureId;
-
-  int m_SelectedCMPoint;
-  Side m_SelectedSide;
-
-  void gl_draw_circle_with_border(double x, double y, double r, bool select);
-
-  /** Parent object */
-  LayerInspectorUILogic *m_Parent;
-
-  ColorMapInteraction *m_Interactor;
-
-  friend class ColorMapInteraction;
-};
-
-class ColorMapInteraction : public InteractionMode
-{
-public:
-  ColorMapInteraction(ColorMapWidget *parent) : InteractionMode(parent)
-    { this->m_Parent = parent; }
-
-  int OnMousePress(const FLTKEvent &e);
-  int OnMouseDrag(const FLTKEvent &e, const FLTKEvent &pe);
-  int OnMouseRelease(const FLTKEvent &e, const FLTKEvent &pe);
-
-private:
-  ColorMapWidget *m_Parent;
-};
-
-#endif
diff --git a/UserInterface/BasicComponents/FLTKCanvas.cxx b/UserInterface/BasicComponents/FLTKCanvas.cxx
deleted file mode 100644
index 659b7d7..0000000
--- a/UserInterface/BasicComponents/FLTKCanvas.cxx
+++ /dev/null
@@ -1,232 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: FLTKCanvas.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/19 20:28:56 $
-  Version:   $Revision: 1.8 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include <cstdlib>
-#include <ctime>
-
-#include "FLTKCanvas.h"
-
-#include <FL/Fl.H>
-#include "SNAPOpenGL.h"
-#include "GLToPNG.h"
-
-using namespace std;
-
-FLTKCanvas
-::FLTKCanvas(int x, int y, int w, int h, const char *label)
-: Fl_Gl_Window(x,y,w,h,label)
-{
-  m_Dragging = false;
-  m_FlipYCoordinate = true;
-  m_GrabFocusOnEntry = false;
-  m_Focus = false;
-  m_DumpPNG = NULL;
-}
-
-void
-FLTKCanvas
-::SaveAsPNG(const char *filename)
-{
-  m_DumpPNG = filename;
-  this->redraw();
-  Fl::flush();
-  m_DumpPNG = NULL;
-}
-
-
-int 
-FLTKCanvas
-::handle(int eventID) 
-{
-  // Create an event object
-  FLTKEvent event;
-  event.Id = eventID;
-
-  // Note that the y coordinate is optionally reflected
-  event.XCanvas[0] = Fl::event_x();
-  event.XCanvas[1] = m_FlipYCoordinate ? h()-1-Fl::event_y() : Fl::event_y();
-  
-  // Get the event timestamp
-  event.Source = this;  
-  event.Button = Fl::event_button();
-  event.State = Fl::event_state();
-  event.Key = Fl::event_key();
-
-  // Construct the software button
-  if(event.Button == FL_LEFT_MOUSE && (event.State & FL_ALT))
-    event.SoftButton = FL_RIGHT_MOUSE;
-  else if(event.Button == FL_LEFT_MOUSE && (event.State & FL_CTRL))
-    event.SoftButton = FL_MIDDLE_MOUSE;
-  else if(event.Button == FL_RIGHT_MOUSE && (event.State & FL_CTRL))
-    event.SoftButton = FL_MIDDLE_MOUSE;
-  else
-    event.SoftButton = event.Button;
-
-  // If the window has not been displayed, we can't compute the 
-  // object space coordinates
-  if (shown() && visible())
-    {
-
-    // Make this window the current context
-    make_current();
-
-    // Convert the event coordinates into the model view coordinates
-    double modelMatrix[16], projMatrix[16];
-    GLint viewport[4];
-    glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
-    glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
-    glGetIntegerv(GL_VIEWPORT,viewport);
-
-    // Projection works with doubles, event is a float
-    Vector3d xProjection;
-    gluUnProject(event.XCanvas[0],event.XCanvas[1],0,
-                 modelMatrix,projMatrix,viewport,
-                 &xProjection[0],&xProjection[1],&xProjection[2]);
-    event.XSpace = to_float(xProjection);
-    }
-
-  // Record the event as the drag-start if the mouse was pressed
-  if (eventID == FL_PUSH)
-    {
-    // Debug positions
-    m_DragStartEvent = event;
-    m_Dragging = true;
-    }
-  else if(eventID == FL_RELEASE)
-    {
-    m_Dragging = false;
-    }
-
-  // Propagate the event through the stack
-  for (list<InteractionMode *>::iterator it = m_Interactors.begin();
-      it != m_Interactors.end();it++)
-    {
-    InteractionMode *mode = *it;
-    int result;
-
-    // Delegate the event base on the ID
-    switch (eventID)
-      {
-      case FL_PUSH : 
-        result = mode->OnMousePress(event);
-        break;
-      case FL_DRAG : 
-        result = mode->OnMouseDrag(event,m_DragStartEvent);
-        break;
-      case FL_RELEASE : 
-        result = mode->OnMouseRelease(event,m_DragStartEvent);
-        break;
-      case FL_ENTER : 
-        result = mode->OnMouseEnter(event);
-        break;
-      case FL_LEAVE : 
-        result = mode->OnMouseLeave(event);
-        break;
-      case FL_MOVE : 
-        result = mode->OnMouseMotion(event);
-        break;
-      case FL_MOUSEWHEEL :
-        result = mode->OnMouseWheel(event);
-        break;
-      case FL_KEYDOWN :
-        result = mode->OnKeyDown(event);
-        break;
-      case FL_KEYUP :
-        result = mode->OnKeyUp(event);
-        break;
-      case FL_SHORTCUT :
-        result = mode->OnShortcut(event);
-        break;
-      case FL_DND_ENTER :
-      case FL_DND_LEAVE :
-      case FL_DND_DRAG :
-      case FL_DND_RELEASE :
-      case FL_PASTE : 
-        result = mode->OnDragAndDrop(event);
-        break;
-      default:
-        result = mode->OnOtherEvent(event);
-      };
-
-    // Break out if the event was taken care of
-    if (result)
-      return 1;
-    }
-
-  // Take care of focus grabbing on entry
-  if(eventID == FL_ENTER && m_GrabFocusOnEntry)
-    {
-    this->take_focus();
-    m_Focus = true;
-    redraw();
-    return 1;
-    }
-  else if(eventID == FL_LEAVE && m_GrabFocusOnEntry)
-    {
-    m_Focus = false;
-    redraw();
-    return 1;
-    }
-  else if(eventID == FL_FOCUS && m_GrabFocusOnEntry)
-    {
-    // m_Focus = true;
-    return 1;
-    }
-  else if(eventID == FL_UNFOCUS && m_GrabFocusOnEntry)
-    {
-    // m_Focus = false;
-    return 1;
-    }
-
-  // The event was not handled
-  return 0;
-}
-
-void
-FLTKCanvas
-::draw()
-{
-  // Let the children do the drawing
-  FireInteractionDrawEvent();
-
-  // dump png if requested
-  if (m_DumpPNG != NULL)
-  {
-    vtkImageData* img = 
-      GLToVTKImageData((unsigned int) GL_RGBA, 0, 0, w(), h());
-    VTKImageDataToPNG(img, m_DumpPNG);
-    img->Delete();
-  }
-}
-
diff --git a/UserInterface/BasicComponents/FLTKCanvas.h b/UserInterface/BasicComponents/FLTKCanvas.h
deleted file mode 100644
index 01af94f..0000000
--- a/UserInterface/BasicComponents/FLTKCanvas.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: FLTKCanvas.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:16 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __FLTKCanvas_h_
-#define __FLTKCanvas_h_
-
-#include <FL/Fl_Gl_Window.H>
-#include "FLTKEvent.h"
-#include "InteractionMode.h"
-#include "InteractionModeClient.h"
-
-#include <list>
-
-/**
- * \class FLTKCanvas
- * \brief An extension of Fl_Gl_Window with advanced interaction handling.
- * 
- * This is an extension of the Fl_Gl_Window from FLTK that allows
- * the concept of interaction modes to be used.  InteractionModes 
- * are event handlers that are associated with different ways of user
- * interaction with the window.  This is used with toolbars, where different
- * toolbar buttons change the behavior of the interaction.  
- * 
- * Multiple interaction modes can be used simultaneously in a stack.  The top mode
- * in the stack is the first to receive events, and the event is propagated through
- * the stack until it has been handled properly.
- */
-class FLTKCanvas : public Fl_Gl_Window, public InteractionModeClient 
-{
-public:
-
-  /** Constructor sets up some basics, sets interaction mode stack to be empty */
-  FLTKCanvas(int x, int y, int w, int h, const char *label);
-  virtual ~FLTKCanvas() {}
-
-  /** Handle events */
-  virtual int handle(int eventID);
-
-  /** Default drawing handler */
-  virtual void draw();
-
-  /** Are we dragging ? */
-  irisIsMacro(Dragging);
-
-  /** Are we flipping? */
-  irisSetMacro(FlipYCoordinate,bool);
-
-  /** Check if keyboard focus is grabbed when the mouse enters the window */
-  irisGetMacro(GrabFocusOnEntry,bool);
-
-  /** Set whether keyboard focus is grabbed when the mouse enters the window */
-  irisSetMacro(GrabFocusOnEntry,bool);
-
-  /** Check if the window has keyboard focus */
-  irisGetMacro(Focus,bool);
-
-  /** Save the window content to a PNG file */
-  void SaveAsPNG(const char *filename);
-
-private:
-
-  // The event at the start of a drag operation (if there is one going on)
-  FLTKEvent m_DragStartEvent;
-
-  // Are we dragging or not
-  bool m_Dragging;
-
-  // Should we flip the Y coordinates of the events (top = 0, bottom = h)
-  bool m_FlipYCoordinate;
-
-  /** Whether the keyboard focus is grabbed when the mouse enters the window */
-  bool m_GrabFocusOnEntry;
-
-  /** Whether the window has keyboard focus */
-  bool m_Focus;
-
-  /** PNG filename to save on the next draw command */
-  const char *m_DumpPNG;
-};
-
-#endif // __FLTKCanvas_h_
-
diff --git a/UserInterface/BasicComponents/FLTKEvent.h b/UserInterface/BasicComponents/FLTKEvent.h
deleted file mode 100644
index 16ca985..0000000
--- a/UserInterface/BasicComponents/FLTKEvent.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: FLTKEvent.h,v $
-  Language:  C++
-  Date:      $Date: 2010/10/19 20:28:56 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __FLTKEvent_h_
-#define __FLTKEvent_h_
-
-#include <FL/Fl.H>
-#include <FL/Enumerations.H>
-
-#include "SNAPCommonUI.h"
-
-class FLTKCanvas;
-
-extern void fl_gettime(long *sec, long *usec);
-
-struct FLTKEventTimeStamp
-{
-  long sec, usec;
-  FLTKEventTimeStamp()
-    { fl_gettime(&sec, &usec); }
-  long ElapsedUSecFrom(const FLTKEventTimeStamp &earlier)
-    { return 1000000 * (sec - earlier.sec) + (usec - earlier.usec); }
-};
-
-/**
- * \class FLTKEvent
- * \brief A wrapper around FLTK event info.
- *
- * \sa FLTKCanvas
- */
-struct FLTKEvent {
-    /** The FLTK id of the event */
-    int Id;
-
-    /** The cursor position of the event in window coordinates */
-    Vector2i XCanvas;
-
-    /** The cursor position of the event in object space coordinates */
-    Vector3f XSpace;
-
-    /** Time when the event was generated (value of the clock() function) */
-    FLTKEventTimeStamp TimeStamp;
-    
-    /** The button that generated this event */
-    int Button;
-
-    /**
-     * The simulated event mouse button.  If user presses CTRL-LEFT, this will
-     * have the value FL_MIDDLE_MOUSE and when the user presses ALT-LEFT, this
-     * will have the value FL_RIGHT_MOUSE.  Useful for Macs and people without
-     * a middle mouse button 
-     */
-    int SoftButton;
-
-    /** The state of the interface (ALT,CTRL,SHIFT) */
-    int State;
-
-    /** The key associated with the event */
-    int Key;
-
-    /**
-     * Pointer to the FLTKCanvas that generated this event.  This is a safety
-     * measure because the recipient of these events should already have such
-     * a pointer to the specific subclass of FLTKCanvas
-     */
-    FLTKCanvas *Source;
-};
-
-#endif // __FLTKEvent_h_
-
diff --git a/UserInterface/BasicComponents/FLTKWidgetActivationManager.h b/UserInterface/BasicComponents/FLTKWidgetActivationManager.h
deleted file mode 100644
index 3cf2d56..0000000
--- a/UserInterface/BasicComponents/FLTKWidgetActivationManager.h
+++ /dev/null
@@ -1,324 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: FLTKWidgetActivationManager.h,v $
-  Language:  C++
-  Date:      $Date: 2008/11/15 12:20:38 $
-  Version:   $Revision: 1.5 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef _FLTKWidgetActivationManager_h_
-#define _FLTKWidgetActivationManager_h_
-
-#include "FL/Fl_Widget.H"
-#include "FL/Fl_Menu_Item.H"
-#include "FL/Fl_Check_Button.H"
-#include <map>
-#include <set>
-#include <list>
-#include <string>
-
-/**
- * \class WidgetActivationManager 
- * \brief A generic state machine for widget management
- * \see FLTKWidgetActivationManager
- */
-template<typename TFlag>
-class WidgetActivationManager {
-public:
-
-  
-  /** Observer, used to callback when a flag changes */
-  class Observer 
-    {
-    public:
-      virtual ~Observer() {};
-      virtual void OnStateChange(TFlag flag, bool value) = 0;
-    };
-
-  /** 
-   * With default parameters, this call specifies that flag A implies flag B.
-   * Using the optional parameters, you can specify A->!B, !A->B or !A->!B.
-   * Read: A in stateA implies B is in stateB 
-   * */
-  void SetFlagImplies(TFlag A, TFlag B, bool stateA=true, bool stateB=true)
-    {
-    // Apply the forward rule
-    m_Flags[A].Rules[ stateA ? 1 : 0 ].push_back( Rule(B, stateB) );
-
-    // Apply the reverse rule
-    m_Flags[B].Rules[ stateB ? 0 : 1 ].push_back( Rule(A, !stateA) );
-    }
-
-  /** 
-   * This is a quick way to set up a set of flags that are mutually exclusive
-   * (but all the flags may be set to false at once)
-   */
-  void SetFlagsMutuallyExclusive( int nFlags, TFlag *F )
-    {
-    // For each flag, set up a rule to all the other flags
-    for(unsigned int i = 0; i < nFlags; i++) 
-      for(unsigned int j = 0; j < i; j++)
-        SetFlagImplies( F[i], F[j], true, false );
-    }
-
-  /** Set up mutual exclusion between three flags */
-  void SetFlagsMutuallyExclusive( TFlag A, TFlag B, TFlag C )
-    {
-    SetFlagImplies( A, B, true, false );
-    SetFlagImplies( A, C, true, false );
-    SetFlagImplies( B, C, true, false );
-    }
-
-  /** Get the value of a flag */
-  bool GetFlag(TFlag flag)
-    { return m_Flags[flag].State; }
-
-  /** 
-   * Add a listener/observer to a flag. When the flag is changed, the observer
-   * is executed with the pointer to the flag that has been changed and its new
-   * value 
-   */
-  void AddObserver(Observer *observer, TFlag flag)
-    {
-    m_Flags[flag].Observers.insert(observer);
-    }
-
-  /** 
-   * Update a flag to a new value. Ignore the third parameter, it
-   * is used internally to throw an exception if the flag machine
-   * enters an infinite loop
-   */
-  void UpdateFlag(TFlag flag, bool value, int recursionCount = 0)
-    {
-    // Do nothing if the flag already has the given value
-    if(m_Flags[flag].State == value) return;
-
-    // Throw an exception if the recursion depth is too great
-    if(recursionCount > static_cast<int>(m_Flags.size()))
-      throw std::string("Infinite loop in the flag state machine!");
-
-    // Get the flag data for this flag
-    FlagData &fd = m_Flags[flag];
-
-    // Update the flag
-    fd.State = value;
-
-    // Trigger all the rules for this flag. We do this before updating the widgets 
-    // so that the settings related to the actual flag being updated are applied last
-    typename std::list<Rule>::iterator itRule = fd.Rules[ value ? 1 : 0 ].begin();   
-    while( itRule != fd.Rules[ value ? 1 : 0 ].end() )
-      {
-      UpdateFlag( itRule->Target, itRule->Value, recursionCount + 1 );
-      ++itRule;
-      }
-
-    // Activate all the widgets tied to this flag
-    typename std::set<WidgetWrapper *>::iterator itWidget = fd.Widgets.begin();    
-    while( itWidget != fd.Widgets.end() )
-      (*itWidget++)->OnStateChange(value);
-
-    // Fire all the observers
-    typename std::set<Observer *>::iterator itObserver = fd.Observers.begin();    
-    while( itObserver != fd.Observers.end() )
-      (*itObserver++)->OnStateChange(flag, value);
-    }
-
-  /** Destructor, deletes widget wrappers */
-  virtual ~WidgetActivationManager()
-    {
-    typename std::set<WidgetWrapper *>::iterator itWidget = m_AllWidgets.begin();
-    while(itWidget != m_AllWidgets.end())
-      delete *(itWidget++);
-    }
-
-  /**
-   * A class used to control the state of an FLTK widget
-   */
-  class WidgetWrapper {
-  public:
-    virtual ~WidgetWrapper() {}
-    virtual void OnStateChange(bool newState) = 0;
-  };
-
-  
-
-protected:
-
-  /** 
-   * A rule relating one flag to another. The rule has a target and a
-   * value. When a rule is triggered, it set's the target flag to the value
-   */
-  struct Rule {
-    // The target of the rule
-    TFlag Target;
-
-    // The value the rule assigns to the target
-    bool Value;
-
-    // A constructor
-    Rule(TFlag target, bool value) : Target(target), Value(value) {}
-  };
-
-  /**
-   * A structure associated with a flag
-   */ 
-  struct FlagData
-    {
-    // A list of rules that are triggered when the flag is set to true
-    // and false states
-    std::list<Rule> Rules[2];
-
-    // A list of widget controllers that are affected by the flag's state
-    std::set<WidgetWrapper *> Widgets;
-
-    // A list of generic observers for this widget
-    std::set<Observer *> Observers;
-
-    // The state of the menu item
-    bool State;
-
-    // Constructor
-    FlagData() { State = false; }
-    };
-
-  /**
-   * Add a controlled widget to a flag. The wrapper will be deleted when
-   * the destructor is called, so don't call delete!
-   */
-  void AddWidgetWrapper(WidgetWrapper *widget, TFlag flag)
-    {
-    m_Flags[flag].Widgets.insert(widget);
-    m_AllWidgets.insert(widget);
-    widget->OnStateChange(false);
-    }
-
-
-private:
-  // A list of flags and associated flag data
-  std::map<TFlag, FlagData> m_Flags;
-
-  // A list of widget wrappers, to be deleted
-  std::set<WidgetWrapper *> m_AllWidgets;
-};
-
-
- /** 
-   * A wrapper for a generic FLTK widget or menu item, calls activate
-   * or deactivate depending on the state 
-   */
-  template<class TWidget,typename TFlag>
-    class GenericWidgetWrapper : public WidgetActivationManager<TFlag>::WidgetWrapper {
-  public:
-    virtual ~GenericWidgetWrapper() {}
-    // State change method
-    virtual void OnStateChange(bool newState) 
-      {
-      if(newState) m_Widget->activate();
-      else m_Widget->deactivate();
-      }
-    
-    // Constructor
-    GenericWidgetWrapper(TWidget *w) : m_Widget(w) {};
-
-  protected:
-    TWidget *m_Widget;
-  };
-
-
-/** 
-   * A special wrapper for FLTK widgets that can be assigned a value. It
-   * can assign a default value to the widget when it's deactivated and when
-   * it's activated
-   */
-  template<class TWidget, class TValue, typename TFlag>
-  class ValuatorWidgetWrapper
-  : public GenericWidgetWrapper<TWidget,TFlag> {
-  public:
-      virtual ~ValuatorWidgetWrapper() {}
-    // State change method
-    virtual void OnStateChange(bool newState)
-      {
-      GenericWidgetWrapper<TWidget,TFlag>::OnStateChange(newState);
-      this->m_Widget->value( newState ? m_OnValue : m_OffValue );
-      }
-
-    // Constructor
-    ValuatorWidgetWrapper(TWidget *w, const TValue &on, const TValue &off)
-      : GenericWidgetWrapper<TWidget,TFlag>(w), m_OffValue(off), m_OnValue(on) {}
-
-  protected:
-    TValue m_OffValue, m_OnValue;
-  };
-
-
-
-
-/**
- * \class FLWidgetActivationManager
- * \brief Simplifies management of widget on/off status
- * This class can link the on-off status of FLTK widgets and menu items
- * with a set of flags in a 'state machine'. The flags can be related to
- * each other, for example, a flag can imply another flag or a set of
- * flags can be mutually exclusive
- */
-template<typename TFlag>
-class FLTKWidgetActivationManager : public WidgetActivationManager<TFlag>
-{
-public:
-  /** Associate an FLTK widget with a flag */
-  void AddWidget(Fl_Widget *widget, TFlag flag)
-    {
-    typedef GenericWidgetWrapper<Fl_Widget,TFlag> WrapperType;
-    AddWidgetWrapper(new WrapperType(widget), flag);
-    }
-
-  /** Associate an FLTK menu item with a flag */
-  void AddMenuItem(Fl_Menu_Item *menu, TFlag flag)
-    {
-    typedef GenericWidgetWrapper<Fl_Menu_Item,TFlag> WrapperType;
-    AddWidgetWrapper(new WrapperType(menu), flag);
-    }
-
-  /** Associate an FLTK checkbox with a flag and two values */
-  void AddCheckBox(Fl_Check_Button *cb, TFlag flag, bool onState, bool offState)
-    {
-    typedef ValuatorWidgetWrapper<Fl_Check_Button, int, TFlag> WrapperType;
-    AddWidgetWrapper(new WrapperType(cb,onState ? 1 : 0,offState ? 1 : 0), flag);    
-    }
-
-protected:
- 
-  
-};
-
-
-
-
-
-#endif
diff --git a/UserInterface/BasicComponents/FunctionPlot2D.cxx b/UserInterface/BasicComponents/FunctionPlot2D.cxx
deleted file mode 100644
index 7800e31..0000000
--- a/UserInterface/BasicComponents/FunctionPlot2D.cxx
+++ /dev/null
@@ -1,178 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: FunctionPlot2D.cxx,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:16 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "FunctionPlot2D.h"
-
-#include "FL/gl.h"
-  
-FunctionPlot2D
-::FunctionPlot2D()
-{
-  m_Settings = FunctionPlot2DSettings::GetDefaultSettings();
-}
-
-void
-FunctionPlot2D
-::SetDataPoints(float *xPoints,float *yPoints,unsigned int nPoints)
-{
-  // Intialize the array
-  m_Points.clear();
-  m_Points.reserve(nPoints);
-  
-  // Fill the array
-  for(unsigned int i=0;i<nPoints;i++)
-    {
-    m_Points.push_back(Vector2f(xPoints[i],yPoints[i]));    
-    }
-}
-
-void
-FunctionPlot2D
-::Draw()
-{
-  // Push the color/blending attributes
-  glPushAttrib(GL_COLOR_BUFFER_BIT);
-
-  // Draw the background rectangle
-  glColor3fv(m_Settings.GetBackgroundColor().data_block());
-  glBegin(GL_QUADS);
-  glVertex2f(0,0);
-  glVertex2f(0,1);
-  glVertex2f(1,1);
-  glVertex2f(1,0);
-  glEnd();
-
-  // Draw the frame around the plot if requested
-  if(m_Settings.GetShowFrame())
-    {
-    glColor3fv(m_Settings.GetFrameColor().data_block());
-    glBegin(GL_LINE_LOOP);
-    glVertex2f(0,0);
-    glVertex2f(0,1);
-    glVertex2f(1,1);
-    glVertex2f(1,0);
-    glEnd();
-    }
-
-  // These are the extents of the plot region
-  Vector2f xMin = m_Settings.GetPlotRangeMin();
-  Vector2f xMax = m_Settings.GetPlotRangeMax();
-
-  // Make sure these points create a rectangle
-  assert(xMin(0) < xMax(0) && xMin(1) < xMax(1));
-  
-  // Change the view matrix to the passed in coordinates
-  glMatrixMode(GL_MODELVIEW);
-  glPushMatrix();
-  glScalef(1.0f / (xMax(0) - xMin(0)), 1.0f / (xMax(1) - xMin(1)), 1.0f);
-  glTranslatef(-xMin(0),-xMin(1),0.0f);
-
-  // Do we draw the axes?
-  if(m_Settings.GetShowAxes())
-    {
-
-    // First draw the ticks, or it may look ugly
-    if(m_Settings.GetShowMajorTicks())
-      {
-      
-      }
-
-    if(m_Settings.GetShowMinorTicks())
-      {
-
-      }
-
-    // Now draw the axes
-    Vector2f xAxes = m_Settings.GetAxesPosition();
-
-    glColor3fv(m_Settings.GetAxesColor().data_block());
-    glBegin(GL_LINES);
-    glVertex2f(xAxes(0),xMin(1));
-    glVertex2f(xAxes(0),xMax(1));
-    glVertex2f(xMin(0), xAxes(1));
-    glVertex2f(xMax(0), xAxes(1));
-    glEnd();
-
-    }
-  
-  // Allow line smoothing
-  glEnable(GL_BLEND);
-  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-  glLineWidth(2.0);
-
-  // Finally, plot the function
-  glColor3fv(m_Settings.GetPlotColor().data_block());
-  glBegin(GL_LINE_STRIP);
-
-  // Plot all the points
-  for(PointVector::iterator it=m_Points.begin();it!=m_Points.end();++it)
-    {
-    glVertex2fv(it->data_block());
-    }
-
-  glEnd();
-
-  // Restore the model matrix
-  glPopMatrix();  
-
-  // Restore the attributes
-  glPopAttrib();
-}
-
-FunctionPlot2DSettings
-FunctionPlot2DSettings
-::GetDefaultSettings()
-{
-  FunctionPlot2DSettings settings;
-
-  settings.m_PlotRangeMin = Vector2f(-1.0f);
-  settings.m_PlotRangeMax = Vector2f(1.0f);
-  settings.m_AxesPosition = Vector2f(0.0f);
-  settings.m_MajorTickSpacing = Vector2f(0.5f);
-  settings.m_MinorTickSpacing = Vector2f(0.1f);
-
-  settings.m_ShowAxes = true;
-  settings.m_ShowFrame = true;
-  settings.m_ShowMajorTicks = true;
-  settings.m_ShowMinorTicks = true;
-  
-  settings.m_AxesColor = Vector3f(0.0f);
-  settings.m_FrameColor = Vector3f(0.0f);
-  settings.m_PlotColor = Vector3f(1.0f,0.0f,0.0f);
-  settings.m_BackgroundColor = Vector3f(1.0f);
-
-  return settings;
-}
-
-
diff --git a/UserInterface/BasicComponents/FunctionPlot2D.h b/UserInterface/BasicComponents/FunctionPlot2D.h
deleted file mode 100644
index 3cff195..0000000
--- a/UserInterface/BasicComponents/FunctionPlot2D.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: FunctionPlot2D.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:16 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __FunctionPlot2D_h_
-#define __FunctionPlot2D_h_
-
-#include "SNAPCommonUI.h"
-#include <vector>
-
-/**
- * Settings for plotting 2D functions.  Based on Mathematica options
- * to the Plot command (a small subset, of course).
- */
-class FunctionPlot2DSettings
-{
-public:
-    virtual ~FunctionPlot2DSettings() {} ;
-
-  irisGetMacro(PlotRangeMin,Vector2f);
-  irisSetMacro(PlotRangeMin,Vector2f);
-
-  irisGetMacro(PlotRangeMax,Vector2f);
-  irisSetMacro(PlotRangeMax,Vector2f);
-
-  irisGetMacro(AxesPosition,Vector2f);
-  irisSetMacro(AxesPosition,Vector2f);
-
-  irisGetMacro(MajorTickSpacing,Vector2f);
-  irisSetMacro(MajorTickSpacing,Vector2f);
-
-  irisGetMacro(MinorTickSpacing,Vector2f);
-  irisSetMacro(MinorTickSpacing,Vector2f);
-
-  irisGetMacro(ShowAxes,bool);
-  irisSetMacro(ShowAxes,bool);
-
-  irisGetMacro(ShowFrame,bool);
-  irisSetMacro(ShowFrame,bool);
-
-  irisGetMacro(ShowMajorTicks,bool);
-  irisSetMacro(ShowMajorTicks,bool);
-
-  irisGetMacro(ShowMinorTicks,bool);
-  irisSetMacro(ShowMinorTicks,bool);
-
-  irisGetMacro(AxesColor,Vector3f);
-  irisSetMacro(AxesColor,Vector3f);
-
-  irisGetMacro(FrameColor,Vector3f);
-  irisSetMacro(FrameColor,Vector3f);
-  
-  irisGetMacro(PlotColor,Vector3f);
-  irisSetMacro(PlotColor,Vector3f);
-
-  irisGetMacro(BackgroundColor,Vector3f);
-  irisSetMacro(BackgroundColor,Vector3f);
-
-  static FunctionPlot2DSettings GetDefaultSettings();
-
-private:
-  Vector2f m_PlotRangeMin;
-  Vector2f m_PlotRangeMax;
-  Vector2f m_AxesPosition;
-  Vector2f m_MajorTickSpacing;
-  Vector2f m_MinorTickSpacing;
-
-  bool m_ShowAxes;
-  bool m_ShowFrame;
-  bool m_ShowMajorTicks;
-  bool m_ShowMinorTicks;
-  
-  Vector3f m_AxesColor;
-  Vector3f m_FrameColor;
-  Vector3f m_PlotColor;
-  Vector3f m_BackgroundColor;
-};
-
-/**
- * \class FunctionPlot2D
- * \brief A UI component for plotting 2D graphs using GL functions.
- */
-class FunctionPlot2D
-{
-public:
-  /** Get a reference to the settings in this object */
-  FunctionPlot2DSettings &GetSettings() 
-  {
-    return m_Settings;
-  }
-
-  /** Set the data to be plotted */
-  void SetDataPoints(float *xPoints,float *yPoints,unsigned int nPoints);
-
-  /** 
-   * Draw the function in the standard OpenGL context.  The method will place
-   * the plot inside the region ((0,0),(1,1)).  
-   */
-  void Draw();
-
-  /** Constructor, takes on default plot settings */
-  FunctionPlot2D();
-  
-private:
-  typedef std::vector<Vector2f> PointVector;
-
-  FunctionPlot2DSettings m_Settings;  
-  PointVector m_Points;
-};
-
-#endif
diff --git a/UserInterface/BasicComponents/FunctionPlot2DBox.cxx b/UserInterface/BasicComponents/FunctionPlot2DBox.cxx
deleted file mode 100644
index b6d01be..0000000
--- a/UserInterface/BasicComponents/FunctionPlot2DBox.cxx
+++ /dev/null
@@ -1,81 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: FunctionPlot2DBox.cxx,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:16 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "FunctionPlot2DBox.h"
-#include "SNAPOpenGL.h"
-
-FunctionPlot2DBox
-::FunctionPlot2DBox(int x,int y,int w,int h,const char *label)
-  : FLTKCanvas(x,y,w,h,label)
-{
-}
-
-
-void 
-FunctionPlot2DBox
-::draw()
-{
-  // The standard 'valid' business
-  if(!valid())
-    {
-    // Set up the basic projection with a small margin
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    gluOrtho2D(-0.05,1.05,-0.05,1.05);
-    glViewport(0,0,w(),h());
-
-    // Establish the model view matrix
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();    
-    }
-    
-  // Clear the viewport
-  glClearColor(0.906f,0.906f,0.906f,1.0f);
-  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
-
-  // Push the related attributes
-  glPushAttrib(GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT | GL_LINE_BIT);
-
-  // Disable lighting
-  glDisable(GL_LIGHTING);
-
-  // Call the plotting routine
-  m_Plotter.Draw();
-  
-  // Pop the attributes
-  glPopAttrib();
-
-  // Done
-  glFlush();
-}
diff --git a/UserInterface/BasicComponents/FunctionPlot2DBox.h b/UserInterface/BasicComponents/FunctionPlot2DBox.h
deleted file mode 100644
index 34ed3ae..0000000
--- a/UserInterface/BasicComponents/FunctionPlot2DBox.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: FunctionPlot2DBox.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:16 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __FunctionPlot2DBox_h_
-#define __FunctionPlot2DBox_h_
-
-#include "FunctionPlot2D.h"
-#include "FLTKCanvas.h"
-
-/**
- * \class FunctionPlot2DBox
- * \brief An FLTK Box used for drawing a plot using the above object
- */
-class FunctionPlot2DBox : public FLTKCanvas
-{
-public:
-  /** The standard FLTK window constructor */
-  FunctionPlot2DBox(int x,int y,int w,int h,const char *label=NULL);
-  
-  /** Access the plotting object associated with this window */
-  FunctionPlot2D &GetPlotter()
-  {
-    return m_Plotter;
-  }
-
-  /** The draw method */
-  void draw();
-
-private:
-  FunctionPlot2D m_Plotter;
-};
-
-#endif
diff --git a/UserInterface/BasicComponents/IntensityCurveBox.cxx b/UserInterface/BasicComponents/IntensityCurveBox.cxx
deleted file mode 100644
index 8d423df..0000000
--- a/UserInterface/BasicComponents/IntensityCurveBox.cxx
+++ /dev/null
@@ -1,633 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: IntensityCurveBox.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/06/03 19:25:32 $
-  Version:   $Revision: 1.8 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "IntensityCurveBox.h"
-#include "LayerInspectorUILogic.h"
-#include "GreyImageWrapper.h"
-#include "itkImageRegionConstIterator.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <iostream>
-#include <algorithm>
-
-#include <FL/Fl.H>
-#include "SNAPOpenGL.h"
-#include <FL/fl_draw.H>
-
-using namespace std;
-unsigned int IntensityCurveBox::CURVE_RESOLUTION = 64;
-
-IntensityCurveBox
-::IntensityCurveBox(int x, int y, int w, int h, const char *label)
-: FLTKCanvas(x,y,w,h,label)
-{
-  // Start with the blank curve
-  m_Curve = NULL;
-  m_Parent = NULL;
-
-  // Initialize the histogram parameters
-  m_HistogramBinSize = 1;
-  m_HistogramMaxLevel = 1.0;
-  m_HistogramLog = false;
-
-  // Set up the interactor
-  m_Interactor = new IntensityCurveInteraction(this);
-  PushInteractionMode(m_Interactor);
-}
-
-IntensityCurveBox
-::~IntensityCurveBox()
-{
-  delete m_Interactor;
-}
-
-void 
-IntensityCurveBox
-::draw() 
-{       
-  // The curve should have been initialized
-  assert(m_Curve);
-
-  if (!valid()) 
-    {
-    // Set up the basic projection
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    gluOrtho2D(-0.025,1.025,-0.05,1.05);
-    glViewport(0,0,w(),h());
-
-    // Establish the model view matrix
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-
-    GLdouble modelMatrix[16], projMatrix[16];
-    GLint viewport[4];
-    glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
-    glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
-    glGetIntegerv(GL_VIEWPORT,viewport);
-    }
-
-  // Clear the viewport
-  glClearColor(.95,.95,.95,1.0);
-  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
-
-  // Push the related attributes
-  glPushAttrib(GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT | GL_LINE_BIT);
-
-  // Disable lighting
-  glDisable(GL_LIGHTING);
-
-  // Draw the plot area. The intensities outside of the window and level
-  // are going to be drawn in darker shade of gray
-  float t0, t1, xDummy;
-  m_Curve->GetControlPoint(0, t0, xDummy);
-  m_Curve->GetControlPoint(m_Curve->GetControlPointCount() - 1, t1, xDummy);
-  
-  // Scale the display so that leftmost point to plot maps to 0, rightmost to 1
-  float z0 = std::min(t0, 0.0f);
-  float z1 = std::max(t1, 1.0f);
-  glPushMatrix();
-  glTranslated(-z0 / (z1-z0), 0, 0);
-  glScaled(1.0 / (z1-z0), 1, 1);
-
-  // Draw the quads
-  glBegin(GL_QUADS);
-
-  // Outer quad
-  glColor3d(0.9, 0.9, 0.9);
-  glVertex2d(z0,0);
-  glVertex2d(z0,1);
-  glVertex2d(z1,1);
-  glVertex2d(z1,0);
-
-  float q0 = std::max(t0, 0.0f);
-  float q1 = std::min(t1, 1.0f);
-  if(q1 > q0)
-    {
-    // Inner quad
-    glColor3d(1.0, 1.0, 1.0);
-    glVertex2d(q0, 0.0); 
-    glVertex2d(q0, 1.0); 
-    glVertex2d(q1, 1.0); 
-    glVertex2d(q1, 0.0);
-    }
-
-  glEnd();
-
-  // Draw a histogram if it exists
-  if(m_Histogram.size())
-    {
-    // Compute the heights of all the histogram bars
-    float xWidth = 1.0f / m_Histogram.size();
-    unsigned int xPixelsPerBin = w() / m_Histogram.size();
-    vector<double> xHeight(m_Histogram.size(), 0.0);
-
-    // Start by computing the maximum (cutoff) height
-    float xHeightMax = m_HistogramMax * m_HistogramMaxLevel;
-    if(m_HistogramLog)
-      xHeightMax = log(xHeightMax) / log(10.0);
-
-    // Continue by computing each bin's height
-    unsigned int i;
-    for(i=0;i < m_Histogram.size();i++)
-      {
-      // Process the histogram height based on options
-      xHeight[i] = m_Histogram[i];
-      if(m_HistogramLog)
-        xHeight[i] = (xHeight[i] > 0) ? log(xHeight[i]) / log(10.0) : 0;
-      if(xHeight[i] > xHeightMax)
-        xHeight[i] = xHeightMax / 0.9f;
-      }
-
-    // Draw the horizontal lines at various powers of 10 if in log mode
-    if(m_HistogramLog)
-      {
-      glColor3d(0.75, 0.75, 0.75);
-      glBegin(GL_LINES);
-      for(double d = 1.0; d < xHeightMax; d+=1.0)
-        { glVertex2f(0,d); glVertex2f(1,d); }
-      glEnd();
-      }
-      
-    // Paint the filled-in histogram bars. We fill in with black color if the 
-    // histogram width is less than 4 pixels
-    if(xPixelsPerBin < 4) 
-      glColor3f(0.0f, 0.0f, 0.0f); 
-    else 
-      glColor3f(0.8f, 0.8f, 1.0f);
-
-    // Paint the bars as quads
-    glBegin(GL_QUADS);
-    for(i=0;i < m_Histogram.size();i++)
-      {
-      // Compute the physical height of the bin
-      float xBin = xWidth * i;
-      float hBin = xHeight[i] * 0.9f / xHeightMax;
-
-      // Paint the bar
-      glVertex2f(xBin,0);
-      glVertex2f(xBin,hBin);
-      glVertex2f(xBin+xWidth,hBin);
-      glVertex2f(xBin+xWidth,0);
-      }
-    glEnd();
-
-    // Draw lines around the quads, but only if the bins are thick
-    if(xPixelsPerBin >= 4)
-      {
-      // Draw the vertical lines between the histogram bars
-      glBegin(GL_LINE_STRIP);
-      glColor3d(0.0, 0.0, 0.0);
-      for(i = 0; i < m_Histogram.size(); i++)
-        {
-        // Compute the physical height of the bin
-        float xBin = xWidth * i;
-        float hBin = xHeight[i] * 0.9f / xHeightMax;
-
-        // Draw around the bar, starting at the lower left corner
-        glVertex2f(xBin, 0.0f);
-        glVertex2f(xBin, hBin);
-        glVertex2f(xBin + xWidth, hBin);
-        glVertex2f(xBin + xWidth, 0.0f);
-        }
-      glEnd();
-      }
-    }
-
-  // Draw the box around the plot area
-  glColor3d(0,0,0);
-  glBegin(GL_LINE_LOOP);
-  glVertex2d(z0,0);
-  glVertex2d(z0,1);
-  glVertex2d(z1,1);
-  glVertex2d(z1,0);
-  glEnd();
-
-  // Set up the smooth line drawing style
-  glEnable(GL_LINE_SMOOTH);
-  glEnable(GL_BLEND);
-  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-  glLineWidth(2.0);
-
-  // Draw the curve using linear segments
-  glColor3d(1.0,0.0,0.0);
-  glBegin(GL_LINE_STRIP);
-
-  float t = z0;
-  float tStep = (z1-z0) / (CURVE_RESOLUTION);
-  for (unsigned int i=0;i<=CURVE_RESOLUTION;i++) 
-    {
-    glVertex2f(t,m_Curve->Evaluate(t));
-    t+=tStep;
-    }
-
-  glEnd();
-
-  // Draw the handles
-  glLineWidth(1.0);
-  for (unsigned int c=0;c<m_Curve->GetControlPointCount();c++) 
-    {
-    // Get the next control point
-    float t,x;
-    m_Curve->GetControlPoint(c,t,x);
-
-    // Draw a quad around the control point
-    if(c == (unsigned int)m_Interactor->GetMovingControlPoint())
-      {
-      glColor3d(1,1,0);
-      gl_draw_circle_with_border(t, x, 5.0, z1-z0, false);
-      }
-    else
-      {
-      glColor3d(1,0,0);
-      gl_draw_circle_with_border(t, x, 4.0, z1-z0, false);
-      }
-    }
-
-  glPopMatrix();
-
-  // Pop the attributes
-  glPopAttrib();
-
-  // Done
-  glFlush();
-}
-
-void
-IntensityCurveBox
-::gl_draw_circle_with_border(double x, double y, double r, double bw, bool select)
-{
-  static std::vector<double> cx, cy;
-  if(cx.size() == 0)
-    {
-    for(double a = 0; a < 2 * vnl_math::pi - 1.0e-6; a += vnl_math::pi / 20)
-      {
-      cx.push_back(cos(a));
-      cy.push_back(sin(a));
-      }
-    }
-
-  glPushMatrix();
-  glTranslated(x, y, 0.0);
-  glScaled(1.2 * bw / this->w(), 1.2 / this->h(), 1.0);
-
-  glBegin(GL_TRIANGLE_FAN);
-  glVertex2d(0, 0);
-  for(size_t i = 0; i < cx.size(); i++)
-    glVertex2d(r * cx[i], r * cy[i]);
-  glVertex2d(r, 0);
-  glEnd();
-
-  if(select)
-    glColor3ub(0xff,0x00,0xff);
-  else
-    glColor3ub(0x00,0x00,0x00);
-  
-  glBegin(GL_LINE_LOOP);
-  for(size_t i = 0; i < cx.size(); i++)
-    glVertex2d(r * cx[i], r * cy[i]);
-  glEnd();
-
-  glPopMatrix();
-}
-
-int 
-IntensityCurveBox
-::GetControlPointInVicinity(float x, float y, int pixelRadius) 
-{
-  float rx = pixelRadius * 1.0f / w();
-  float ry = pixelRadius * 1.0f / h();
-  float fx = 1.0f / (rx * rx);
-  float fy = 1.0f / (ry * ry);
-
-  float minDistance = 1.0f;
-  int nearestPoint = -1;
-
-  for (unsigned int c=0;c<m_Curve->GetControlPointCount();c++) {
-
-    // Get the next control point
-    float cx,cy;
-    m_Curve->GetControlPoint(c,cx,cy);
-
-    // Check the distance to the control point
-    float d = (cx - x) * (cx - x) * fx + (cy - y) * (cy - y) * fy;
-    if (minDistance >= d) {
-      minDistance = d;
-      nearestPoint = c;
-    }
-  }
-
-  // Negative: return -1
-  return nearestPoint;
-}
-
-void 
-IntensityCurveBox
-::ComputeHistogram(GreyImageWrapper *source, unsigned int iMinPixelsPerBin)
-{
-  // Need a wrapper
-  assert(source);
-  assert(this->w() > 0);
-
-  // Get 'absolute' image intensity range, i.e., the largest and smallest
-  // intensity in the whole image
-  GreyType iAbsMin = source->GetImageMin();
-  GreyType iAbsMax = source->GetImageMax();
-  unsigned int nFrequencies = (iAbsMax - iAbsMin) + 1;
-
-  // Compute the freqencies of the intensities
-  unsigned int *frequency = new unsigned int[nFrequencies];
-  memset(frequency,0,sizeof(unsigned int) * nFrequencies);
-  GreyImageWrapper::ConstIterator it = source->GetImageConstIterator();
-  for(it.GoToBegin();!it.IsAtEnd();++it)
-    {
-    frequency[it.Value()-iAbsMin]++;
-    }
-
-  // Determine the bin size: no bin should be less than a single pixel wide
-  if(nFrequencies * iMinPixelsPerBin > m_HistogramBinSize * this->w()) 
-    m_HistogramBinSize = 
-    (unsigned int) ceil(nFrequencies * iMinPixelsPerBin * 1.0 / this->w());
-  unsigned int nBins = (unsigned int) ceil(nFrequencies * 1.0 / m_HistogramBinSize);
-
-  // Allocate an array of bins
-  m_Histogram.resize(nBins);
-  fill(m_Histogram.begin(), m_Histogram.end(), 0);
-
-  // Reset the max-frequency
-  m_HistogramMax = 0;
-
-  // Put the frequencies into the bins
-  for(unsigned int i=0;i<nFrequencies;i++)
-    {
-    unsigned int iBin = i / m_HistogramBinSize;
-    m_Histogram[iBin] += frequency[i];
-
-    // Compute the maximum frequency
-    if(m_HistogramMax < m_Histogram[iBin])
-      m_HistogramMax  = m_Histogram[iBin]; 
-    }
-
-  // Clear the frequencies
-  delete frequency;
-}
-
-IntensityCurveInteraction
-::IntensityCurveInteraction(IntensityCurveBox *parent) 
-: InteractionMode(parent)
-{
-  m_Parent = parent;
-  m_MovingControlPoint = 0;
-}
-
-Vector3f
-IntensityCurveBox
-::GetEventCurveCoordinates(const FLTKEvent &e)
-{
-  // Draw the plot area. The intensities outside of the window and level
-  // are going to be drawn in darker shade of gray
-  float t0, t1, xDummy;
-  m_Curve->GetControlPoint(0, t0, xDummy);
-  m_Curve->GetControlPoint(m_Curve->GetControlPointCount() - 1, t1, xDummy);
-  float z0 = std::min(t0, 0.0f);
-  float z1 = std::max(t1, 1.0f);
-  
-  // Scale the display so that leftmost point to plot maps to 0, rightmost to 1
-  return Vector3f(e.XSpace[0] * (z1 - z0) + z0, e.XSpace[1], e.XSpace[2]);
-}
-
-int 
-IntensityCurveInteraction
-::OnMousePress(const FLTKEvent &event)
-{
-  // Check the control point affected by the event
-  Vector3f xCurve = m_Parent->GetEventCurveCoordinates(event);
-  m_MovingControlPoint = 
-    m_Parent->GetControlPointInVicinity(xCurve[0],xCurve[1],5);
-
-  SetCursor(m_MovingControlPoint);
-
-  // Clear the dragged flag
-  m_FlagDraggedControlPoint = false;
-
-  return 1;
-}
-
-int 
-IntensityCurveInteraction
-::OnMouseRelease(const FLTKEvent &event,
-  const FLTKEvent &irisNotUsed(dragEvent))
-{
-  Vector3f xCurve = m_Parent->GetEventCurveCoordinates(event);
-  if (m_MovingControlPoint >= 0) 
-    {
-    if(m_FlagDraggedControlPoint)
-      {
-      // Update the control point
-      if (UpdateControl(xCurve))
-        {
-        // Repaint parent
-        m_Parent->redraw();
-
-        // Fire the update event (should this be done on drag?)
-        m_Parent->GetParent()->OnCurveChange();
-        m_Parent->GetParent()->OnControlPointUpdate();
-        }
-      }
-    else
-      {
-      m_Parent->GetParent()->OnControlPointUpdate();
-      m_Parent->redraw();
-      }
-
-    // Set the cursor back to normal
-    SetCursor(-1);
-  }
-
-  return 1;
-}
-
-int 
-IntensityCurveInteraction
-::OnMouseDrag(const FLTKEvent &event,
-  const FLTKEvent &irisNotUsed(dragEvent))
-{
-  Vector3f xCurve = m_Parent->GetEventCurveCoordinates(event);
-  if (m_MovingControlPoint >= 0) 
-    {
-    // Update the moving control point
-    if (UpdateControl(xCurve)) 
-      {
-      // Repaint parent
-      m_Parent->redraw();
-
-      // Fire the update event (should this be done on drag?)
-      m_Parent->GetParent()->OnCurveChange();
-      m_Parent->GetParent()->OnControlPointUpdate();
-      }
-
-    // Set the dragged flag
-    m_FlagDraggedControlPoint = true;
-    }
-
-  return 1;
-}
-
-int 
-IntensityCurveInteraction
-::OnMouseEnter(const FLTKEvent &irisNotUsed(event))
-{
-  return 1;
-}
-
-int 
-IntensityCurveInteraction
-::OnMouseLeave(const FLTKEvent &irisNotUsed(event))
-{
-  return 1;
-}
-
-int 
-IntensityCurveInteraction
-::OnMouseMotion(const FLTKEvent &event)
-{
-  Vector3f xCurve = m_Parent->GetEventCurveCoordinates(event);
-  int cp = 
-    m_Parent->GetControlPointInVicinity(xCurve[0],xCurve[1],5);
-
-  SetCursor(cp);
-
-  return 1;
-}
-
-void
-IntensityCurveInteraction
-::SetCursor(int cp)
-{
-  if (cp < 0)
-    {
-    fl_cursor(FL_CURSOR_DEFAULT);
-    }
-  else if (cp == 0 ||
-    cp == (int)(m_Parent->GetCurve()->GetControlPointCount()-1))
-    {
-    fl_cursor(FL_CURSOR_WE);
-    }
-  else
-    {
-    fl_cursor(FL_CURSOR_MOVE);
-    }
-}
-
-int
-IntensityCurveInteraction
-::GetMovingControlPoint() const
-{
-  return m_MovingControlPoint;
-}
-
-void
-IntensityCurveInteraction
-::SetMovingControlPoint(int cp)
-{
-  m_MovingControlPoint = cp;
-}
-
-
-bool
-IntensityCurveBox
-::UpdateControlPoint(size_t i, float t, float x)
-{
-  // Must be in range
-  assert(i < m_Curve->GetControlPointCount());
-  
-  // Get the current values
-  float told, xold;
-  m_Curve->GetControlPoint(i, told, xold);
-
-  // The control value should be in range
-  // if(t < 0.0 || t > 1.0)
-  //  return false;
-
-  // First and last control points are treated specially because they
-  // provide windowing style behavior
-  int last = m_Curve->GetControlPointCount()-1;
-  if (i == 0 || i == (size_t) last) 
-    {
-    // Get the current domain
-    float tMin,tMax,x;        
-    m_Curve->GetControlPoint(0,   tMin, x);
-    m_Curve->GetControlPoint(last,tMax, x);
-
-    // Check if the new domain is valid
-    float epsilon = 0.02;
-    if (i == 0 && t < tMax - epsilon) 
-      tMin = t;
-    else if (i == (size_t) last && t > tMin + epsilon) 
-      tMax = t;
-    else 
-      // One of the conditions failed; the window has size <= 0
-      return false;
-
-    // Change the domain of the curve
-    m_Curve->ScaleControlPointsToWindow(tMin, tMax);
-    } 
-  else
-    {
-    // Check whether the X coordinate is in range
-    if (x < 0.0 || x > 1.0)
-      return false;
-
-    // Update the control point
-    m_Curve->UpdateControlPoint(i, t, x);
-
-    // Check the curve for monotonicity
-    if(!m_Curve->IsMonotonic()) 
-      {
-      m_Curve->UpdateControlPoint(i, told, xold);
-      return false;
-      }
-    }
-  return true;
-}
-
-bool
-IntensityCurveInteraction
-::UpdateControl(const Vector3f &p)
-{
-  return m_Parent->UpdateControlPoint(
-    m_MovingControlPoint, p[0], p[1]);
-}
-
diff --git a/UserInterface/BasicComponents/IntensityCurveBox.h b/UserInterface/BasicComponents/IntensityCurveBox.h
deleted file mode 100644
index cb653fa..0000000
--- a/UserInterface/BasicComponents/IntensityCurveBox.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: IntensityCurveBox.h,v $
-  Language:  C++
-  Date:      $Date: 2010/06/03 19:25:32 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __IntensityCurveBox_h_
-#define __IntensityCurveBox_h_
-
-#include <FL/Fl_Gl_Window.H>
-
-#include <SNAPCommonUI.h>
-#include <IntensityCurveInterface.h>
-#include <FLTKCanvas.h>
-#include <InteractionMode.h>
-
-class LayerInspectorUILogic;
-class GreyImageWrapper;
-class IntensityCurveInteraction;
-
-/**
- * \class IntensityCurveBox
- * \brief An FLTK Box (Gl_Window) used to paint intensity mapping curves.
- */
-class IntensityCurveBox : public FLTKCanvas {
-public:
-  IntensityCurveBox(int x,int y,int w,int h,const char *label);
-  virtual ~IntensityCurveBox();
-
-  // Get the intensity curve interactor
-  irisGetMacro(Interactor, IntensityCurveInteraction *);
-
-  /**
-   * Handle displaying the curve
-   */
-  void draw();
-
-  /** Compute the histogram given an image wrapper */
-  void ComputeHistogram(GreyImageWrapper *source,
-    unsigned int iMinPixelsPerBin = 1);
-
-  // Get/set the intensity curve
-  irisGetMacro(Curve,IntensityCurveInterface *);
-  irisSetMacro(Curve,IntensityCurveInterface *);
-
-  // Get/set the parent object
-  irisGetMacro(Parent,LayerInspectorUILogic *);
-  irisSetMacro(Parent,LayerInspectorUILogic *);
-
-  // Get the histogram itself
-  const std::vector<unsigned int> &GetHistogram() const
-    { return m_Histogram; }
-
-  // Get/set the histogram properties
-  irisGetMacro(HistogramBinSize, unsigned int);
-  irisSetMacro(HistogramBinSize, unsigned int);
-  irisGetMacro(HistogramMaxLevel, float);
-  irisSetMacro(HistogramMaxLevel, float);
-  irisIsMacro(HistogramLog);
-  irisSetMacro(HistogramLog, bool);
-
-  // External command for moving the control points. The method will
-  // not allow updates that violate constraints. The return value is 
-  // true if the constraints were not violated. Return values tnew and
-  // xnew give the values of the control point after update. 
-  bool UpdateControlPoint(size_t i, float t, float x);
-
-  /**
-   * The resolution of the curve displayed on the screen
-   * TODO: Control over curve resolution
-   */
-  static unsigned int CURVE_RESOLUTION;
-
-private:
-
-  /**
-   * Check if a control point is close to another point (i.e. mouse position)
-   */
-  int GetControlPointInVicinity(float x, float y, int pixelRadius);
-
-  /**
-   * Map event coordinates to image space coordinates 
-   */
-  Vector3f GetEventCurveCoordinates(const FLTKEvent &e);
-
-  /** The intensity mapping curve */
-  IntensityCurveInterface *m_Curve;
-
-  /** Parent object */
-  LayerInspectorUILogic *m_Parent;
-
-  /** Histogram of the image */
-  std::vector<unsigned int> m_Histogram;   
-
-  /** Max frequency in the histogram */
-  unsigned int m_HistogramMax;
-
-  /** Max level in the histograms: bins above this level are truncated */
-  float m_HistogramMaxLevel;
-
-  /** Size of the bin, in intensities */
-  unsigned int m_HistogramBinSize;
-
-  /** Flag, whether log of the frequencies is used */
-  bool m_HistogramLog;
-
-  // Draw circles
-  void gl_draw_circle_with_border(double x, double y, double r, double bw, bool select);
-
-  IntensityCurveInteraction* m_Interactor;
-
-  // Allow access to private data
-  friend class IntensityCurveInteraction;
-
-  
-
-};
-
-/**
- * Interaction handler for control point manipulation
- */
-class IntensityCurveInteraction : public InteractionMode {
-public:
-  IntensityCurveInteraction(IntensityCurveBox *parent);
-
-  int OnMousePress(const FLTKEvent &event);
-  int OnMouseRelease(const FLTKEvent &event, const FLTKEvent &pressEvent);
-  int OnMouseDrag(const FLTKEvent &event, const FLTKEvent &pressEvent);
-  int OnMouseEnter(const FLTKEvent &event);
-  int OnMouseLeave(const FLTKEvent &event);
-  int OnMouseMotion(const FLTKEvent &event);
-  int GetMovingControlPoint() const;
-  void SetMovingControlPoint(int cp);
-
-private:
-  // Pointer to the parent canvas
-  IntensityCurveBox *m_Parent;
-
-  // Set cursor depending on selected point
-  void SetCursor(int iControlPoint);
-
-  // Update a control point to reflect mouse motion to p
-  bool UpdateControl(const Vector3f &p);
-
-  // Control point being currently edited
-  int m_MovingControlPoint;
-
-  bool m_FlagDraggedControlPoint;
-
-};
-
-#endif // __IntensityCurveBox_h_
-
diff --git a/UserInterface/BasicComponents/InteractionMode.h b/UserInterface/BasicComponents/InteractionMode.h
deleted file mode 100644
index 74ac269..0000000
--- a/UserInterface/BasicComponents/InteractionMode.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: InteractionMode.h,v $
-  Language:  C++
-  Date:      $Date: 2010/04/16 04:02:35 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __InteractionMode_h_
-#define __InteractionMode_h_
-
-#include <FL/Fl.H>
-
-#include "SNAPCommonUI.h"
-#include "FLTKEvent.h"
-
-// Forward reference to the canvas object
-class FLTKCanvas;
-
-/**
- * \class InteractionMode
- * \brief This class defines a UI interaction mode.  
- *
- * It is used to define the behavior of a tool on a canvas (FLTKCanvas).   
- * This class removes the need to write huge handle() methods
- */
-class InteractionMode
-{
-public:
-
-  /** Constructor takes the pointer to the target canvas object */
-  InteractionMode(FLTKCanvas *canvas)
-    { this->m_Canvas = canvas; }
-
-  /** Destructor */
-  virtual ~InteractionMode(void) {} 
-
-  /**
-   * Called when mouse button is pressed.
-   */
-  virtual int OnMousePress(const FLTKEvent &irisNotUsed(event)) 
-    { return 0; }
-
-  /**
-   * Called when mouse is pressed.  The event generated when the mouse
-   * was pressed is also passed in for reference.
-   */
-  virtual int OnMouseRelease(const FLTKEvent &irisNotUsed(event),
-                             const FLTKEvent &irisNotUsed(pressEvent)) 
-    { return 0; }
-
-  /**
-   * Called when the mouse is dragged.  The event generated when the mouse
-   * was pressed is also passed in for reference.
-   */
-  virtual int OnMouseDrag(const FLTKEvent &irisNotUsed(event),
-                          const FLTKEvent &irisNotUsed(pressEvent)) 
-    { return 0; }
-
-  /**
-   * Called when mouse enters the canvas.  Return 1 to track motion events.
-   */
-  virtual int OnMouseEnter(const FLTKEvent &irisNotUsed(event)) 
-    { return 0; }
-
-  /**
-   * Called when mouse exits the canvas.  
-   */
-  virtual int OnMouseLeave(const FLTKEvent &irisNotUsed(event)) 
-    { return 0; }
-
-  /**
-   * Called when mouse moves in the canvas
-   */
-  virtual int OnMouseMotion(const FLTKEvent &irisNotUsed(event)) 
-    { return 0; }
-
-  /**
-   * Called when mouse moves in the canvas
-   */
-  virtual int OnMouseWheel(const FLTKEvent &irisNotUsed(event)) 
-    { return 0; }
-
-  /**
-   * Called when a key on the keyboard is pressed.
-   */
-  virtual int OnKeyDown(const FLTKEvent &irisNotUsed(event)) 
-    { return 0; }
-
-  /**
-   * Called when a key on the keyboard is released.
-   */
-  virtual int OnKeyUp(const FLTKEvent &irisNotUsed(event)) 
-    { return 0; }
-
-  /**
-   * Called for FLTK short-cut events
-   */
-  virtual int OnShortcut(const FLTKEvent &irisNotUsed(event)) 
-    { return 0; }
-
-  /**
-   * Called for FLTK Drag and Drop paste events
-   */
-  virtual int OnDragAndDrop(const FLTKEvent &irisNotUsed(event))
-    { return 0; }
-
-  /**
-   * Called for all other FLTK events
-   */
-  virtual int OnOtherEvent(const FLTKEvent &irisNotUsed(event)) 
-    { return 0; }
-
-  /**
-   * Can be called when the canvas is redrawing itself. 
-   * This is not really an event but a convenience method.
-   */
-  virtual void OnDraw() 
-    { return; }
-
-  /** Get the pointer to the client canvas */
-  FLTKCanvas *GetCanvas() const
-    { return m_Canvas; }
-
-protected:
-
-  // The target canvas
-  FLTKCanvas *m_Canvas;
-};
-
-#endif // __InteractionMode_h_
diff --git a/UserInterface/BasicComponents/InteractionModeClient.cxx b/UserInterface/BasicComponents/InteractionModeClient.cxx
deleted file mode 100644
index dee6d57..0000000
--- a/UserInterface/BasicComponents/InteractionModeClient.cxx
+++ /dev/null
@@ -1,104 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: InteractionModeClient.cxx,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:16 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "InteractionModeClient.h"
-#include <algorithm>
-#include <list>
-
-void                            
-InteractionModeClient
-::PushInteractionMode(InteractionMode *mode)
-{
-  m_Interactors.push_front(mode);
-}
-
-InteractionMode *
-InteractionModeClient
-::PopInteractionMode() 
-{
-  InteractionMode *lastMode = m_Interactors.front();
-  m_Interactors.pop_front();
-  return lastMode;
-}
-
-void 
-InteractionModeClient
-::ClearInteractionStack() 
-{
-  m_Interactors.clear();
-} 
-
-void InteractionModeClient
-::SetSingleInteractionMode(InteractionMode *mode)
-{
-  this->ClearInteractionStack();
-  this->PushInteractionMode(mode);
-}
-
-unsigned int 
-InteractionModeClient
-::GetInteractionModeCount()
-{
-  return m_Interactors.size();
-}
-
-InteractionMode *
-InteractionModeClient
-::GetTopInteractionMode()
-{
-  return m_Interactors.front();
-}
-
-bool
-InteractionModeClient
-::IsInteractionModeAdded(InteractionMode *target)
-{
-  return 
-    std::find(m_Interactors.begin(), m_Interactors.end(), target) !=
-      m_Interactors.end();
-}
-
-void 
-InteractionModeClient
-::FireInteractionDrawEvent()
-{
-  // Propagate the drawing event through the stack
-  typedef std::list<InteractionMode *>::iterator ModeIterator; 
-  for (ModeIterator it = m_Interactors.begin(); it!=m_Interactors.end();it++)
-    {
-    InteractionMode *mode = *it;
-    mode->OnDraw();
-    }
-}
-
diff --git a/UserInterface/BasicComponents/InteractionModeClient.h b/UserInterface/BasicComponents/InteractionModeClient.h
deleted file mode 100644
index 99cf98b..0000000
--- a/UserInterface/BasicComponents/InteractionModeClient.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*=========================================================================
-
-  Program:   Insight Segmentation & Registration Toolkit
-  Module:    $RCSfile: InteractionModeClient.h,v $
-  Language:  C++
-  Date:      $Date: 2006/12/02 04:22:21 $
-  Version:   $Revision: 1.1 $
-  Copyright (c) 2003 Insight Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-#ifndef __InteractionModeClient_h_
-#define __InteractionModeClient_h_
-
-#include "InteractionMode.h"
-#include <list>
-
-/**
- * \class InteractionModeClient
- * \brief An abstract class that can pass on Fltk events to interaction modes
- */
-class InteractionModeClient
-{
-public:
-  /**
-   * Push an interaction mode onto the stack of modes.  Mode becomes first to 
-   * receive events.  The events that it does not receive are passed on to the
-   * next mode on the stack.
-   */
-  void PushInteractionMode(InteractionMode *mode);
-
-  /**
-   * Pop the last interaction mode off the stack
-   */
-  InteractionMode *PopInteractionMode();
-
-  /**
-   * Get the top interaction mode on the stack
-   */
-  InteractionMode *GetTopInteractionMode();
-
-  /**
-   * See if the interaction mode is in the stack
-   */
-  bool IsInteractionModeAdded(InteractionMode *target);
-
-  /**
-   * Remove all interaction modes
-   */
-  void ClearInteractionStack();
-
-  /** 
-   * Set the interaction stack to consist of just one interaction mode. This is 
-   * equivalent to calling ClearInteractionStack() followed by PushInteractionMode()
-   */
-  void SetSingleInteractionMode(InteractionMode *mode);
-
-  /**
-   * Get the number of interaction modes on the stack
-   */
-  unsigned int GetInteractionModeCount();
-
-  // Virtual destructor
-  virtual ~InteractionModeClient() {}
-
-protected:
-  /**
-   * This method should be called to draw the interactors (call their OnDraw methods 
-   * in a sequence from bottom to top)
-   */
-  void FireInteractionDrawEvent();
-
-  // The stack of interaction modes
-  std::list<InteractionMode *> m_Interactors;
-};
-
-#endif // __InteractionModeClient_h_
-
diff --git a/UserInterface/BasicComponents/MetaDataTable.cxx b/UserInterface/BasicComponents/MetaDataTable.cxx
deleted file mode 100644
index 5557285..0000000
--- a/UserInterface/BasicComponents/MetaDataTable.cxx
+++ /dev/null
@@ -1,313 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: MetaDataTable.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/06/28 18:45:08 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "MetaDataTable.h"
-#include "FL/fl_draw.H"
-#include "itkImage.h"
-#include "itkMetaDataDictionary.h"
-#include "itkMetaDataObject.h"
-#include "itkGDCMImageIO.h"
-using namespace std;
-
-string
-get_rai_code(itk::SpatialOrientation::ValidCoordinateOrientationFlags code)
-  {
-  std::map<itk::SpatialOrientation::ValidCoordinateOrientationFlags, string> m_CodeToString;
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RIP] = "RIP";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LIP] = "LIP";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RSP] = "RSP";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LSP] = "LSP";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RIA] = "RIA";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LIA] = "LIA";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RSA] = "RSA";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LSA] = "LSA";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IRP] = "IRP";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ILP] = "ILP";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SRP] = "SRP";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SLP] = "SLP";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IRA] = "IRA";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ILA] = "ILA";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SRA] = "SRA";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SLA] = "SLA";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RPI] = "RPI";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LPI] = "LPI";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAI] = "RAI";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LAI] = "LAI";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RPS] = "RPS";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LPS] = "LPS";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAS] = "RAS";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LAS] = "LAS";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PRI] = "PRI";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PLI] = "PLI";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ARI] = "ARI";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ALI] = "ALI";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PRS] = "PRS";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PLS] = "PLS";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ARS] = "ARS";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ALS] = "ALS";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IPR] = "IPR";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SPR] = "SPR";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IAR] = "IAR";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SAR] = "SAR";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IPL] = "IPL";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SPL] = "SPL";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IAL] = "IAL";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SAL] = "SAL";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PIR] = "PIR";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PSR] = "PSR";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIR] = "AIR";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ASR] = "ASR";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PIL] = "PIL";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PSL] = "PSL";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIL] = "AIL";
-  m_CodeToString[itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ASL] = "ASL";
-  return m_CodeToString[code];
-  }
-
-template<class AnyType>
-bool
-try_get_metadata(itk::MetaDataDictionary &mdd, 
-                   string &key, string &output, AnyType deflt)
-  {
-  AnyType v = deflt;
-  if(itk::ExposeMetaData<AnyType>(mdd, key, v))
-    {
-    ostringstream oss;
-    oss << v << endl;
-    output = oss.str();
-    return true;
-    }
-  else return false;
-  }
-
-void
-MetaDataTable
-::SetInputImage(itk::ImageBase<3> *image)
-{
-  int w = 0, h = 0;
-
-  // Init preferred widths
-  m_PreferredKeyWidth = 0;
-  m_PreferredValueWidth = 0;
-  m_PreferredHeight = 0;
-
-  // Get the data
-  m_Header.clear();
-  m_Body.clear();
-
-  m_Header.push_back("Header Field");
-  m_Header.push_back("Value");
-
-  // Measure widths
-  fl_font(FL_HELVETICA_BOLD, 11);
-  fl_measure(m_Header[0].c_str(), m_PreferredKeyWidth, m_PreferredHeight);
-  fl_measure(m_Header[1].c_str(), m_PreferredValueWidth, m_PreferredHeight);
-  m_PreferredKeyWidth += 6;
-  m_PreferredValueWidth += 6;
-
-  fl_font(FL_HELVETICA, 11);
-
-  // Get the dictionary
-  itk::MetaDataDictionary &mdd = image->GetMetaDataDictionary();
-  itk::MetaDataDictionary::ConstIterator itMeta;
-  for(itMeta = mdd.Begin(); itMeta != mdd.End(); ++itMeta)
-    {
-    // Get the metadata as a generic object
-    string key = itMeta->first, v_string;
-    string value;
-
-    // Orientation flag object
-    itk::SpatialOrientation::ValidCoordinateOrientationFlags v_oflags = 
-      itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_INVALID;
-
-    // Is the value a string?
-    if(itk::ExposeMetaData<string>(mdd, key, value))
-      {
-      // For some weird reason, some of the strings returned by this method
-      // contain '\0' characters. We will replace them by spaces
-      ostringstream sout("");
-      for(unsigned int i=0;i<value.length();i++)
-        if(value[i] >= ' ') sout << value[i];
-      value = sout.str();
-
-      // Make sure the value has more than blanks
-      if(value.find_first_not_of(" ") == v_string.npos)
-        value="";
-      }
-    else if(itk::ExposeMetaData(mdd, key, v_oflags))
-      {
-      value = get_rai_code(v_oflags);
-      }
-    else 
-      {
-      bool rc = false;
-      if(!rc) rc |= try_get_metadata<double>(mdd, key, value, 0);
-      if(!rc) rc |= try_get_metadata<float>(mdd, key, value, 0);
-      if(!rc) rc |= try_get_metadata<int>(mdd, key, value, 0);
-      if(!rc) rc |= try_get_metadata<unsigned int>(mdd, key, value, 0);
-      if(!rc) rc |= try_get_metadata<long>(mdd, key, value, 0);
-      if(!rc) rc |= try_get_metadata<unsigned long>(mdd, key, value, 0);
-      if(!rc) rc |= try_get_metadata<short>(mdd, key, value, 0);
-      if(!rc) rc |= try_get_metadata<unsigned short>(mdd, key, value, 0);
-      if(!rc) rc |= try_get_metadata<char>(mdd, key, value, 0);
-      if(!rc) rc |= try_get_metadata<unsigned char>(mdd, key, value, 0);
-
-      if(!rc)
-        {
-        ostringstream oss;
-        oss << "object of type " 
-          << itMeta->second->GetMetaDataObjectTypeName();
-        value = oss.str();
-        }
-      }
-
-    // Try to remap the key to DICOM
-    string dcm_label;
-    if(itk::GDCMImageIO::GetLabelFromTag(key, dcm_label))
-      key = dcm_label;
-
-    // Store the values
-    vector<string> row;
-    row.push_back(key);
-    row.push_back(value);
-    m_Body.push_back(row);
-
-    // Measure text
-    w = 0, h = 0;
-    fl_measure(key.c_str(), w, h);
-    m_PreferredKeyWidth = std::max(w + 6, m_PreferredKeyWidth);
-    w = 0; h = 0;
-    fl_measure(value.c_str(), w, h);
-    m_PreferredValueWidth = std::max(w + 6, m_PreferredValueWidth);
-    m_PreferredHeight = std::max(h, m_PreferredHeight);
-
-    }
-
-  // Set the number of rows and columns
-  this->rows(std::max((int) m_Body.size(),10));
-  this->cols(m_Header.size());
-  this->col_header(1);
-  this->col_resize(4);
-  this->row_height_all(4+m_PreferredHeight);
-}
-
-void 
-MetaDataTable
-::SetColumnWidth(int total_width)
-{
-  // Case 1: there is no data
-  if(m_PreferredKeyWidth == 0)
-    {
-    col_width(0, total_width/2);
-    col_width(1, total_width - col_width(0));
-    }
-  else
-    {
-    int wk = std::min(total_width/2, m_PreferredKeyWidth);
-    col_width(0, wk);
-    int wv = std::max(total_width - wk, m_PreferredValueWidth);
-    col_width(1, wv);
-    row_height_all(m_PreferredHeight + 4);
-    }
-}
-
-
-void
-MetaDataTable
-::draw_cell(TableContext context,  		
-    int R, int C, int X, int Y, int W, int H)
-{
-  string text;
-
-  // If data is not initialized, return
-  if(m_Header.size() == 0)
-    return;
-
-  // Actual drawing
-  switch(context)
-    {
-  case CONTEXT_STARTPAGE:
-    fl_font(FL_HELVETICA, 11);
-    return;
-
-  /*
-  case CONTEXT_ROW_HEADER:
-    text = m_Body[R][0];
-    fl_push_clip(X, Y, W, H);
-    fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, FL_LIGHT1);
-    fl_pop_clip();
-
-    fl_push_clip(X+3, Y, W-6, H);
-    fl_color(FL_BLACK);
-    fl_draw(text.c_str(), X+3, Y, W-6, H, FL_ALIGN_LEFT);
-    fl_pop_clip();
-    break;
-  */
-
-  case CONTEXT_COL_HEADER:
-    text = m_Header[C];
-
-    fl_push_clip(X, Y, W, H);
-    fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, FL_LIGHT1);
-    fl_pop_clip();
-
-    fl_push_clip(X+3, Y, W-6, H);
-    fl_font(FL_HELVETICA_BOLD, 11);
-    fl_color(FL_BLACK);
-    fl_draw(text.c_str(), X+3, Y, W-6, H, FL_ALIGN_LEFT);
-    fl_font(FL_HELVETICA, 11);
-    fl_pop_clip();
-    break;
-
-  case CONTEXT_CELL:
-
-    fl_push_clip(X, Y, W, H);
-    fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, 
-      row_selected(R) ? selection_color() : FL_WHITE);
-    fl_pop_clip();
-
-    if(R < (int) m_Body.size())
-      {
-      text = m_Body[R][C];
-      fl_push_clip(X+3, Y, W-6, H);
-      fl_color(FL_BLACK);
-      fl_draw(text.c_str(), X+3, Y, W-6, H, FL_ALIGN_LEFT);
-      fl_pop_clip();
-      }
-    break;
-
-  default:
-    break;
-  }
-}
diff --git a/UserInterface/BasicComponents/MetaDataTable.h b/UserInterface/BasicComponents/MetaDataTable.h
deleted file mode 100644
index e6843d1..0000000
--- a/UserInterface/BasicComponents/MetaDataTable.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: MetaDataTable.h,v $
-  Language:  C++
-  Date:      $Date: 2010/06/03 12:31:27 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __MetaDataTable_h_
-#define __MetaDataTable_h_
-
-#include "FL/Fl_Table.H"
-#include "FL/Fl_Table_Row.H"
-#include "SNAPCommon.h"
-#include <vector>
-#include <string>
-
-namespace itk { template <unsigned int VDim> class ImageBase; }
-
-class MetaDataTable : public Fl_Table_Row
-{
-public:
-  MetaDataTable(int x, int y, int w, int h, const char *l=0) 
-    : Fl_Table_Row(x,y,w,h,l) { end(); }
-
-  ~MetaDataTable() { }
-
-  void SetInputImage(itk::ImageBase<3> *image);
-  
-  void SetColumnWidth(int total_width);
-
-  irisGetMacro(PreferredKeyWidth, size_t);
-  irisGetMacro(PreferredValueWidth, size_t);
-
-protected:
-
-  /* Draw table cell */
-  void draw_cell(TableContext context,  		
-    int R=0, int C=0, int X=0, int Y=0, int W=0, int H=0);
-
-  std::vector< std::string > m_Header;
-  std::vector< std::vector< std::string > > m_Body;
-
-  int m_PreferredKeyWidth, m_PreferredValueWidth, m_PreferredHeight;
-
-};
-
-#endif
-
diff --git a/UserInterface/BasicComponents/RecursiveInteractionMode.cxx b/UserInterface/BasicComponents/RecursiveInteractionMode.cxx
deleted file mode 100644
index 87aab07..0000000
--- a/UserInterface/BasicComponents/RecursiveInteractionMode.cxx
+++ /dev/null
@@ -1,144 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: RecursiveInteractionMode.cxx,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:16 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "RecursiveInteractionMode.h"
-#include <algorithm>
-
-int 
-RecursiveInteractionMode
-::OnMousePress(const FLTKEvent &event) 
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    if((*m)->OnMousePress(event)) return 1;
-  return 0;
-}
-
-int RecursiveInteractionMode
-::OnMouseRelease(const FLTKEvent &event, const FLTKEvent &pressEvent) 
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    if((*m)->OnMouseRelease(event, pressEvent)) return 1;
-  return 0;
-}
-
-int 
-RecursiveInteractionMode
-::OnMouseDrag(const FLTKEvent &event, const FLTKEvent &pressEvent) 
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    if((*m)->OnMouseDrag(event, pressEvent)) return 1;
-  return 0;
-}
-
-int 
-RecursiveInteractionMode
-::OnMouseEnter(const FLTKEvent &event)
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    if((*m)->OnMouseEnter(event)) return 1;
-  return 0;
-}
-
-int 
-RecursiveInteractionMode
-::OnMouseLeave(const FLTKEvent &event) 
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    if((*m)->OnMouseLeave(event)) return 1;
-  return 0;
-}
-
-int 
-RecursiveInteractionMode
-::OnMouseMotion(const FLTKEvent &event) 
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    if((*m)->OnMouseMotion(event)) return 1;
-  return 0;
-}
-
-int 
-RecursiveInteractionMode
-::OnMouseWheel(const FLTKEvent &event) 
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    if((*m)->OnMouseWheel(event)) return 1;
-  return 0;
-}
-
-int 
-RecursiveInteractionMode
-::OnKeyDown(const FLTKEvent &event) 
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    if((*m)->OnKeyDown(event)) return 1;
-  return 0;
-}
-
-int 
-RecursiveInteractionMode
-::OnKeyUp(const FLTKEvent &event) 
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    if((*m)->OnKeyUp(event)) return 1;
-  return 0;
-}
-
-int 
-RecursiveInteractionMode
-::OnShortcut(const FLTKEvent &event) 
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    if((*m)->OnShortcut(event)) return 1;
-  return 0;
-}
-
-int 
-RecursiveInteractionMode
-::OnOtherEvent(const FLTKEvent &event) 
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    if((*m)->OnOtherEvent(event)) return 1;
-  return 0;
-}
-
-void 
-RecursiveInteractionMode
-::OnDraw() 
-{
-  for(ModeIterator m = m_Interactors.begin(); m != m_Interactors.end(); m++)
-    (*m)->OnDraw();
-}
-
-
diff --git a/UserInterface/BasicComponents/RecursiveInteractionMode.h b/UserInterface/BasicComponents/RecursiveInteractionMode.h
deleted file mode 100644
index b52f254..0000000
--- a/UserInterface/BasicComponents/RecursiveInteractionMode.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*=========================================================================
-
-  Program:   Insight Segmentation & Registration Toolkit
-  Module:    $RCSfile: RecursiveInteractionMode.h,v $
-  Language:  C++
-  Date:      $Date: 2006/12/02 04:22:21 $
-  Version:   $Revision: 1.1 $
-  Copyright (c) 2003 Insight Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-#ifndef __RecursiveInteractionMode_h_
-#define __RecursiveInteractionMode_h_
-
-#include "InteractionModeClient.h"
-#include <list>
-
-// Forward reference to FLTK Canvas
-class FLTKCanvas;
-
-/**
- * \class RecursiveInteractionMode
- * \brief An interaction mode to which more interaction modes can be added
- * This class is an interaction mode and an interaction mode client, so that
- * you can create a tree of interaction modes. The only thing to remember is 
- * that if you override one of the OnXXX event methods, you need to call 
- * Superclass::OnXXX in order for the child events to be invoked
- */
-class RecursiveInteractionMode : public InteractionMode, public InteractionModeClient
-{
-public:
-  // Typedef for the iterator
-  typedef std::list<InteractionMode *>::iterator ModeIterator;
-
-  // All the events
-  virtual int OnMousePress(const FLTKEvent &event);
-  virtual int OnMouseRelease(const FLTKEvent &event, const FLTKEvent &pressEvent);
-  virtual int OnMouseDrag(const FLTKEvent &event, const FLTKEvent &pressEvent);
-  virtual int OnMouseEnter(const FLTKEvent &event);
-  virtual int OnMouseLeave(const FLTKEvent &event);
-  virtual int OnMouseMotion(const FLTKEvent &event);
-  virtual int OnMouseWheel(const FLTKEvent &event);
-  virtual int OnKeyDown(const FLTKEvent &event);
-  virtual int OnKeyUp(const FLTKEvent &event);
-  virtual int OnShortcut(const FLTKEvent &event);
-  virtual int OnOtherEvent(const FLTKEvent &event);
-  virtual void OnDraw();
-
-  // Constructor, takes the target FLTK canvas as the parameter
-  RecursiveInteractionMode(FLTKCanvas *canvas)
-    : InteractionMode(canvas) {}
-
-  // Virtual destructor
-  virtual ~RecursiveInteractionMode() {}
-};
-
-#endif // __RecursiveInteractionMode_h_
diff --git a/UserInterface/BasicComponents/SNAPFormattedOutput.h b/UserInterface/BasicComponents/SNAPFormattedOutput.h
deleted file mode 100644
index 22d00de..0000000
--- a/UserInterface/BasicComponents/SNAPFormattedOutput.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SNAPFormattedOutput.h,v $
-  Language:  C++
-  Date:      $Date: 2010/06/15 16:27:44 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SNAPFormattedOutput_h_
-#define __SNAPFormattedOutput_h_
-
-#include "FL/Fl_Output.H"
-#include <cstdio>
-#include <cstring>
-
-/**
- * \class SNAPFormattedOutput
- * \brief An extension of Fl_Output that can take double as input
- */
-class SNAPFormattedOutput : public Fl_Output
-{
-public:
-  SNAPFormattedOutput(int X, int Y, int W, int H,const char *l=0)
-    : Fl_Output(X,Y,W,H,l) { set_format("%.4g"); }
-
-  void set_format(const char *format)
-    { strncpy(m_Format, format, 32); }
-
-  const char *get_format() const
-    { return m_Format; }
-
-  void value(double val)
-    { 
-    sprintf(m_Buffer, m_Format, val);
-    Fl_Output::value(m_Buffer);
-    }
-
-  void value(double val, const char *format)
-    { set_format(format); value(val); }
-
-protected:
-  char m_Format[32], m_Buffer[128];
-};
-
-
-#endif
diff --git a/UserInterface/BasicComponents/SNAPValueOutput.h b/UserInterface/BasicComponents/SNAPValueOutput.h
deleted file mode 100644
index a904b6b..0000000
--- a/UserInterface/BasicComponents/SNAPValueOutput.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SNAPValueOutput.h,v $
-  Language:  C++
-  Date:      $Date: 2010/06/15 16:27:44 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SNAPValueOutput_h_
-#define __SNAPValueOutput_h_
-
-#include "FL/Fl_Value_Output.H"
-#include <cstdio>
-
-/**
- * \class SNAPValueOutput
- * \brief An extension of Fl_Value_Output with specified number of significant
- * digits (uses %.*g format)
- */
-class SNAPValueOutput : public Fl_Value_Output
-{
-public:
-  SNAPValueOutput(int X, int Y, int W, int H,const char *l=0)
-    : Fl_Value_Output(X,Y,W,H,l) { this->step(4); }
-
-protected:
-
-  int format(char *buffer)
-    {
-    double s = step();
-    if(s >= 1.0)
-      return sprintf(buffer, "%.*g", (int) s, this->value());
-    else 
-      return Fl_Value_Output::format(buffer);
-    }
-
-  int handle(int event)
-    { return 0; }
-};
-
-
-#endif
diff --git a/UserInterface/BasicComponents/SnakeParametersPreviewBox.cxx b/UserInterface/BasicComponents/SnakeParametersPreviewBox.cxx
deleted file mode 100644
index 1b992b0..0000000
--- a/UserInterface/BasicComponents/SnakeParametersPreviewBox.cxx
+++ /dev/null
@@ -1,346 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SnakeParametersPreviewBox.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/19 19:15:14 $
-  Version:   $Revision: 1.6 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-
-#include "SnakeParametersPreviewBox.h"
-#include "SnakeParametersPreviewPipeline.h"
-#include "OpenGLSliceTexture.h"
-#include "SnakeParametersUILogic.h"
-#include "SNAPOpenGL.h"
-
-extern void fl_alert(const char *, ...);
-
-SnakeParametersPreviewBox
-::SnakeParametersPreviewBox(int x, int y, int w, int h, const char *label)
-: FLTKCanvas(x,y,w,h,label), m_Interactor(this)
-{
-  // Initialize the texture object
-  m_Texture = new OpenGLSliceTexture;
-  m_Texture->SetGlComponents(4);
-  m_Texture->SetGlFormat(GL_RGBA);
-
-  // Set up the interactor
-  PushInteractionMode(&m_Interactor);
-}
-
-SnakeParametersPreviewBox
-::~SnakeParametersPreviewBox()
-{
-  delete m_Texture;
-}
-
-void
-SnakeParametersPreviewBox
-::draw()
-{
-  // Set up the projection if necessary
-  if(!valid()) 
-  {
-    // The window will have coordinates (0,0) to (1,1)
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    gluOrtho2D(0.0,1.0,0.0,1.0);
-    glViewport(0,0,w(),h());
-
-    // Establish the model view matrix
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-    // glScaled(4,4,1);
-  }
-
-  // Update everything
-  m_Pipeline->Update(this);
-
-  // Clear the display
-  glClearColor(0.0,0.0,0.0,1.0);
-  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    
-
-  // Set up the line drawing attributes
-  glPushAttrib(GL_LIGHTING_BIT | GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
-
-  // Set up the model matrix
-  glPushMatrix();
-  glScaled(1.0 / m_Pipeline->GetSpeedImage()->GetBufferedRegion().GetSize(0),
-           1.0 / m_Pipeline->GetSpeedImage()->GetBufferedRegion().GetSize(1),
-           1.0);
-  
-  // Draw the speed image
-  m_Texture->SetImage(m_Pipeline->GetDisplayImage());
-  m_Texture->Draw(Vector3d(1.0));
-
-  // Set up the line drawing mode
-  glEnable(GL_LINE_SMOOTH);
-  glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
-  glEnable(GL_BLEND);
-  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-  
-  glLineWidth(2.0);
-  glColor3d(1.0, 0.0, 0.0);
-
-  // Draw the evolving contour if it's available
-  if(m_Pipeline->IsDemoLoopRunning())
-    {
-    std::vector<Vector2d> &points = m_Pipeline->GetDemoLoopContour();
-    glColor3d(1.0, 0.0, 0.0);
-    glBegin(GL_LINES);
-    std::vector<Vector2d>::iterator it = points.begin();
-    for(; it != points.end(); ++it)
-      {
-      glVertex(*it);
-      }
-    glEnd();
-
-    glLineWidth(1.0);
-    glColor4d(1.0, 0.0, 0.0, 0.5);
-    }
-
-
-  // Draw the vectors
-  //glLineWidth(1.0);
-
-  // No more image scaling
-  glPopMatrix();
-  glPushMatrix();
-
-  // Get the point collection
-  const SnakeParametersPreviewPipeline::SampledPointList 
-    &list = m_Pipeline->GetSampledPoints();
-    
-  // Draw the spline
-  glBegin(GL_LINE_LOOP);
-  for(unsigned int j=0;j<list.size();j++)
-    {
-    glVertex2d(list[j].x[0],list[j].x[1]);
-    }
-  glEnd();
-
-  // Draw the forces on the spline
-  // Draw the vectors from the curve
-  glColor3d(1.0,0.0,0.0);
-  glBegin(GL_LINES);
-  for(unsigned int i=0;i<list.size();i+=4)
-    {
-    // A reference so we can access the point in shorthand
-    const SnakeParametersPreviewPipeline::SampledPoint &p = list[i];
-    
-    // Decide which force to draw, depending on the current state
-    double force = 0;
-    switch(m_ForceToDisplay) 
-      {
-      case PROPAGATION_FORCE : 
-        force = p.PropagationForce; 
-        break;
-      case CURVATURE_FORCE : 
-        force = p.CurvatureForce; 
-        break;
-      case ADVECTION_FORCE : 
-        force = p.AdvectionForce; 
-        break;
-      case TOTAL_FORCE : 
-        force = p.PropagationForce + p.CurvatureForce + p.AdvectionForce;
-        break;
-      }
-
-    // Scale the force for effect
-    force *= 10;
-
-    // Draw the forces
-    glVertex2d(p.x[0],p.x[1]);
-    glVertex2d(p.x[0] + force * p.n[0] / w(),p.x[1] + force * p.n[1] / w());     
-  }
-
-  glEnd();  
-
-/*
-  const SnakeParametersPreviewPipeline::ImagePointList
-    &plist = m_Pipeline->GetImagePoints();
-  
-  glBegin(GL_LINES);
-  for(unsigned int j=0;j<plist.size();j++)
-    {
-    const SnakeParametersPreviewPipeline::PointInfo &point = plist[j];
-    
-    float length = 10.0f;
-    switch(m_ForceToDisplay)
-      {
-      case CURVATURE_FORCE   : length *= point.CurvatureForce; break;
-      case ADVECTION_FORCE   : length *= point.AdvectionForce; break;
-      case PROPAGATION_FORCE : length *= point.PropagationForce; break;
-      case TOTAL_FORCE       : 
-        length *= (point.CurvatureForce + point.AdvectionForce + 
-                   point.PropagationForce); break;
-      }
-    
-    SnakeParametersPreviewPipeline::SampledPoint p = point.point;
-    glVertex2d(p.x[0],p.x[1]);
-    glVertex2d(p.x[0] + length * p.n[0],p.x[1] + length * p.n[1]);
-    }
-  glEnd();
-*/
-
-  // Draw the interactor
-  m_Interactor.OnDraw();
-  
-  // Pop the matrix
-  glPopMatrix();
-  
-  // Restore the attribute state
-  glPopAttrib();
-}
-
-SnakeParametersPreviewBox::Interactor
-::Interactor(SnakeParametersPreviewBox *owner)
-: InteractionMode(owner)
-{
-  m_Owner = owner;
-  m_ControlPicked = m_ControlsVisible = false;
-}
-
-int
-SnakeParametersPreviewBox::Interactor
-::OnMousePress(const FLTKEvent &event)
-{
-  // Get the point of the event
-  Vector2d xClick(
-    event.XCanvas[0] * 1.0 / m_Owner->w(), 
-    event.XCanvas[1] * 1.0 / m_Owner->h());
-
-  if(m_ControlsVisible) 
-    {
-    // The closest point index
-    m_ActiveControl = 0;
-    double minDistance = 0.0;
-
-    // Get a hold of the control points
-    const SnakeParametersPreviewPipeline::ControlPointList 
-      &cp = m_Owner->m_Pipeline->GetControlPoints();    
-
-    // Find the closest control point
-    for(unsigned int i=0;i<cp.size();i++)
-      {
-      double distance = (cp[i] - xClick).two_norm();
-      if(i == 0 || minDistance > distance) 
-        {
-        minDistance = distance;
-        m_ActiveControl = i;
-        }
-      }
-
-    // Make sure the distance is large enough
-    if(minDistance < 6.0 / m_Owner->w())
-      {
-      m_ControlPicked = true;
-      }
-    else
-      {
-      m_ControlsVisible = m_ControlPicked = false;
-      m_Owner->redraw();
-      }
-    }
-  else 
-    {
-    m_ControlsVisible = true;
-    m_Owner->redraw();
-    }
-
-  return true;
-}
-
-int
-SnakeParametersPreviewBox::Interactor
-::OnMouseRelease(const FLTKEvent &event, const FLTKEvent &irisNotUsed(pressEvent))
-{
-  Vector2d xClick(
-    event.XCanvas[0] * 1.0 / m_Owner->w(), 
-    event.XCanvas[1] * 1.0 / m_Owner->h());
-
-  if(m_ControlPicked)
-    {
-    // Update the control point
-    m_Owner->m_Pipeline->ChangeControlPoint(
-      m_ActiveControl, xClick, false);
-
-    // Redraw the parent
-    m_Owner->GetParentUI()->RedrawAllBoxes();
-    }
-
-  return true;
-}
-
-int
-SnakeParametersPreviewBox::Interactor
-::OnMouseDrag(const FLTKEvent &event, const FLTKEvent &irisNotUsed(pressEvent))
-{
-  Vector2d xClick(
-    event.XCanvas[0] * 1.0 / m_Owner->w(), 
-    event.XCanvas[1] * 1.0 / m_Owner->h());
-
-  if(m_ControlPicked)
-    {
-    // Update the control point
-    m_Owner->m_Pipeline->ChangeControlPoint(
-      m_ActiveControl, xClick, false);
-
-    // Redraw the parent
-    m_Owner->GetParentUI()->RedrawAllBoxes();
-    }
-
-  return true;
-}
-
-void
-SnakeParametersPreviewBox::Interactor
-::OnDraw()
-{
-  if(m_ControlsVisible)
-    {
-    glColor3f(1,0.67,0.33);
-
-    // Get a hold of the control points
-    const SnakeParametersPreviewPipeline::ControlPointList 
-      &cp = m_Owner->m_Pipeline->GetControlPoints();    
-    
-    for(unsigned int i=0;i<cp.size();i++)
-      {
-      glPushMatrix();
-      glTranslated(cp[i][0],cp[i][1],0);
-      
-      GLUquadric *obj = gluNewQuadric();
-      gluDisk(obj,0, 4.0 / m_Owner->w(),8,3);
-      gluDeleteQuadric(obj);
-      glPopMatrix();
-      }
-    }
-}
-
diff --git a/UserInterface/BasicComponents/SnakeParametersPreviewBox.h b/UserInterface/BasicComponents/SnakeParametersPreviewBox.h
deleted file mode 100644
index 377ba1b..0000000
--- a/UserInterface/BasicComponents/SnakeParametersPreviewBox.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SnakeParametersPreviewBox.h,v $
-  Language:  C++
-  Date:      $Date: 2009/07/16 22:02:27 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-
-#ifndef __SnakeParametersPreviewBox_h_
-#define __SnakeParametersPreviewBox_h_
-
-#include "FLTKCanvas.h"
-#include "SnakeParameters.h"
-#include "itkRGBAPixel.h"
-
-class OpenGLSliceTexture;
-class SnakeParametersPreviewPipeline;
-class SnakeParametersUILogic;
-
-/**
- * \class SnakeParametersPreviewBox
- * \brief A user interface component used to preview snake 
- * parameters in 2D.  
- * 
- * This component displays a portion of an image and a curve representing
- * an evolving snake.  Using the snake equation parameters that the user specifies,
- * forces normal to the boundary of the image are shown as vectors
- */
-class SnakeParametersPreviewBox : public FLTKCanvas
-{
-public:
-  SnakeParametersPreviewBox(int x, int y, int w, int h, const char *label=0);
-  virtual ~SnakeParametersPreviewBox();
-
-  /** A preview pipeline that has the logic of this class */
-  irisSetMacro(Pipeline,SnakeParametersPreviewPipeline *);
-  irisGetMacro(Pipeline,SnakeParametersPreviewPipeline *);
-
-  irisSetMacro(ParentUI, SnakeParametersUILogic *);
-  irisGetMacro(ParentUI, SnakeParametersUILogic *);
-  
-  /** An enumeration of different display modes for this widget */
-  enum DisplayMode 
-    {
-    CURVATURE_FORCE=0,ADVECTION_FORCE,PROPAGATION_FORCE,TOTAL_FORCE
-    };
-
-  /** Set the display mode */
-  irisSetMacro(ForceToDisplay,DisplayMode);
-  
-  /** Draw method - paints the widget */
-  void draw();
-  
-protected:
-  
-  // Texture type for drawing speed images
-  typedef itk::RGBAPixel<unsigned char> RGBAType;
-
-  /** Parent UI */
-  SnakeParametersUILogic *m_ParentUI;
-
-  /** Preview pipeline logic */
-  SnakeParametersPreviewPipeline *m_Pipeline;
-  
-  /** A texture object used to store the image */
-  OpenGLSliceTexture *m_Texture;
-  
-  /** Which force is being displayed? */
-  DisplayMode m_ForceToDisplay;
-
-  /** An interaction mode for point manipulation */
-  class Interactor : public InteractionMode {
-  public:
-    Interactor(SnakeParametersPreviewBox *owner);
-
-    int OnMousePress(const FLTKEvent &event);
-    int OnMouseRelease(const FLTKEvent &event, const FLTKEvent &irisNotUsed(pressEvent));
-    int OnMouseDrag(const FLTKEvent &event, const FLTKEvent &irisNotUsed(pressEvent));
-    void OnDraw();
-  private:
-    SnakeParametersPreviewBox *m_Owner;
-    bool m_ControlsVisible;
-    bool m_ControlPicked;
-    unsigned int m_ActiveControl;
-  };
-
-  // Allow private access to the interactor
-  friend class SnakeParametersPreviewBox::Interactor;
-
-  /** The interactor */
-  Interactor m_Interactor;
-};
-
-
-
-
-
-#endif // __SnakeParametersPreviewBox_h_
diff --git a/UserInterface/BasicComponents/SnakeParametersPreviewPipeline.cxx b/UserInterface/BasicComponents/SnakeParametersPreviewPipeline.cxx
deleted file mode 100644
index 39d34d0..0000000
--- a/UserInterface/BasicComponents/SnakeParametersPreviewPipeline.cxx
+++ /dev/null
@@ -1,628 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SnakeParametersPreviewPipeline.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/19 19:15:14 $
-  Version:   $Revision: 1.6 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "SnakeParametersPreviewPipeline.h"
-
-#include "FL/Fl.H"
-#include "FL/Fl_Gl_Window.H"
-#include "SNAPOpenGL.h"
-#include "GlobalState.h"
-
-#include "LevelSetExtensionFilter.h"
-#include "SignedDistanceFilter.h"
-#include "SNAPLevelSetFunction.h"
-#include "itkBSplineInterpolationWeightFunction.h"
-#include "itkBSplineKernelFunction.h"
-#include "itkImageRegionConstIteratorWithIndex.h"
-#include "itkNarrowBandLevelSetImageFilter.h"
-#include "itkVTKImageExport.h"
-#include "vtkCellArray.h"
-#include "vtkContourFilter.h"
-#include "vtkImageData.h"
-#include "vtkImageImport.h"
-#include "vtkPolyData.h"
-
-#include "SNAPLevelSetDriver.h"
-#include "PolygonScanConvert.h"
-
-#ifndef vtkFloatingPointType
-#define vtkFloatingPointType float
-#endif
-
-using namespace std;
-
-extern void fl_alert(const char *, ...);
-
-/**
- * This private-scope class creates a 2D demo of the level set segmentation
- * The segmentation is a 2D version of the SNAP segmentation, with contours
- * extracted at each iteration. The user supplies the speed image, a set of
- * points that form the initial contour and the snake evolution parameters.
- * Then, on a timer, call OnTimerEvent() to generate a demo loop of evolving
- * contours.
- */
-class LevelSetPreview2d
-{
-public:
-  typedef itk::OrientedImage<float, 2> FloatImageType;
-  typedef SnakeParametersPreviewPipeline::SampledPointList CurveType;
-
-  // Constructor
-  LevelSetPreview2d()
-    {
-    m_Driver = NULL;
-    m_SpeedImage = NULL;
-    m_DriverDirty = true;
-    m_ContourDirty = true;
-    m_DemoLoopLength = 160;
-    m_DemoLoopStep = 2;
-    m_LevelSetImage = NULL;
-
-    }
-
-  // Destructor
-  ~LevelSetPreview2d()
-    { 
-    if(m_Driver) delete m_Driver; 
-    }
-
-  // Timer callback, used to regenerate the current contour
-  void OnTimerEvent()
-    {
-    // Clear the output
-    m_CurrentCurve.clear();
-
-    // If the driver is dirty, we need to create a new one
-    if(m_DriverDirty && m_Driver != NULL)
-      { 
-      delete m_Driver;
-      m_Driver = NULL;
-      }
-
-    // If the driver is null and all the necessary components exist, create it
-    if(m_Driver == NULL && m_SpeedImage.IsNotNull() && m_Curve.size() > 0)
-      {
-      // Check if we need to allocate the level set image
-      if(m_LevelSetImage.IsNull() || m_LevelSetImage->GetBufferedRegion() != 
-          m_SpeedImage->GetBufferedRegion())
-        {
-        m_LevelSetImage = FloatImageType::New();
-        m_LevelSetImage->SetRegions(m_SpeedImage->GetBufferedRegion());
-        m_LevelSetImage->Allocate();
-        m_ContourDirty = true;
-        }
-
-      // Check if the contour is dirty, and create a contour image
-      if(m_ContourDirty)
-        {
-        // Scale the contour by the size of the image
-        std::vector<Vector2d> points; points.reserve(m_Curve.size());
-        for(CurveType::iterator it = m_Curve.begin(); it != m_Curve.end(); ++it)
-          {
-          points.push_back(Vector2d(
-            it->x[0] *  m_LevelSetImage->GetBufferedRegion().GetSize()[0], 
-            it->x[1] *  m_LevelSetImage->GetBufferedRegion().GetSize()[1]));
-          }
-
-        // Fill in the contour in the level set image
-        m_LevelSetImage->FillBuffer(0.0f);
-        typedef PolygonScanConvert<
-          float, GL_FLOAT, std::vector<Vector2d>::iterator> ScanConvertType;
-        ScanConvertType::RasterizeFilled(
-          points.begin(), points.size(), m_LevelSetImage);
-
-        // Ensure that the initial level set is zero
-        typedef itk::ImageRegionIterator<FloatImageType> IteratorType;
-        IteratorType it2(m_LevelSetImage, m_LevelSetImage->GetBufferedRegion());
-        for(; !it2.IsAtEnd(); ++it2)
-          it2.Set(it2.Get() > 0 ? -1.0 : 1.0);
-        m_LevelSetImage->Modified();
-
-        // The contour is not dirty any more
-        m_ContourDirty = false;
-        }
-
-      m_Driver = new SNAPLevelSetDriver2d(
-        m_LevelSetImage.GetPointer(), m_SpeedImage, m_Parameters);
-
-      m_DriverDirty = false;
-      m_DemoLoopTime = 0;
-      }
-
-    // Now that we've made sure that the driver is OK, run the demo loop
-    if(m_Driver != NULL)
-      {
-      // Run some number of level set evolutions
-      if(m_DemoLoopTime > m_DemoLoopLength)
-        {
-        m_DemoLoopTime = 0;
-        m_Driver->Restart();
-        }
-      else
-        {
-        m_Driver->Run(m_DemoLoopStep);
-        m_DemoLoopTime += m_DemoLoopStep;
-        }
-
-      // Initialize the VTK Importer
-      m_VTKExporter = itk::VTKImageExport<FloatImageType>::New();
-      m_VTKImporter = vtkImageImport::New();
-
-      // Pipe the importer into the exporter (that's a lot of code)
-      m_VTKImporter->SetUpdateInformationCallback(
-        m_VTKExporter->GetUpdateInformationCallback());
-      m_VTKImporter->SetPipelineModifiedCallback(
-        m_VTKExporter->GetPipelineModifiedCallback());
-      m_VTKImporter->SetWholeExtentCallback(
-        m_VTKExporter->GetWholeExtentCallback());
-      m_VTKImporter->SetSpacingCallback(
-        m_VTKExporter->GetSpacingCallback());
-      m_VTKImporter->SetOriginCallback(
-        m_VTKExporter->GetOriginCallback());
-      m_VTKImporter->SetScalarTypeCallback(
-        m_VTKExporter->GetScalarTypeCallback());
-      m_VTKImporter->SetNumberOfComponentsCallback(
-        m_VTKExporter->GetNumberOfComponentsCallback());
-      m_VTKImporter->SetPropagateUpdateExtentCallback(
-        m_VTKExporter->GetPropagateUpdateExtentCallback());
-      m_VTKImporter->SetUpdateDataCallback(
-        m_VTKExporter->GetUpdateDataCallback());
-      m_VTKImporter->SetDataExtentCallback(
-        m_VTKExporter->GetDataExtentCallback());
-      m_VTKImporter->SetBufferPointerCallback(
-        m_VTKExporter->GetBufferPointerCallback());  
-      m_VTKImporter->SetCallbackUserData(
-        m_VTKExporter->GetCallbackUserData());  
-
-      // Create and configure the contour filter
-      m_VTKContour = vtkContourFilter::New();
-      m_VTKContour->SetInput(m_VTKImporter->GetOutput());    
-      m_VTKContour->ReleaseDataFlagOn();
-      m_VTKContour->ComputeScalarsOff();
-      m_VTKContour->ComputeGradientsOff();
-      m_VTKContour->UseScalarTreeOn();
-      m_VTKContour->SetNumberOfContours(1);
-      m_VTKContour->SetValue(0, 0.0);
-
-      // Generate a contour
-      m_VTKExporter->SetInput(m_Driver->GetCurrentState());
-      m_VTKContour->Update();
-
-      // Get the list of points representing the evolving contour
-      vtkPolyData *pd = m_VTKContour->GetOutput();
-      m_CurrentCurve.reserve(pd->GetNumberOfCells() * 2);
-      for(int i=0;i<pd->GetNumberOfCells();i++)
-        {
-        vtkFloatingPointType *pt1 = pd->GetPoint(pd->GetCell(i)->GetPointId(0));
-        m_CurrentCurve.push_back(Vector2d(pt1[0] + 0.5,pt1[1] + 0.5));
-        vtkFloatingPointType *pt2 = pd->GetPoint(pd->GetCell(i)->GetPointId(1));
-        m_CurrentCurve.push_back(Vector2d(pt2[0] + 0.5,pt2[1] + 0.5));
-        }
-      }
-
-    m_VTKImporter->Delete();
-    m_VTKContour->Delete();
-    }
-
-  // Change the speed image passed as the input to the level set
-  void SetSpeedImage(FloatImageType *image)
-    {
-    if(image != m_SpeedImage)
-      {
-      m_DriverDirty = true;
-      m_ContourDirty = true;
-      m_SpeedImage = image;
-      }
-    }
-
-  // Set the initial contour curve
-  void SetInitialContour(const CurveType &curve)
-    {
-    m_Curve = curve;
-    m_ContourDirty = true;
-    m_DriverDirty = true;
-    }
-
-  // Set the snake paramters
-  void SetSnakeParameters(const SnakeParameters &parameters)
-    {
-    if(!(m_Parameters == parameters))
-      {
-      m_Parameters = parameters;
-      m_DriverDirty = true;
-      }
-    }
-
-  // Set the length of the demo loop
-  void SetDemoLoopLength(unsigned int length)
-    {
-    m_DemoLoopLength = length;
-    m_DriverDirty = true;
-    }
-
-  // Set the step size of the demo loop
-  void SetDemoLoopStep(unsigned int step)
-    {
-    m_DemoLoopStep = step;
-    m_DriverDirty = true;
-    }
-
-  // See if there is something to display
-  bool IsLevelSetComputed()
-    { return m_Driver != NULL; }
-
-  // Get the level set image to display
-  FloatImageType *GetLevelSetImage()
-    { return m_Driver->GetCurrentState(); }
-
-  // Get the evolving contour
-  vector<Vector2d> &GetEvolvingContour()
-    { return m_CurrentCurve; }
-
-private:
-  // Parameters of the level set algorithm
-  FloatImageType::Pointer m_SpeedImage, m_LevelSetImage;
-  CurveType m_Curve;
-  SnakeParameters m_Parameters;
-  unsigned int m_DemoLoopStep, m_DemoLoopLength, m_DemoLoopTime;
-
-  // Snake evolution driver pointer
-  SNAPLevelSetDriver2d *m_Driver;
-
-  // VTK objects for computing a contour
-  typedef itk::VTKImageExport<FloatImageType> ExporterType;
-  itk::SmartPointer<ExporterType> m_VTKExporter;
-  vtkImageImport *m_VTKImporter;
-  vtkContourFilter *m_VTKContour;
-
-  // The zero level set, as it evolves
-  vector<Vector2d> m_CurrentCurve;
-
-  bool m_DriverDirty, m_ContourDirty;
-};
-
-
-
-void 
-SnakeParametersPreviewPipeline
-::AnimationCallback()
-{
-  // Call the callback on the demo loop
-  m_DemoLoop->OnTimerEvent();
-}
-
-SnakeParametersPreviewPipeline
-::SnakeParametersPreviewPipeline(GlobalState *state)
-{
-  // Store the global state
-  m_GlobalState = state;
-
-  // Start with a 100 interpolated points
-  m_NumberOfSampledPoints = 100;
-
-  m_ControlsModified = false;
-  m_SpeedModified = false;
-  m_ParametersModified = false;
-  m_QuickUpdate = false;
-
-  // Initialize the parameters
-  m_Parameters = SnakeParameters::GetDefaultEdgeParameters();
-
-  // Initialize the display filter
-  m_DisplayMapper = IntensityFilterType::New();
-
-  // Set the current color map preset
-  m_ColorMapPreset = m_GlobalState->GetSpeedColorMap();
-  m_DisplayMapper->SetFunctor(
-    SpeedColorMap::GetPresetColorMap(m_ColorMapPreset));
-
-  // Create a new demo loop
-  m_DemoLoop = new LevelSetPreview2d;
-
-  // The demo loop is not running
-  m_DemoLoopRunning = false;
-}
-
-SnakeParametersPreviewPipeline
-::~SnakeParametersPreviewPipeline()
-{
-  delete m_DemoLoop;
-}
-
-void
-SnakeParametersPreviewPipeline
-::SetControlPoints(const std::vector<Vector2d> &points)
-{
-  if(m_ControlPoints != points)
-    {  
-    // Save the points
-    m_ControlPoints = points;
-
-    // Set the flags
-    m_ControlsModified = true;
-    m_QuickUpdate = false;
-    }
-}
-
-void 
-SnakeParametersPreviewPipeline
-::ChangeControlPoint(
-  unsigned int index, const Vector2d &point, bool quickUpdate)
-{
-  // Update the point
-  assert(index < m_ControlPoints.size());
-
-  // Update the point
-  m_ControlPoints[index] = point;
-
-  // Set the flags
-  m_ControlsModified = true;
-
-  // Set the update flag
-  m_QuickUpdate = quickUpdate;
-}
-
-void
-SnakeParametersPreviewPipeline
-::SetSpeedImage(FloatImageType *image)
-{
-  // Update the image internally
-  if(image != m_SpeedImage)
-    {
-    // Set the modified flag
-    m_SpeedModified = true;
-    m_SpeedImage = image;
-
-    // Create a filter to compute a gradient image
-    typedef itk::GradientImageFilter<FloatImageType> GradientFilter;
-    GradientFilter::Pointer filter = GradientFilter::New();
-
-    // Set up and run the filter
-    filter->SetInput(m_SpeedImage);
-    m_GradientImage = filter->GetOutput();
-    filter->Update();
-
-    // Pass the image to the display functor
-    m_DisplayMapper->SetInput(m_SpeedImage);
-
-    // Pass the speed image to the preview object
-    m_DemoLoop->SetSpeedImage(image);
-    }
-}
-
-void
-SnakeParametersPreviewPipeline
-::SetSnakeParameters(const SnakeParameters &parameters)
-{
-  // Clean up the parameters
-  SnakeParameters clean = parameters;
-  clean.SetClamp(false);
-  clean.SetGround(0);
-  clean.SetLaplacianSpeedExponent(0);
-  clean.SetLaplacianWeight(0);
-  clean.SetSolver(SnakeParameters::PARALLEL_SPARSE_FIELD_SOLVER);
-
-  // Make the 2D example behave more like 3D ...
-  clean.SetCurvatureWeight(5 * parameters.GetCurvatureWeight());
-
-  // Don't waste time on nonsense
-  if(m_Parameters == clean) return;
-    
-  // Save the parameters
-  m_Parameters = clean;
-  m_ParametersModified = true;
-
-  // Pass the parameters to the demo loop
-  m_DemoLoop->SetSnakeParameters(m_Parameters);
-}
-
-void 
-SnakeParametersPreviewPipeline
-::SetNumberOfSampledPoints(unsigned int number)
-{
-  if(number!=m_NumberOfSampledPoints)
-    {
-    m_NumberOfSampledPoints = number;
-    m_ControlsModified = true;
-    }
-}
-
-void
-SnakeParametersPreviewPipeline
-::Update(Fl_Gl_Window *context)
-{
-  // Check what work needs to be done
-  if(m_ControlsModified)
-    {
-    UpdateContour();
-    }
-  if(!m_QuickUpdate)
-    {
-    if(m_ControlsModified)
-      {
-      m_DemoLoop->SetInitialContour(GetSampledPoints());
-      // UpdateLevelSet(context);
-      }
-    if(m_ParametersModified || m_ControlsModified)
-      {
-      UpdateForces();
-      m_ParametersModified = false;
-      }
-    }
-
-  // Clear the modified flags
-  m_ControlsModified = false;
-
-  // Also, check whether the colormap used for display has changed
-  if(m_ColorMapPreset != m_GlobalState->GetSpeedColorMap())
-    {
-    m_ColorMapPreset = m_GlobalState->GetSpeedColorMap();
-    m_DisplayMapper->SetFunctor(
-      SpeedColorMap::GetPresetColorMap(m_ColorMapPreset));
-    }
-}
-
-void 
-SnakeParametersPreviewPipeline
-::UpdateContour()
-{
-  // Create a b-spline object
-  typedef itk::BSplineInterpolationWeightFunction<double,1,3> FunctionType;
-  FunctionType::Pointer function = FunctionType::New();
-
-  // Used to compute spline derivatives
-  itk::BSplineKernelFunction<3>::Pointer kf3 = itk::BSplineKernelFunction<3>::New();
-  itk::BSplineKernelFunction<2>::Pointer kf2 = itk::BSplineKernelFunction<2>::New();
-  itk::BSplineKernelFunction<2>::Pointer kf1 = itk::BSplineKernelFunction<2>::New();
-
-  // Initialize the sampled point array
-  m_SampledPoints.clear();
-  m_SampledPoints.reserve(m_NumberOfSampledPoints);
-  
-  int uMax = m_ControlPoints.size() - 3; 
-  for(double t = 0; t < 1.0; t += 0.005)
-    {
-    double s = t * uMax;
-    
-    // The starting index
-    // int si = ((int)(t * uMax)) - 1;
-    int sidx = (int) floor(s - 1);
-    double u = s - sidx;
-
-    // Compute the position and derivatives of the b-spline
-    Vector2d x(0.0f,0.0f);
-    Vector2d xu(0.0f,0.0f);
-    Vector2d xuu(0.0f,0.0f);
-    for(int k=0; k < 4; k++)
-      {      
-      double w = kf3->Evaluate(u);
-      double wu = kf2->Evaluate(u+0.5) - kf2->Evaluate(u-0.5);
-      double wuu = kf1->Evaluate(u+1) + kf1->Evaluate(u-1) - 2 * kf1->Evaluate(u);
-      u-=1.0;
-
-      int idx = (uMax + sidx + k) % uMax;
-      x += w * m_ControlPoints[idx];
-      xu += wu * m_ControlPoints[idx];
-      xuu += wuu * m_ControlPoints[idx];
-      }
-
-    // Create and save the point
-    SampledPoint pt;
-    pt.x = x;
-    pt.t = t;
-    xu.normalize();
-    pt.n = Vector2d(-xu[1],xu[0]);    
-    pt.PropagationForce = pt.CurvatureForce = pt.AdvectionForce = 0.0;
-    pt.kappa 
-      = (xu[0] * xuu[1] - xu[1] * xuu[0]) / pow(xu[0]*xu[0] + xu[1]*xu[1],1.5);
-
-    m_SampledPoints.push_back(pt);
-    }
-}
-
-void
-SnakeParametersPreviewPipeline
-::UpdateLevelSetFunction()
-{
-}
-
-void
-SnakeParametersPreviewPipeline
-::UpdateLevelSet(Fl_Gl_Window *irisNotUsed(context))
-{
-}
-
-void
-SnakeParametersPreviewPipeline
-::UpdateForces()
-{
-  // Image interpolator types
-  typedef itk::LinearInterpolateImageFunction<
-    FloatImageType,double> LerpType;
-  typedef itk::VectorLinearInterpolateImageFunction<
-    VectorImageType,double> VectorLerpType;
-  
-  // Create the speed image interpolator
-  LerpType::Pointer sLerp = LerpType::New();
-  sLerp->SetInputImage(m_SpeedImage);
-
-  // Create the gradient image interpolator
-  VectorLerpType::Pointer gLerp = VectorLerpType::New();
-  gLerp->SetInputImage(m_GradientImage);
-
-  // Get the image dimensions
-  itk::Size<2> idim = m_SpeedImage->GetBufferedRegion().GetSize();
-  
-  // Compute the geometry of each point
-  for(unsigned int i = 0; i < m_SampledPoints.size(); i++)
-    {
-    // A reference so we can access the point in shorthand
-    SampledPoint &p = m_SampledPoints[i];
-    
-    // We're done computing the geometric properties of the curve.  Now, let's
-    // compute the image-related quantities.  First, convert the point to image
-    // coordinates
-    LerpType::ContinuousIndexType idx;
-    idx[0] = idim[0] * p.x[0];
-    idx[1] = idim[1] * p.x[1];
-
-    // Get the value of the g function
-    double g = sLerp->EvaluateAtContinuousIndex(idx);
-
-    // Get the value of the gradient
-    VectorLerpType::OutputType gradG = gLerp->EvaluateAtContinuousIndex(idx);
-    
-    // Compute the propagation force component of the curve evolution
-    p.PropagationForce = m_Parameters.GetPropagationWeight() 
-      * pow(g,m_Parameters.GetPropagationSpeedExponent());
-
-    // Compute the curvature force component of the curve evolution
-    p.CurvatureForce = m_Parameters.GetCurvatureWeight() * p.kappa
-      * pow(g,m_Parameters.GetCurvatureSpeedExponent()+1);
-
-    // Compute the advection force component of the curve evolution
-    p.AdvectionForce = - m_Parameters.GetAdvectionWeight()
-      * (p.n[0] * gradG[0] + p.n[1] * gradG[1])
-      * pow(g,m_Parameters.GetAdvectionSpeedExponent());    
-    }
-}
-
-
-
-std::vector<Vector2d> &
-SnakeParametersPreviewPipeline
-::GetDemoLoopContour()
-{
-  return m_DemoLoop->GetEvolvingContour();
-}
diff --git a/UserInterface/BasicComponents/SnakeParametersPreviewPipeline.h b/UserInterface/BasicComponents/SnakeParametersPreviewPipeline.h
deleted file mode 100644
index 0ec1124..0000000
--- a/UserInterface/BasicComponents/SnakeParametersPreviewPipeline.h
+++ /dev/null
@@ -1,219 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SnakeParametersPreviewPipeline.h,v $
-  Language:  C++
-  Date:      $Date: 2009/01/23 20:09:38 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SnakeParametersPreviewPipeline_h_
-#define __SnakeParametersPreviewPipeline_h_
-
-#include "SNAPOpenGL.h"
-#include "SNAPCommonUI.h"
-#include "itkOrientedImage.h"
-#include "itkRGBAPixel.h"
-#include "itkCovariantVector.h"
-#include "itkUnaryFunctorImageFilter.h"
-#include "SnakeParameters.h"
-#include "SpeedColorMap.h"
-
-template<class TInputImage, class TOutputImage> class SignedDistanceFilter;
-template<class TInputImage> class SNAPLevelSetFunction;
-template<class TFilter> class LevelSetExtensionFilter;
-class Fl_Gl_Window;
-
-class vtkImageImport;
-class vtkContourFilter;
-class LevelSetPreviewPipeline2D;
-
-namespace itk {
-  template<class TInputImage, class TOutputImage> 
-    class ParallelSparseFieldLevelSetImageFilter;
-};
-
-class LevelSetPreview2d;
-
-// #define SNAKE_PREVIEW_ADVANCED 1
-
-/** 
- * \class SnakeParametersPreviewPipeline
- * \brief A pipeline used to preview snake parameters.
- * 
- * Given a set of control points an image, and some snake parameters, this
- * class computes a b-spline curve based on those control points, creates a
- * level set embedding of the curve, and computes various level set evolution
- * forces acting on the curve.
- */
-class SnakeParametersPreviewPipeline
-{
-public:
-  SnakeParametersPreviewPipeline(GlobalState *state);
-  virtual ~SnakeParametersPreviewPipeline();
-
-  // Images used by this class (internally and externally)
-  typedef itk::OrientedImage<unsigned char, 2> CharImageType;
-  typedef itk::OrientedImage<float, 2> FloatImageType;
-
-  // Define a color image for display
-  typedef itk::RGBAPixel<unsigned char> DisplayPixelType;
-  typedef itk::OrientedImage<DisplayPixelType,2> DisplayImageType;
-
-  // Index type used to refer to pixels
-  typedef FloatImageType::IndexType IndexType;
-
-  // Force types
-  enum ForceType {CURVATURE=0, ADVECTION, PROPAGATION, TOTAL };
-  
-  // A sample from the curve
-  struct SampledPoint {
-    // The geometry of the point
-    double t;
-    Vector2d x;
-    Vector2d n;
-    double kappa;
-    
-    // The forces acting on the point
-    double PropagationForce;
-    double CurvatureForce;
-    double AdvectionForce;
-    
-    double operator[](unsigned int i) const
-      { return x[i]; } 
-  };
-
-  // Various list types
-  typedef std::vector<Vector2d> ControlPointList;
-  typedef std::vector<Vector2d> LevelSetContourType;
-  typedef std::vector<SampledPoint> SampledPointList;  
-
-  /** Set the speed image */
-  void SetSpeedImage(FloatImageType *image);
-
-  /** Set the snake parameters */
-  void SetSnakeParameters(const SnakeParameters &parameters);
-
-  /** Set the control points of the interface curve */
-  void SetControlPoints(const ControlPointList &points);
-
-  /** Change just one control point, with an option of changing it
-   * quickly, ie, not recomputing the level set, only the curve */
-  void ChangeControlPoint(unsigned int index, const Vector2d &point,
-    bool quickUpdate);
-
-  /** Set the number of points sampled for display of the curve */
-  void SetNumberOfSampledPoints(unsigned int number);
-  
-  /** Update the internals of the pipeline and compute the curve and the
-   * force points.  This method requires a GL context because it relies on
-   * GL tesselation code for generating an image from the curve */
-  void Update(Fl_Gl_Window *context);
-
-  /** Get the speed image */
-  irisGetMacro(SpeedImage,FloatImageType *);
-  
-  /** Get a reference to the control points of the interface curve */
-  irisGetMacro(ControlPoints,const ControlPointList &);
-
-  /** Get a list of densely interpolated points on the curve (for drawing) */
-  irisGetMacro(SampledPoints,const SampledPointList &);
-
-  /** Is the demo loop running ? */
-  irisIsMacro(DemoLoopRunning);
-  irisSetMacro(DemoLoopRunning, bool);
-
-  /** Get the demo loop contour */
-  std::vector<Vector2d> &GetDemoLoopContour();
-
-  /** Get the color image corresponding to the speed image */
-  DisplayImageType *GetDisplayImage()  
-    { return m_DisplayMapper->GetOutput(); }
-
-  /** Set the idle callback function that FLTK should call in demo mode */
-  void AnimationCallback();
-
-private:
-
-  /** The global state */
-  GlobalState *m_GlobalState;
-      
-  /** The speed image */
-  itk::SmartPointer<FloatImageType> m_SpeedImage;
-
-  // Gradient image used by this component
-  typedef itk::CovariantVector<float,2> VectorType;
-  typedef itk::Image<VectorType,2> VectorImageType;
-  typedef itk::SmartPointer<VectorImageType> VectorImagePointer;
-  
-  /** The grandient of the speed image */
-  VectorImagePointer m_GradientImage;
-  
-  /** A set of snake parameters */
-  SnakeParameters m_Parameters;
-    
-  /** A list of control points */
-  ControlPointList m_ControlPoints;
-  
-  /** Number of points to sample from the curve */
-  unsigned int m_NumberOfSampledPoints;
-
-  /** A list of sampled points */
-  SampledPointList m_SampledPoints;
-
-  // Flags indicating which part of the pipeline should be refreshed
-  bool m_ControlsModified;
-  bool m_SpeedModified;
-  bool m_ParametersModified;
-  bool m_QuickUpdate;
-    
-  // Internal components of the Update method
-  void UpdateLevelSetFunction();
-  void UpdateContour();
-  void UpdateLevelSet(Fl_Gl_Window *context);
-  void UpdateForces();
-  void Update();
-
-  // A filter used to convert the speed image to a color image to display on the screen
-  typedef itk::UnaryFunctorImageFilter<
-    FloatImageType,DisplayImageType,SpeedColorMap> IntensityFilterType;
-  typedef itk::SmartPointer<IntensityFilterType> IntensityFilterPointer;
-  IntensityFilterPointer m_DisplayMapper;
-
-  // Demo loop object
-  LevelSetPreview2d *m_DemoLoop;
-
-  // Whether the demo loop is currently running
-  bool m_DemoLoopRunning;
-
-  // The color map preset currently in use for speed image rendering
-  ColorMapPreset m_ColorMapPreset;
-};
-
-
-#endif // __SnakeParametersPreviewPipeline_h_
diff --git a/UserInterface/BasicComponents/StatisticsTable.cxx b/UserInterface/BasicComponents/StatisticsTable.cxx
deleted file mode 100644
index 18939ba..0000000
--- a/UserInterface/BasicComponents/StatisticsTable.cxx
+++ /dev/null
@@ -1,220 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: StatisticsTable.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/05/31 19:52:37 $
-  Version:   $Revision: 1.1 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "StatisticsTable.h"
-#include "FL/fl_draw.H"
-using namespace std;
-
-void
-StatisticsTable
-::SetSegmentationStatistics(
-  const SegmentationStatistics &data, const ColorLabelTable &clt)
-{
-  static char buffer[256];
-
-  // Get the data
-  m_Header.clear();
-  m_Body.clear();
-
-  // Get first entry
-  SegmentationStatistics::Entry e = data.GetStats()[0];
-
-  // Set the columns
-  m_Header.push_back("Label");
-  m_Header.push_back("Label Id");
-  m_Header.push_back("# Voxels");
-  m_Header.push_back("Volume (mm^3)");
-  for(size_t i = 0; i < e.gray.size(); i++)
-    {
-    sprintf(buffer, "Mean(%s)", e.gray[i].layer_id.c_str());
-    m_Header.push_back(buffer);
-
-    sprintf(buffer, "S.D.(%s)", e.gray[i].layer_id.c_str());
-    m_Header.push_back(buffer);
-    }
-
-  // Set the body of the table
-  for(size_t i = 0; i < MAX_COLOR_LABELS; i++)
-    {
-    SegmentationStatistics::Entry e = data.GetStats()[i];
-    const ColorLabel &cl = clt.GetColorLabel(i);
-    if(e.count == 0) 
-      continue;
-
-    vector<string> m_Row;
-    m_Row.push_back(cl.GetLabel());
-    
-    sprintf(buffer, "%d", (int) i);
-    m_Row.push_back(buffer);
-
-    sprintf(buffer, "%d", (int) e.count);
-    m_Row.push_back(buffer);
-    
-    sprintf(buffer, "%g", e.volume_mm3);
-    m_Row.push_back(buffer);
-    
-    for(size_t i = 0; i < e.gray.size(); i++)
-      {
-      sprintf(buffer, "%g", e.gray[i].mean);
-      m_Row.push_back(buffer);
-
-      sprintf(buffer, "%g", e.gray[i].sd);
-      m_Row.push_back(buffer);
-      }
-
-    m_Body.push_back(m_Row);
-    }
-
-  // Set the number of rows and columns
-  this->rows(m_Body.size());
-  this->cols(m_Header.size()-1);
-  this->row_header(1);
-  this->col_header(1);
-  this->col_resize(4);
-
-  // Set the column widths (allow for scrollbar)
-  this->col_width_all(100);
-  if(m_Body.size() > 8)
-    this->row_header_width(144);
-  else
-    this->row_header_width(160);
-}
-
-std::string
-StatisticsTable
-::CopySelection()
-{
-  ostringstream oss;
-
-  // Count the number of selected rows
-  size_t nsel = 0;
-  for(size_t r = 0; r < m_Body.size(); r++)
-    if(this->row_selected(r))
-      nsel++;
-
-  // If no selection, include the header too
-  if(nsel == 0)
-    {
-    for(size_t j = 0; j < m_Header.size(); j++)
-      {
-      if(j > 0)
-        oss << "\t";
-      oss << m_Header[j];
-      }
-    oss << endl;
-    }
-
-  // Go through the selected rows
-  for(size_t r = 0; r < m_Body.size(); r++)
-    {
-    if(this->row_selected(r) || nsel == 0)
-      {
-      for(size_t j = 0; j < m_Body[r].size(); j++)
-        {
-        if(j > 0)
-          oss << "\t";
-        oss << m_Body[r][j];
-        }
-      oss << endl;
-      }
-    }
-
-  return oss.str();
-}
-
-
-void
-StatisticsTable
-::draw_cell(TableContext context,  		
-    int R, int C, int X, int Y, int W, int H)
-{
-  string text;
-
-
-  // If data is not initialized, return
-  if(m_Header.size() == 0)
-    return;
-
-  // Actual drawing
-  switch(context)
-    {
-  case CONTEXT_STARTPAGE:
-    fl_font(FL_COURIER, 12);
-    return;
-
-  case CONTEXT_ROW_HEADER:
-    text = m_Body[R][0];
-    fl_push_clip(X, Y, W, H);
-    fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, FL_LIGHT1);
-    fl_pop_clip();
-
-    fl_push_clip(X+3, Y, W-6, H);
-    fl_color(FL_BLACK);
-    fl_draw(text.c_str(), X+3, Y, W-6, H, FL_ALIGN_LEFT);
-    fl_pop_clip();
-    break;
-
-  case CONTEXT_COL_HEADER:
-    text = m_Header[C+1];
-
-    fl_push_clip(X, Y, W, H);
-      {
-      fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, FL_LIGHT1);
-      fl_color(FL_BLACK);
-      fl_draw(text.c_str(), X, Y, W, H, FL_ALIGN_CENTER);
-      }
-    fl_pop_clip();
-    break;
-
-  case CONTEXT_CELL:
-    text = m_Body[R][C+1];
-
-    fl_push_clip(X, Y, W, H);
-    fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, 
-      row_selected(R) ? selection_color() : FL_WHITE);
-    fl_pop_clip();
-
-    fl_push_clip(X+3, Y, W-6, H);
-      {
-      // TEXT
-      fl_color(FL_BLACK);
-      fl_draw(text.c_str(), X+3, Y, W-6, H, FL_ALIGN_RIGHT);
-      }
-    fl_pop_clip();
-    break;
-
-  default:
-    break;
-  }
-}
diff --git a/UserInterface/BasicComponents/StatisticsTable.h b/UserInterface/BasicComponents/StatisticsTable.h
deleted file mode 100644
index 0c39fa6..0000000
--- a/UserInterface/BasicComponents/StatisticsTable.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: StatisticsTable.h,v $
-  Language:  C++
-  Date:      $Date: 2010/05/31 19:52:37 $
-  Version:   $Revision: 1.1 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __StatisticsTable_h_
-#define __StatisticsTable_h_
-
-#include "FL/Fl_Table.H"
-#include "FL/Fl_Table_Row.H"
-#include "SNAPCommon.h"
-#include "SegmentationStatistics.h"
-#include "ColorLabelTable.h"
-
-class StatisticsTable : public Fl_Table_Row
-{
-public:
-  StatisticsTable(int x, int y, int w, int h, const char *l=0) 
-    : Fl_Table_Row(x,y,w,h,l) { end(); }
-
-  ~StatisticsTable() { }
-
-  void SetSegmentationStatistics(
-    const SegmentationStatistics &data, const ColorLabelTable &clt);
-
-  std::string CopySelection();
-
-protected:
-
-  /* Draw table cell */
-  void draw_cell(TableContext context,  		
-    int R=0, int C=0, int X=0, int Y=0, int W=0, int H=0);
-
-  std::vector< std::string > m_Header;
-  std::vector< std::vector< std::string > > m_Body;
-
-};
-
-#endif
-
diff --git a/UserInterface/Common/SNAPAppearanceSettings.cxx b/UserInterface/Common/SNAPAppearanceSettings.cxx
deleted file mode 100644
index 174e4d2..0000000
--- a/UserInterface/Common/SNAPAppearanceSettings.cxx
+++ /dev/null
@@ -1,422 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SNAPAppearanceSettings.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/19 20:28:56 $
-  Version:   $Revision: 1.13 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 of the License, or
-  (at your option) any later version.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-#include "SNAPAppearanceSettings.h"
-#include "Registry.h"
-#include "FL/gl.h"
-
-using namespace std;
-
-// Columns: NORMAL_COLOR, ACTIVE_COLOR, LINE_THICKNESS, DASH_SPACING, 
-//          FONT_SIZE,    VISIBLE,      ALPHA_BLEND,    FEATURE_COUNT
-const int 
-SNAPAppearanceSettings
-::m_Applicable[SNAPAppearanceSettings::ELEMENT_COUNT][SNAPAppearanceSettings::FEATURE_COUNT] = {
-    { 1, 0, 1, 1, 0, 1, 1 },    // Crosshairs
-    { 1, 0, 0, 0, 1, 1, 1 },    // Markers
-    { 1, 1, 1, 1, 0, 0, 1 },    // ROI
-    { 1, 0, 0, 0, 0, 0, 0 },    // Slice Background
-    { 1, 0, 0, 0, 0, 0, 0 },    // 3D Background
-    { 1, 1, 1, 1, 0, 1, 1 },    // Zoom thumbnail
-    { 1, 0, 1, 1, 0, 1, 1 },    // 3D Crosshairs
-    { 1, 0, 1, 1, 0, 1, 1 },    // Thumbnail Crosshairs
-    { 1, 1, 1, 1, 0, 1, 1 },    // 3D Image Box
-    { 1, 1, 1, 1, 0, 1, 1 },    // 3D ROI Box
-    { 1, 1, 1, 1, 0, 1, 1 },    // Paintbrush outline
-    { 1, 0, 1, 0, 1, 1, 1 },    // Rulers
-    { 1, 0, 1, 1, 0, 0, 1 },    // POLY_DRAW_MAIN
-    { 1, 0, 1, 1, 0, 1, 1 },    // POLY_DRAW_CLOSE
-    { 1, 1, 1, 1, 0, 0, 1 }     // POLY_EDIT
-    };
-
-SNAPAppearanceSettings::Element 
-SNAPAppearanceSettings
-::m_DefaultElementSettings[SNAPAppearanceSettings::ELEMENT_COUNT];
-
-void 
-SNAPAppearanceSettings
-::InitializeDefaultSettings()
-{
-  // An element pointer for setting properties
-  Element *elt;
-  
-  // Crosshairs
-  elt = &m_DefaultElementSettings[CROSSHAIRS];
-  elt->NormalColor = Vector3d(0.3, 0.3, 1.0);
-  elt->ActiveColor = Vector3d(0.0, 0.0, 0.0);
-  elt->LineThickness = 1.0;
-  elt->DashSpacing = 1.0;
-  elt->FontSize = 0;
-  elt->Visible = true;
-  elt->AlphaBlending = false;
-
-  // Markers
-  elt = &m_DefaultElementSettings[MARKERS];
-  elt->NormalColor = Vector3d(1.0, 0.75, 0.0);
-  elt->ActiveColor = Vector3d(0.0, 0.0, 0.0);
-  elt->LineThickness = 0.0;
-  elt->DashSpacing = 0.0;
-  elt->FontSize = 16;
-  elt->Visible = true;
-  elt->AlphaBlending = false;
-
-  // ROI
-  elt = &m_DefaultElementSettings[ROI_BOX];
-  elt->NormalColor = Vector3d(1.0, 0.0, 0.2);
-  elt->ActiveColor = Vector3d(1.0, 1.0, 0.2);
-  elt->LineThickness = 1.0;
-  elt->DashSpacing = 3.0;
-  elt->FontSize = 0;
-  elt->Visible = true;
-  elt->AlphaBlending = false;
-
-  // Slice background
-  elt = &m_DefaultElementSettings[BACKGROUND_3D];
-  elt->NormalColor = Vector3d(0.0, 0.0, 0.0);
-  elt->ActiveColor = Vector3d(0.0, 0.0, 0.0);
-  elt->LineThickness = 0.0;
-  elt->DashSpacing = 0.0;
-  elt->FontSize = 0;
-  elt->Visible = true;
-  elt->AlphaBlending = false;
-
-  // 3D Window background
-  elt = &m_DefaultElementSettings[BACKGROUND_3D];
-  elt->NormalColor = Vector3d(0.0, 0.0, 0.0);
-  elt->ActiveColor = Vector3d(0.0, 0.0, 0.0);
-  elt->LineThickness = 0.0;
-  elt->DashSpacing = 0.0;
-  elt->FontSize = 0;
-  elt->Visible = true;
-  elt->AlphaBlending = false;
-
-  // Zoom thumbail
-  elt = &m_DefaultElementSettings[ZOOM_THUMBNAIL];
-  elt->NormalColor = Vector3d(1.0, 1.0, 0.0);
-  elt->ActiveColor = Vector3d(1.0, 1.0, 1.0);
-  elt->LineThickness = 1.0;
-  elt->DashSpacing = 0.0;
-  elt->FontSize = 0;
-  elt->Visible = true;
-  elt->AlphaBlending = false;
-
-  // 3D crosshairs
-  elt = &m_DefaultElementSettings[CROSSHAIRS_3D];
-  elt->NormalColor = Vector3d(0.3, 0.3, 1.0);
-  elt->ActiveColor = Vector3d(0.0, 0.0, 0.0);
-  elt->LineThickness = 1.0;
-  elt->DashSpacing = 1.0;
-  elt->FontSize = 0;
-  elt->Visible = true;
-  elt->AlphaBlending = true;
-
-  // Thumbnail crosshairs
-  elt = &m_DefaultElementSettings[CROSSHAIRS_THUMB];
-  elt->NormalColor = Vector3d(0.3, 0.3, 1.0);
-  elt->ActiveColor = Vector3d(0.0, 0.0, 0.0);
-  elt->LineThickness = 1.0;
-  elt->DashSpacing = 1.0;
-  elt->FontSize = 0;
-  elt->Visible = true;
-  elt->AlphaBlending = false;
-
-  // Thumbnail crosshairs
-  elt = &m_DefaultElementSettings[IMAGE_BOX_3D];
-  elt->NormalColor = Vector3d(0.2, 0.2, 0.2);
-  elt->ActiveColor = Vector3d(0.4, 0.4, 0.4);
-  elt->LineThickness = 1.0;
-  elt->DashSpacing = 1.0;
-  elt->FontSize = 0;
-  elt->Visible = true;
-  elt->AlphaBlending = false;
-
-  // Thumbnail crosshairs
-  elt = &m_DefaultElementSettings[ROI_BOX_3D];
-  elt->NormalColor = Vector3d(1.0, 0.0, 0.2);
-  elt->ActiveColor = Vector3d(1.0, 1.0, 0.2);
-  elt->LineThickness = 1.0;
-  elt->DashSpacing = 3.0;
-  elt->FontSize = 0;
-  elt->Visible = true;
-  elt->AlphaBlending = false;
-   
-  // Paintbrush outline
-  elt = &m_DefaultElementSettings[PAINTBRUSH_OUTLINE];
-  elt->NormalColor = Vector3d(1.0, 0.0, 0.2);
-  elt->ActiveColor = Vector3d(1.0, 1.0, 0.2);
-  elt->LineThickness = 1.0;
-  elt->DashSpacing = 1.0;
-  elt->FontSize = 0;
-  elt->Visible = true;
-  elt->AlphaBlending = false;
-
-  // Markers
-  elt = &m_DefaultElementSettings[RULER];
-  elt->NormalColor = Vector3d(0.3, 1.0, 0.0);
-  elt->ActiveColor = Vector3d(0.0, 0.0, 0.0);
-  elt->LineThickness = 1.0;
-  elt->DashSpacing = 0.0;
-  elt->FontSize = 12;
-  elt->Visible = true;
-  elt->AlphaBlending = true;
-
-  // Polygon outline (drawing)
-  elt = &m_DefaultElementSettings[POLY_DRAW_MAIN];
-  elt->NormalColor = Vector3d(1.0, 0.0, 0.5);
-  elt->LineThickness = 2.0;
-  elt->Visible = true;
-  elt->AlphaBlending = true;
-
-  // Polygon outline (drawing)
-  elt = &m_DefaultElementSettings[POLY_DRAW_CLOSE];
-  elt->NormalColor = Vector3d(1.0, 0.0, 0.5);
-  elt->LineThickness = 2.0;
-  elt->Visible = true;
-  elt->DashSpacing = 1.0;
-  elt->AlphaBlending = true;
-
-  // Polygon outline (editing)
-  elt = &m_DefaultElementSettings[POLY_EDIT];
-  elt->NormalColor = Vector3d(1.0, 0.0, 0.0);
-  elt->ActiveColor = Vector3d(0.0, 1.0, 0.0);
-  elt->LineThickness = 2.0;
-  elt->Visible = true;
-  elt->AlphaBlending = true;
-}
-
-const char *
-SNAPAppearanceSettings
-::m_ElementNames[SNAPAppearanceSettings::ELEMENT_COUNT] = 
-  { "CROSSHAIRS", "MARKERS", "ROI_BOX", "BACKGROUND_2D", "BACKGROUND_3D", 
-    "ZOOM_THUMBNAIL", "CROSSHAIRS_3D", "CROSSHAIRS_THUMB", "IMAGE_BOX_3D",
-    "ROI_BOX_3D", "RULER", "PAINTBRUSH_OUTLINE", 
-    "POLY_DRAW_MAIN", "POLY_DRAW_CLOSE", "POLY_EDIT"};
-
-SNAPAppearanceSettings
-::SNAPAppearanceSettings()
-{
-  // Initialize the default settings
-  InitializeDefaultSettings();
-
-  // Set the common flags
-  m_FlagLinkedZoomByDefault = true;
-  m_FlagMultisessionZoomByDefault = true;
-  m_FlagMultisessionPanByDefault = true;
-  m_FlagFloatingPointWarningByDefault = true;
-  m_FlagEnableHiddenFeaturesByDefault = false;
-  m_FlagEnableAutoCheckForUpdateByDefault = -1;
-  m_ZoomThumbnailMaximumSize = 160;
-  m_ZoomThumbnailSizeInPercent = 30.0;
-  m_FlagDisplayZoomThumbnail = true;
-  m_GreyInterpolationMode = NEAREST;
-
-  m_SliceLayout = LAYOUT_ASC;
-  m_FlagLayoutPatientAnteriorShownLeft = true;
-  m_FlagLayoutPatientRightShownLeft = true;
-  m_FlagAutoPan = false;
-
-  m_EnumMapInterpolationMode.AddPair(NEAREST,"NearestNeighbor");
-  m_EnumMapInterpolationMode.AddPair(LINEAR,"Linear");
-
-  m_EnumMapSliceLayout.AddPair(LAYOUT_ASC,"ASC");
-  m_EnumMapSliceLayout.AddPair(LAYOUT_ACS,"ACS");
-  m_EnumMapSliceLayout.AddPair(LAYOUT_SAC,"SAC");
-  m_EnumMapSliceLayout.AddPair(LAYOUT_SCA,"SCA");
-  m_EnumMapSliceLayout.AddPair(LAYOUT_CAS,"CAS");
-  m_EnumMapSliceLayout.AddPair(LAYOUT_CSA,"CSA");
-  
-  // Set the UI elements to their default values  
-  for(unsigned int iElement = 0; iElement < ELEMENT_COUNT; iElement++)
-    m_Elements[iElement] = m_DefaultElementSettings[iElement];
-
-  // Initial visibility is true
-  m_OverallVisibility = true;
-
-}
-
-void
-SNAPAppearanceSettings
-::LoadFromRegistry(Registry &r)
-{
-  // Load the flags and settings
-  m_FlagDisplayZoomThumbnail =
-    r["FlagDisplayZoomThumbnail"][m_FlagDisplayZoomThumbnail];
-
-  m_FlagLinkedZoomByDefault = 
-    r["FlagLinkedZoomByDefault"][m_FlagLinkedZoomByDefault];
-
-  m_FlagMultisessionZoomByDefault = 
-    r["FlagMultisessionZoomByDefault"][m_FlagMultisessionZoomByDefault];
-
-  m_FlagMultisessionPanByDefault = 
-    r["FlagMultisessionPanByDefault"][m_FlagMultisessionPanByDefault];
-
-  m_FlagFloatingPointWarningByDefault = 
-    r["FlagFloatingPointWarningByDefault"][m_FlagFloatingPointWarningByDefault];
-
-  m_FlagEnableHiddenFeaturesByDefault = 
-    r["FlagEnableHiddenFeaturesByDefault"][m_FlagEnableHiddenFeaturesByDefault];
-
-  m_FlagEnableAutoCheckForUpdateByDefault =
-    r["FlagEnableAutoCheckForUpdateByDefault"][m_FlagEnableAutoCheckForUpdateByDefault];
-
-  m_FlagAutoPan =
-    r["FlagAutoPan"][m_FlagAutoPan];
-
-  m_ZoomThumbnailSizeInPercent = 
-    r["ZoomThumbnailSizeInPercent"][m_ZoomThumbnailSizeInPercent];
-
-  m_ZoomThumbnailMaximumSize = 
-    r["ZoomThumbnailMaximumSize"][m_ZoomThumbnailMaximumSize];
-
-  m_GreyInterpolationMode = 
-    r["GreyImageInterpolationMode"].GetEnum(m_EnumMapInterpolationMode, NEAREST);
-
-  // Overall visibility is not saved or loaded
-
-  // Read slice layout information
-  m_SliceLayout = 
-    r["SliceLayout"].GetEnum(m_EnumMapSliceLayout, LAYOUT_ASC);
-  m_FlagLayoutPatientAnteriorShownLeft = r["PatientAnteriorShownLeft"][true];
-  m_FlagLayoutPatientRightShownLeft = r["PatientRightShownLeft"][true];
-
-  // Load the user interface elements
-  for(unsigned int iElement = 0; iElement < ELEMENT_COUNT; iElement++)
-    {
-    // Create a folder to hold the element
-    Registry& f = r.Folder( 
-      r.Key("UserInterfaceElement[%s]", m_ElementNames[iElement]) );
-
-    // Get the default element
-    const Element &def = m_DefaultElementSettings[iElement];
-    Element &elt = m_Elements[iElement];
-    
-    // Store the element in the folder
-    elt.NormalColor = f["NormalColor"][def.NormalColor];
-    elt.ActiveColor = f["ActiveColor"][def.ActiveColor];
-    elt.LineThickness = f["LineThickness"][def.LineThickness];
-    elt.DashSpacing = f["DashSpacing"][def.DashSpacing];
-    elt.FontSize = f["FontSize"][def.FontSize];
-    elt.AlphaBlending = f["AlphaBlending"][def.AlphaBlending];
-    elt.Visible = f["Visible"][def.Visible];
-    }
-}
-
-void
-SNAPAppearanceSettings
-::SaveToRegistry(Registry &r)
-{
-  // Save the flags and settings
-  r["FlagDisplayZoomThumbnail"] << m_FlagDisplayZoomThumbnail;
-  r["FlagLinkedZoomByDefault"] << m_FlagLinkedZoomByDefault;
-  r["FlagMultisessionZoomByDefault"] << m_FlagMultisessionZoomByDefault;
-  r["FlagMultisessionPanByDefault"] << m_FlagMultisessionPanByDefault;
-  r["FlagFloatingPointWarningByDefault"] << m_FlagFloatingPointWarningByDefault;
-  r["FlagEnableHiddenFeaturesByDefault"] << m_FlagEnableHiddenFeaturesByDefault;
-  r["FlagEnableAutoCheckForUpdateByDefault"] << m_FlagEnableAutoCheckForUpdateByDefault;
-  r["FlagAutoPan"] << m_FlagAutoPan;
-  r["ZoomThumbnailSizeInPercent"] << m_ZoomThumbnailSizeInPercent;
-  r["ZoomThumbnailMaximumSize"] << m_ZoomThumbnailMaximumSize;
-  r["GreyImageInterpolationMode"].PutEnum(m_EnumMapInterpolationMode, m_GreyInterpolationMode);
-
-  // Overall visibility is not saved or loaded
-
-  // Write slice layout information
-  r["SliceLayout"].PutEnum(m_EnumMapSliceLayout, m_SliceLayout);
-  r["PatientAnteriorShownLeft"] << m_FlagLayoutPatientAnteriorShownLeft;
-  r["PatientRightShownLeft"] << m_FlagLayoutPatientRightShownLeft;
-  
-
-
-  // Save each of the screen elements
-  for(unsigned int iElement = 0; iElement < ELEMENT_COUNT; iElement++)
-    {
-    // Create a folder to hold the element
-    Registry& f = r.Folder( 
-      r.Key("UserInterfaceElement[%s]", m_ElementNames[iElement]) );
-
-    // Get the default element
-    Element &elt = m_Elements[iElement];
-    
-    // Store the element in the folder
-    f["NormalColor"] << elt.NormalColor;
-    f["ActiveColor"] << elt.ActiveColor;
-    f["LineThickness"] << elt.LineThickness;
-    f["DashSpacing"] << elt.DashSpacing;
-    f["FontSize"] << elt.FontSize;
-    f["AlphaBlending"] << elt.AlphaBlending;
-    f["Visible"] << elt.Visible;
-    }
-}
-
-void 
-SNAPAppearanceSettings
-::ApplyUIElementLineSettings(const Element &elt, bool applyThickness, bool applyStipple)
-{
-  // Apply the thickness properties
-  if(applyThickness)
-    {
-    // Choose whether to use blending or not
-    if( elt.AlphaBlending )
-      {
-      glEnable(GL_BLEND);
-      glEnable(GL_LINE_SMOOTH);
-      glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
-      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-      }
-    glLineWidth( elt.LineThickness );
-    }
-  if(applyStipple && elt.DashSpacing != 0)
-    {
-    // Set the line thickness and stipple
-    glEnable(GL_LINE_STIPPLE);
-    glLineStipple( static_cast<GLint>(elt.DashSpacing),
-                   0x9999 ); // 0011 0011 0011 0011  // 1001 1001 1001 1001
-    }
-}
-
-void SNAPAppearanceSettings
-::GetAnatomyToDisplayTransforms(string &rai1, string &rai2, string &rai3)
-{
-  unsigned int order[6][3] = 
-    {{0,1,2},{0,2,1},{1,0,2},{1,2,0},{2,0,1},{2,1,0}};
-
-  // Start with stock orientations
-  string axes[3] = {string("RPS"),string("AIL"),string("RIP")};
-
-  // Switch the configurable directions
-  if(!m_FlagLayoutPatientRightShownLeft)
-    {
-    axes[0][0] = axes[2][0] = 'L';
-    }
-  if(!m_FlagLayoutPatientAnteriorShownLeft)
-    {
-    axes[1][0] = 'P';
-    }
-
-  // Convert layout index to integer
-  size_t i = (size_t) m_SliceLayout;
-
-  // Set the axes
-  rai1 = axes[order[i][0]];
-  rai2 = axes[order[i][1]];
-  rai3 = axes[order[i][2]];
-}
-
diff --git a/UserInterface/Common/SNAPAppearanceSettings.h b/UserInterface/Common/SNAPAppearanceSettings.h
deleted file mode 100644
index 0bcc6d6..0000000
--- a/UserInterface/Common/SNAPAppearanceSettings.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SNAPAppearanceSettings.h,v $
-  Language:  C++
-  Date:      $Date: 2010/10/19 20:28:56 $
-  Version:   $Revision: 1.12 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SNAPAppearanceSettings_h_
-#define __SNAPAppearanceSettings_h_
-
-#if defined(_MSC_VER)
-#pragma warning ( disable : 4786 )
-#endif
-
-// Include the common items from the logic part of SNAP
-#include "SNAPCommonUI.h"
-#include "Registry.h"
-#include <string>
-
-/**
- * \class SNAPAppearanceSettings
- * \brief User interface settings that the user can configure
- */
-class SNAPAppearanceSettings
-{
-public:
-  /**
-   * A structure that describes the appearance of a screen element
-   */
-  struct Element
-  {
-    Vector3d NormalColor;
-    Vector3d ActiveColor;
-    double LineThickness;
-    double DashSpacing;
-    int FontSize;
-    bool Visible, AlphaBlending;
-  };
-
-  /** An enumeration of available screen elements */
-  enum UIElements
-    {
-    CROSSHAIRS = 0, MARKERS, ROI_BOX,
-    BACKGROUND_2D, BACKGROUND_3D,
-    ZOOM_THUMBNAIL, CROSSHAIRS_3D, CROSSHAIRS_THUMB,
-    IMAGE_BOX_3D, ROI_BOX_3D, PAINTBRUSH_OUTLINE, RULER, 
-    POLY_DRAW_MAIN, POLY_DRAW_CLOSE, POLY_EDIT,
-    ELEMENT_COUNT
-    };
-
-  /** An enumeration of the fields that an element may possess */
-  enum UIElementFeatures
-    {
-    NORMAL_COLOR = 0, ACTIVE_COLOR, LINE_THICKNESS, DASH_SPACING,
-    FONT_SIZE, VISIBLE, ALPHA_BLEND, FEATURE_COUNT
-    };
-
-  /** Enumeration of interpolation modes */
-  enum UIGreyInterpolation
-    {
-    NEAREST = 0, LINEAR
-    };
-
-  /** Enumeration of 2D display layouts */
-  enum UISliceLayout
-    {
-    LAYOUT_ASC = 0, LAYOUT_ACS, LAYOUT_SAC, LAYOUT_SCA, LAYOUT_CAS, LAYOUT_CSA, LAYOUT_COUNT
-    };
-
-  SNAPAppearanceSettings();
-  virtual ~SNAPAppearanceSettings() {}
-
-  void LoadFromRegistry(Registry &registry);
-  void SaveToRegistry(Registry &registry);
-
-  // Access a user interface element
-  Element &GetUIElement(unsigned int iElement)
-    { return m_Elements[iElement]; }
-
-  // Set a user interface element
-  void SetUIElement(unsigned int iElement, const Element &value)
-    { m_Elements[iElement] = value; }
-
-  // Check whether the feature is applicable to an element
-  static bool IsFeatureApplicable(unsigned int iElement, unsigned int iFeature)
-    { return m_Applicable[iElement][iFeature] != 0; }
-
-  // Apply the GL settings associated with an appearance element
-  static void ApplyUIElementLineSettings(const Element &elt,
-    bool applyThickness = true, bool applyStipple = true);
-
-  irisGetMacro(FlagDisplayZoomThumbnail, bool);
-  irisSetMacro(FlagDisplayZoomThumbnail, bool);
-
-  irisGetMacro(FlagLinkedZoomByDefault, bool);
-  irisSetMacro(FlagLinkedZoomByDefault, bool);
-
-  irisGetMacro(FlagMultisessionZoomByDefault, bool);
-  irisSetMacro(FlagMultisessionZoomByDefault, bool);
-
-  irisGetMacro(FlagMultisessionPanByDefault, bool);
-  irisSetMacro(FlagMultisessionPanByDefault, bool);
-
-  irisGetMacro(FlagFloatingPointWarningByDefault, bool);
-  irisSetMacro(FlagFloatingPointWarningByDefault, bool);
-
-  irisGetMacro(FlagEnableAutoCheckForUpdateByDefault, int);
-  irisSetMacro(FlagEnableAutoCheckForUpdateByDefault, int);
-
-  irisGetMacro(FlagEnableHiddenFeaturesByDefault, bool);
-  irisSetMacro(FlagEnableHiddenFeaturesByDefault, bool);
-
-  irisGetMacro(ZoomThumbnailSizeInPercent, double);
-  irisSetMacro(ZoomThumbnailSizeInPercent, double);
-
-  irisGetMacro(ZoomThumbnailMaximumSize, int);
-  irisSetMacro(ZoomThumbnailMaximumSize, int);
-
-  irisGetMacro(GreyInterpolationMode, UIGreyInterpolation);
-  irisSetMacro(GreyInterpolationMode, UIGreyInterpolation);
-
-  irisGetMacro(FlagLayoutPatientAnteriorShownLeft, bool);
-  irisSetMacro(FlagLayoutPatientAnteriorShownLeft, bool);
-
-  irisGetMacro(FlagLayoutPatientRightShownLeft, bool);
-  irisSetMacro(FlagLayoutPatientRightShownLeft, bool);
-
-  irisGetMacro(FlagAutoPan, bool);
-  irisSetMacro(FlagAutoPan, bool);
-
-  irisGetMacro(SliceLayout, UISliceLayout);
-  irisSetMacro(SliceLayout, UISliceLayout);
-
-  irisGetMacro(OverallVisibility, bool);
-  irisSetMacro(OverallVisibility, bool);
-
-  /** 
-   * This method uses SliceLayout, FlagLayoutPatientAnteriorShownLeft and
-   * FlagLayoutPatientRightShownLeft to generate RAI codes for the three
-   * display views. 
-   * Use in conjunction with IRISApplication::SetDisplayToAnatomyRAI
-   */
-  void GetAnatomyToDisplayTransforms(std::string &rai1, std::string &rai2, std::string &rai3);
-
-private:
-  // Global settings
-  bool m_FlagDisplayZoomThumbnail;
-  bool m_FlagLinkedZoomByDefault;
-  bool m_FlagMultisessionZoomByDefault;
-  bool m_FlagMultisessionPanByDefault;
-  bool m_FlagFloatingPointWarningByDefault;
-  bool m_FlagEnableHiddenFeaturesByDefault;
-  bool m_FlagAutoPan;
-  int m_FlagEnableAutoCheckForUpdateByDefault;
-  double m_ZoomThumbnailSizeInPercent;
-  int m_ZoomThumbnailMaximumSize;
-  bool m_OverallVisibility;
-
-  // Interpolation used for rendering slices (for now, linear or n-nbr)
-  UIGreyInterpolation m_GreyInterpolationMode;
-
-  /** This is needed to read enum of interpolation modes from registry */
-  RegistryEnumMap<UIGreyInterpolation> m_EnumMapInterpolationMode;
-
-  // Current 2D view layout
-  UISliceLayout m_SliceLayout;
-
-  // View layout additional flags
-  bool m_FlagLayoutPatientAnteriorShownLeft;
-  bool m_FlagLayoutPatientRightShownLeft;
-
-  // This is needed to read 2D view layout enums
-  RegistryEnumMap<UISliceLayout> m_EnumMapSliceLayout;
-
-  /** An array of user interface elements */
-  Element m_Elements[ELEMENT_COUNT];
-    
-  /** A list of flags that indicate for each element, whether each feature is 
-   * applicable or not */
-  static const int m_Applicable[ELEMENT_COUNT][FEATURE_COUNT];
-
-  /** Names of the appearance elements */
-  static const char *m_ElementNames[];
-
-  /** The set of default values for each element */
-  static Element m_DefaultElementSettings[ELEMENT_COUNT];
-
-  /** Initialize the default settings */
-  static void InitializeDefaultSettings();
-};
-
-
-#endif // __SNAPAppearanceSettings_h_
diff --git a/UserInterface/Common/SNAPCommonUI.h b/UserInterface/Common/SNAPCommonUI.h
deleted file mode 100644
index b85ac82..0000000
--- a/UserInterface/Common/SNAPCommonUI.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SNAPCommonUI.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:16 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SNAPCommonIO_h_
-#define __SNAPCommonIO_h_
-
-/** 
- * This is an include file that should be inserted into all SNAP UI 
- * header files 
- **/
-
-// Include the common items from the logic part of SNAP
-#include "SNAPCommon.h"
-
-// Enable cygwin support
-#if defined(_WIN32)
-#include <itkWindows.h>
-#endif
-
-#endif // __SNAPCommonIO_h_
diff --git a/UserInterface/ImageIOWizard/Artwork/dollAIR.gif b/UserInterface/ImageIOWizard/Artwork/dollAIR.gif
deleted file mode 100644
index e767030..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/dollAIR.gif and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/dollARI.gif b/UserInterface/ImageIOWizard/Artwork/dollARI.gif
deleted file mode 100644
index 14996eb..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/dollARI.gif and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/dollIAR.gif b/UserInterface/ImageIOWizard/Artwork/dollIAR.gif
deleted file mode 100644
index 454fefe..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/dollIAR.gif and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/dollIRA.gif b/UserInterface/ImageIOWizard/Artwork/dollIRA.gif
deleted file mode 100644
index a64dd30..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/dollIRA.gif and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/dollInvalid.gif b/UserInterface/ImageIOWizard/Artwork/dollInvalid.gif
deleted file mode 100644
index 2a1af8e..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/dollInvalid.gif and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/dollRAI.gif b/UserInterface/ImageIOWizard/Artwork/dollRAI.gif
deleted file mode 100644
index b21e8e7..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/dollRAI.gif and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/dollRIA.gif b/UserInterface/ImageIOWizard/Artwork/dollRIA.gif
deleted file mode 100644
index 7236823..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/dollRIA.gif and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/x01.png b/UserInterface/ImageIOWizard/Artwork/x01.png
deleted file mode 100644
index e1f2f59..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/x01.png and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/x02.png b/UserInterface/ImageIOWizard/Artwork/x02.png
deleted file mode 100644
index b96485b..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/x02.png and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/y01.png b/UserInterface/ImageIOWizard/Artwork/y01.png
deleted file mode 100644
index b3ad9e3..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/y01.png and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/y02.png b/UserInterface/ImageIOWizard/Artwork/y02.png
deleted file mode 100644
index 949f4a1..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/y02.png and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/z01.png b/UserInterface/ImageIOWizard/Artwork/z01.png
deleted file mode 100644
index 3e03aaf..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/z01.png and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/Artwork/z02.png b/UserInterface/ImageIOWizard/Artwork/z02.png
deleted file mode 100644
index 9b26987..0000000
Binary files a/UserInterface/ImageIOWizard/Artwork/z02.png and /dev/null differ
diff --git a/UserInterface/ImageIOWizard/ImageIOWizard.fl b/UserInterface/ImageIOWizard/ImageIOWizard.fl
deleted file mode 100644
index 63ec5ab..0000000
--- a/UserInterface/ImageIOWizard/ImageIOWizard.fl
+++ /dev/null
@@ -1,421 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0109
-header_name {.h} 
-code_name {.cxx}
-class ImageIOWizard {open : {private ImageIOWizardBase}
-} {
-  Function {MakeWindow()} {open return_type {virtual void}
-  } {
-    Fl_Window m_WinInput {
-      label {ITK-SNAP Image Input Wizard} open
-      xywh {522 175 470 330} type Double
-      code0 {\#include "ImageIOWizardBase.h"} modal visible
-    } {
-      Fl_Wizard m_WizInput {open
-        xywh {-5 -10 505 395}
-      } {
-        Fl_Group m_PageFile {
-          label {File Selection}
-          xywh {0 0 470 330} box PLASTIC_DOWN_BOX labelfont 2 labelsize 10 hide
-        } {
-          Fl_Group m_InFilePage {
-            label {Select a file that contains an image:}
-            xywh {10 15 370 40} labeltype EMBOSSED_LABEL align 20
-          } {}
-          Fl_Input m_InFilePageBrowser {
-            label {Image file name:}
-            callback {this->OnFilePageFileInputChange();}
-            tooltip {Enter the filename of the image you want to load, or select one using the 'Browse' and 'History' buttons} xywh {30 100 405 25} labelsize 12 align 5 when 1 textsize 12
-          }
-          Fl_Button {} {
-            label {&Browse...}
-            callback {this->OnFilePageBrowse();}
-            xywh {265 130 80 25} box PLASTIC_UP_BOX shortcut 0x80062 labelsize 12
-          }
-          Fl_Menu_Button m_InFilePageHistory {
-            label History
-            callback {this->OnFilePageFileHistoryChange();}
-            tooltip {Select one of the recently loaded images} xywh {355 130 80 25} box PLASTIC_UP_BOX selection_color 181 labelsize 12 align 20 textsize 12
-          } {}
-          Fl_Choice m_InFilePageFormat {
-            label {Image file format:}
-            callback {this->OnFilePageFileFormatChange();}
-            tooltip {Use this dropdown box to select an image format if one is not selected for you automatically. Normally, SNAP will figure out the file format once you select an image file using the 'Browse' button.} xywh {30 190 210 25} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-          } {
-            MenuItem {} {
-              label {Select a format...}
-              xywh {10 10 100 20} labelsize 12 hide
-            }
-          }
-          Fl_Group {} {
-            label {Button Group} open
-            xywh {190 285 280 45} labeltype NO_LABEL
-          } {
-            Fl_Button m_BtnFilePageNext {
-              label {&Next  >}
-              callback {this->OnFilePageNext();}
-              xywh {290 295 80 25} box PLASTIC_UP_BOX shortcut 0x8006e color 180 labelfont 1 labelsize 12 deactivate
-            }
-            Fl_Button {} {
-              label {< Back}
-              xywh {200 295 80 25} box PLASTIC_UP_BOX color 180 labelsize 12 deactivate
-            }
-            Fl_Button {} {
-              label Cancel
-              callback {this->OnCancel();}
-              xywh {380 295 80 25} box PLASTIC_UP_BOX shortcut 0xff1b color 180 labelsize 12
-            }
-          }
-        }
-        Fl_Group m_PageHeader {
-          label {Header Info}
-          xywh {0 0 470 330} box PLASTIC_DOWN_BOX labelfont 2 labelsize 10 hide deactivate
-        } {
-          Fl_Group {} {
-            label {Supply missing header information:} open
-            xywh {10 15 370 40} labeltype EMBOSSED_LABEL align 20
-          } {}
-          Fl_Group {} {
-            label {Header size:}
-            xywh {30 60 360 35} labelsize 12 align 20
-          } {
-            Fl_Value_Input m_InHeaderPageHeaderSize {
-              label bytes
-              callback {this->OnHeaderPageInputChange();}
-              xywh {185 65 70 25} labelsize 12 align 8 textsize 12
-            }
-          }
-          Fl_Group {} {
-            label {Image dimensions:} open
-            xywh {30 100 405 35} labelsize 12 align 20
-          } {
-            Fl_Value_Input m_InHeaderPageDimX {
-              label {X:}
-              callback {this->OnHeaderPageInputChange();}
-              tooltip {The dimension of the image volume, in voxels} xywh {185 105 70 25} labelsize 12 textsize 12
-            }
-            Fl_Value_Input m_InHeaderPageDimY {
-              label {Y:}
-              callback {this->OnHeaderPageInputChange();}
-              tooltip {The dimension of the image volume, in voxels} xywh {275 105 70 25} labelsize 12 textsize 12
-            }
-            Fl_Value_Input m_InHeaderPageDimZ {
-              label {Z:}
-              callback {this->OnHeaderPageInputChange();}
-              tooltip {The dimension of the image volume, in voxels} xywh {365 105 70 25} labelsize 12 textsize 12
-            }
-          }
-          Fl_Group {} {
-            label {Voxel spacing:} open
-            xywh {30 140 405 35} labelsize 12 align 20
-          } {
-            Fl_Value_Input m_InHeaderPageSpacingX {
-              label {X:}
-              callback {this->OnHeaderPageInputChange();}
-              tooltip {Voxel size in each dimension (in mm)} xywh {185 145 70 25} labelsize 12 maximum 100 step 0.01 value 1 textsize 12
-            }
-            Fl_Value_Input m_InHeaderPageSpacingY {
-              label {Y:}
-              callback {this->OnHeaderPageInputChange();}
-              tooltip {Voxel size in each dimension (in mm)} xywh {275 145 70 25} labelsize 12 maximum 100 step 0.01 value 1 textsize 12
-            }
-            Fl_Value_Input m_InHeaderPageSpacingZ {
-              label {Z:}
-              callback {this->OnHeaderPageInputChange();}
-              tooltip {Voxel size in each dimension (in mm)} xywh {365 145 70 25} labelsize 12 maximum 100 step 0.01 value 1 textsize 12
-            }
-          }
-          Fl_Group {} {
-            label {Voxel representation:} open
-            xywh {30 180 360 35} labelsize 12 align 20
-          } {
-            Fl_Choice m_InHeaderPageVoxelType {
-              callback {this->OnHeaderPageInputChange();} open
-              tooltip {Data type of the voxels} xywh {185 185 195 25} down_box BORDER_BOX labelsize 12 align 20 textsize 12
-            } {
-              MenuItem {} {
-                label {8 bit, unsigned (uchar)}
-                xywh {5 5 100 20} labelsize 12
-              }
-              MenuItem {} {
-                label {8 bit, signed (char)}
-                xywh {15 15 100 20} labelsize 12
-              }
-              MenuItem {} {
-                label {16 bit, unsigned (ushort)}
-                xywh {25 25 100 20} labelsize 12
-              }
-              MenuItem {} {
-                label {16 bit, signed (short)}
-                xywh {35 35 100 20} labelsize 12
-              }
-              MenuItem {} {
-                label {32 bit, unsigned (uint)}
-                xywh {45 45 100 20} labelsize 12
-              }
-              MenuItem {} {
-                label {32 bit, signed (int)}
-                xywh {55 55 100 20} labelsize 12
-              }
-              MenuItem {} {
-                label {32 bit, floating point (float)}
-                xywh {65 65 100 20} labelsize 12
-              }
-              MenuItem {} {
-                label {64 bit, floating point (double)}
-                xywh {75 75 100 20} labelsize 12
-              }
-            }
-          }
-          Fl_Group {} {
-            label {Byte alignment:} open
-            xywh {30 220 360 35} labelsize 12 align 20
-          } {
-            Fl_Choice m_InHeaderPageByteAlign {
-              callback {this->OnHeaderPageInputChange();} open
-              tooltip {Format in which multi-byte values are stored in the image} xywh {185 225 195 25} down_box BORDER_BOX labelsize 12 align 20 textsize 12
-            } {
-              MenuItem {} {
-                label {Big Endian (UNIX, Mac)}
-                xywh {15 15 100 20} labelsize 12
-              }
-              MenuItem {} {
-                label {Little Endian (Intel, AMD)}
-                xywh {25 25 100 20} labelsize 12
-              }
-            }
-          }
-          Fl_Group {} {
-            label {Button Group} open
-            xywh {190 285 280 45} labeltype NO_LABEL
-          } {
-            Fl_Button m_BtnHeaderPageNext {
-              label {&Next  >}
-              callback {this->OnHeaderPageNext();}
-              xywh {290 295 80 25} box PLASTIC_UP_BOX shortcut 0x8006e color 180 labelfont 1 labelsize 12
-            }
-            Fl_Button m_BtnHeaderPageBack {
-              label {< Back}
-              callback {this->OnHeaderPageBack();}
-              xywh {200 295 80 25} box PLASTIC_UP_BOX color 180 labelsize 12
-            }
-            Fl_Button {} {
-              label Cancel
-              callback {this->OnCancel();}
-              xywh {380 295 80 25} box PLASTIC_UP_BOX shortcut 0xff1b color 180 labelsize 12
-            }
-          }
-        }
-        Fl_Group m_PageDICOM {
-          xywh {0 0 480 340} hide deactivate
-        } {
-          Fl_Group {} {
-            label {DICOM Input Options:} open
-            xywh {10 5 370 40} labeltype EMBOSSED_LABEL align 20
-          } {}
-          Fl_Group {} {
-            label {Button Group} open
-            xywh {180 270 280 45} labeltype NO_LABEL
-          } {
-            Fl_Button m_BtnDICOMPageNext {
-              label {&Next  >}
-              callback {this->OnDICOMPageNext();}
-              xywh {280 280 80 25} box PLASTIC_UP_BOX shortcut 0x8006e color 180 labelfont 1 labelsize 12
-            }
-            Fl_Button m_BtnDICOMPageBack {
-              label {< Back}
-              callback {this->OnDICOMPageBack();}
-              xywh {190 280 80 25} box PLASTIC_UP_BOX color 180 labelsize 12
-            }
-            Fl_Button {} {
-              label Cancel
-              callback {this->OnCancel();}
-              xywh {370 280 80 25} box PLASTIC_UP_BOX shortcut 0xff1b color 180 labelsize 12
-            }
-          }
-          Fl_Check_Button {} {
-            label { Load by sequence (all slices with the sequence id below)}
-            xywh {25 50 405 25} down_box DOWN_BOX value 1 labelsize 12
-          }
-          Fl_Check_Button {} {
-            label { Load by filename order}
-            xywh {25 125 405 25} down_box DOWN_BOX labelsize 12 deactivate
-          }
-          Fl_Check_Button {} {
-            label { Load all slices in the directory}
-            xywh {25 200 405 25} down_box DOWN_BOX labelsize 12 deactivate
-          }
-          Fl_Choice m_InDICOMPageSequenceId {
-            label {Sequence id:} open
-            xywh {165 80 270 25} down_box BORDER_BOX labelsize 12 textsize 12
-          } {}
-          Fl_Value_Input {} {
-            label {First Slice:}
-            xywh {230 160 65 25} labelsize 12 maximum 10000 step 1 value 1 textsize 12 deactivate
-          }
-          Fl_Value_Input {} {
-            label {Last Slice:}
-            xywh {370 160 65 25} labelsize 12 maximum 10000 step 1 value 1 textsize 12 deactivate
-          }
-        }
-        Fl_Group m_PageSummary {
-          label Summary open
-          xywh {0 0 470 330} box PLASTIC_DOWN_BOX labelfont 2 labelsize 10
-        } {
-          Fl_Group {} {
-            label {Image Summary:}
-            xywh {10 15 370 40} labeltype EMBOSSED_LABEL align 20
-          } {}
-          Fl_Group {} {
-            label {Button Group}
-            xywh {190 285 280 45} labeltype NO_LABEL
-          } {
-            Fl_Button {} {
-              label {&Finish}
-              callback {this->OnSummaryPageFinish();}
-              xywh {290 295 80 25} box PLASTIC_UP_BOX shortcut 0x80066 color 180 labelfont 1 labelsize 12
-            }
-            Fl_Button {} {
-              label {< Back}
-              callback {this->OnSummaryPageBack();}
-              xywh {200 295 80 25} box PLASTIC_UP_BOX color 180 labelsize 12
-            }
-            Fl_Button {} {
-              label Cancel
-              callback {this->OnCancel();}
-              xywh {380 295 80 25} box PLASTIC_UP_BOX shortcut 0xff1b color 180 labelsize 12
-            }
-          }
-          Fl_Output m_OutSummaryFileName {
-            label {File name:}
-            xywh {100 55 350 20} color 54 labelsize 12 textsize 12
-          }
-          Fl_Output {m_OutSummaryDimensions[0]} {
-            label {Dimensions:}
-            xywh {100 80 55 20} labelsize 12 textsize 12
-            class SNAPFormattedOutput
-          }
-          Fl_Output {m_OutSummaryDimensions[1]} {
-            xywh {155 80 55 20} labelsize 12 textsize 12
-            class SNAPFormattedOutput
-          }
-          Fl_Output {m_OutSummaryDimensions[2]} {
-            xywh {210 80 55 20} labelsize 12 textsize 12
-            class SNAPFormattedOutput
-          }
-          Fl_Output m_OutSummaryOrientation {
-            label {Orientation:}
-            tooltip {Note: origin information is not compatible with SPM/MRICro for Analyze files} xywh {345 80 105 20} color 54 labelsize 12 textsize 12
-          }
-          Fl_Output {m_OutSummarySpacing[0]} {
-            label {Spacing:} selected
-            xywh {100 105 55 20} labelsize 12 textsize 12
-            code0 {\#include "SNAPFormattedOutput.h"}
-            class SNAPFormattedOutput
-          }
-          Fl_Output {m_OutSummarySpacing[1]} {
-            xywh {155 105 55 20} labelsize 12 textsize 12
-            class SNAPFormattedOutput
-          }
-          Fl_Output {m_OutSummarySpacing[2]} {
-            xywh {210 105 55 20} labelsize 12 textsize 12
-            class SNAPFormattedOutput
-          }
-          Fl_Output {m_OutSummaryOrigin[0]} {
-            label {Origin:}
-            xywh {100 130 55 20} labelsize 12 textsize 12
-            class SNAPFormattedOutput
-          }
-          Fl_Output {m_OutSummaryOrigin[1]} {
-            xywh {155 130 55 20} labelsize 12 textsize 12
-            class SNAPFormattedOutput
-          }
-          Fl_Output {m_OutSummaryOrigin[2]} {
-            xywh {210 130 55 20} labelsize 12 textsize 12
-            class SNAPFormattedOutput
-          }
-          Fl_Output m_OutSummaryByteOrder {
-            label {Byte order:}
-            xywh {345 105 105 20} color 54 labelsize 12 textsize 12
-          }
-          Fl_Output m_OutSummaryPixelType {
-            label {Data type:}
-            xywh {345 130 105 20} color 54 labelsize 12 textsize 12
-          }
-          Fl_Value_Output m_OutSummarySize {
-            label {Size in KB:}
-            xywh {345 155 105 20} color 54 labelsize 12 maximum 1e+08 textsize 12
-          }
-          Fl_Group {} {
-            label {Image Header:} open
-            xywh {95 180 355 105} box PLASTIC_DOWN_BOX color 7 labelsize 12 align 5
-          } {
-            Fl_Box m_TableSummaryMetaData {
-              xywh {100 185 345 95} selection_color 246
-              code0 {\#include "MetaDataTable.h"}
-              class MetaDataTable
-            }
-          }
-        }
-      }
-    }
-    Fl_Window m_WinOutput {
-      label {ITK-SNAP Save Image Wizard}
-      xywh {809 564 470 330} type Double modal visible
-    } {
-      Fl_Wizard m_WizOutput {
-        xywh {-5 -10 505 395}
-      } {
-        Fl_Group m_PageSaveFile {
-          label {File Selection}
-          xywh {0 0 470 330} box PLASTIC_DOWN_BOX labelfont 2 labelsize 10
-        } {
-          Fl_Group m_InSaveFile {
-            label {Choose a file name to save the image:}
-            xywh {10 15 370 40} labeltype EMBOSSED_LABEL align 20
-          } {}
-          Fl_Input m_InSaveFilePageBrowser {
-            label {Filename:}
-            callback {this->OnSaveFilePageFileInputChange();}
-            tooltip {Enter the filename of the image you want to save, or select one using the 'Browse' and 'History' buttons} xywh {30 100 405 25} labelsize 12 align 5 when 1 textsize 12
-          }
-          Fl_Button {} {
-            label {&Browse...}
-            callback {this->OnSaveFilePageBrowse();}
-            xywh {265 130 80 25} box PLASTIC_UP_BOX shortcut 0x80062 labelsize 12
-          }
-          Fl_Menu_Button m_InSaveFilePageHistory {
-            label History
-            callback {this->OnSaveFilePageFileHistoryChange();} open
-            xywh {355 130 80 25} box PLASTIC_UP_BOX selection_color 181 labelsize 12 align 20 textsize 12
-          } {}
-          Fl_Choice m_InSaveFilePageFormat {
-            label {Image file format:}
-            callback {this->OnSaveFilePageFileFormatChange();} open
-            tooltip {Use this dropdown box to select an image format if one is not selected for you automatically. Normally, ITK-SNAP will figure out the file format once you select an image file using the 'Browse' button.} xywh {30 190 210 25} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-          } {
-            MenuItem {} {
-              label {Select a format...}
-              xywh {0 0 100 20} labelsize 12 hide
-            }
-          }
-          Fl_Group {} {
-            label {Button Group}
-            xywh {190 285 280 45} labeltype NO_LABEL
-          } {
-            Fl_Button m_BtnSaveFilePageNext {
-              label {&Save}
-              callback {this->OnSaveFilePageSave();}
-              xywh {290 295 80 25} box PLASTIC_UP_BOX shortcut 0x80073 color 180 labelfont 1 labelsize 12 deactivate hotspot
-            }
-            Fl_Button {} {
-              label Cancel
-              callback {this->OnSaveCancel();}
-              xywh {380 295 80 25} box PLASTIC_UP_BOX shortcut 0xff1b color 180 labelsize 12
-            }
-          }
-        }
-      }
-    }
-  }
-} 
diff --git a/UserInterface/ImageIOWizard/ImageIOWizardBase.h b/UserInterface/ImageIOWizard/ImageIOWizardBase.h
deleted file mode 100644
index 951a8f7..0000000
--- a/UserInterface/ImageIOWizard/ImageIOWizardBase.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ImageIOWizardBase.h,v $
-  Language:  C++
-  Date:      $Date: 2008/11/15 12:20:38 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __ImageIOWizardBase_h_
-#define __ImageIOWizardBase_h_
-
-/**
- * \class ImageIOWizardBase
- * The base class for the Image IO Wizard window.  This class declares 
- * callback functions and the child of ImageIOWizard implements them
- */
-class ImageIOWizardBase {
-public:
-    virtual ~ImageIOWizardBase() {}
-  virtual void OnCancel() = 0;
-  virtual void OnFilePageBrowse() = 0;
-  virtual void OnFilePageNext() = 0;
-  virtual void OnFilePageFileInputChange() = 0;
-  virtual void OnFilePageFileHistoryChange() = 0;
-  virtual void OnFilePageFileFormatChange() = 0;
-  virtual void OnHeaderPageNext() = 0;
-  virtual void OnHeaderPageBack() = 0;
-  virtual void OnHeaderPageInputChange() = 0;
-  virtual void OnDICOMPageNext() = 0;
-  virtual void OnDICOMPageBack() = 0;
-  virtual void OnSummaryPageFinish() = 0;
-  virtual void OnSummaryPageBack() = 0;
-
-  // Save related functions
-  virtual void OnSaveFilePageFileInputChange() = 0;
-  virtual void OnSaveFilePageFileFormatChange() = 0;
-  virtual void OnSaveFilePageFileHistoryChange() = 0;
-  virtual void OnSaveFilePageBrowse() = 0;
-  virtual void OnSaveFilePageSave() = 0;
-  virtual void OnSaveCancel() = 0;
-};
-
-#endif
diff --git a/UserInterface/ImageIOWizard/ImageIOWizardLogic.cxx b/UserInterface/ImageIOWizard/ImageIOWizardLogic.cxx
deleted file mode 100755
index 6ad9b38..0000000
--- a/UserInterface/ImageIOWizard/ImageIOWizardLogic.cxx
+++ /dev/null
@@ -1,1194 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ImageIOWizardLogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2011/05/04 15:25:42 $
-  Version:   $Revision: 1.8 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "FL/Fl.H"
-#include "FL/Fl_Native_File_Chooser.H"
-#include "FL/filename.H"
-#include "FL/fl_ask.H"
-#include "FL/Fl_Text_Buffer.H"
-#include <stdio.h>
-#include <cmath>
-#include <map>
-#include <string>
-#include <iomanip>
-#include <sstream>
-
-#include "ImageIOWizardLogic.h"
-#include "itkOrientedImage.h"
-#include "itkImageIOBase.h"
-#include "itkIOCommon.h"
-#include "itkMetaDataObject.h"
-#include "itkGDCMSeriesFileNames.h"
-#include <itksys/SystemTools.hxx>
-
-using std::map;
-
-
-ImageIOWizardLogic
-::ImageIOWizardLogic() 
-{                 
-
-  // Initialize the DICOM directory lister
-  m_DICOMLister = itk::GDCMSeriesFileNames::New();
-  
-  // Initialize the text buffers
-  // m_SummaryTextBuffer = new Fl_Text_Buffer();
-
-  // Initialize the callback pointer
-  m_Callback = NULL;
-}
-
-
-void ImageIOWizardLogic
-::MakeWindow()
-{
-  // Call the parent method
-  ImageIOWizard::MakeWindow();
-
-  // Initialize the file save dialog box based on the allowed file types
-  for(unsigned int i = 0; i < GuidedNativeImageIO::FORMAT_COUNT; i++)
-    {
-    // Create an appropriate description
-    FileFormat fmt = static_cast<FileFormat>(i);
-    GuidedNativeImageIO::FileFormatDescriptor fd = 
-      GuidedNativeImageIO::GetFileFormatDescriptor(fmt);
-    StringType text = fd.name + " File";
-    
-    // Add a menu option to the save menu, disabling it if it's unsupported
-    m_InFilePageFormat->add(text.c_str(),0,NULL,NULL,
-                            this->CanLoadFileFormat((FileFormat) i) ? 
-                              0 : FL_MENU_INACTIVE);
-    
-    // Add a menu option to the save menu, disabling it if it's unsupported
-    m_InSaveFilePageFormat->add(text.c_str(),0,NULL,NULL,
-                                this->CanSaveFileFormat((FileFormat) i) ? 
-                                  0 : FL_MENU_INACTIVE);
-    }
-
-  m_InSaveFilePageFormat->value(0);
-  
-  // Add the buffer to the summary text widget
-  // m_OutSummaryMetaData->buffer(m_SummaryTextBuffer);
-}
-
-
-void ImageIOWizardLogic
-::GoBack(Fl_Group *current) 
-{
-  // The link to the last page
-  Fl_Group *last = NULL;
-
-  // In the input is NULL, get the current page from the wizard widget
-  current = (current == NULL) ? (Fl_Group *)m_WizInput->value() : current;
-
-  if (current == m_PageHeader || current == m_PageDICOM)
-    {
-    last = m_PageFile;
-    }
-  else if (current == m_PageSummary)
-    {
-    last = m_PageHeader;
-    }
-  else
-    {
-    assert(0 == "Next page not valid at this position in the wizard");
-    }
-
-  if (!last->active())
-    {
-    GoBack(last);
-    } 
-  else
-    {
-    m_WizInput->value(last);
-    }
-}
-
-
-void ImageIOWizardLogic
-::GoForward(Fl_Group *current) 
-{
-  // The link to the next page
-  Fl_Group *next = NULL;
-
-  // In the input is NULL, get the current page from the wizard widget
-  current = (current == NULL) ? (Fl_Group *)m_WizInput->value() : current;
-
-  // Follow the sequence of the pages
-  if(current == m_PageFile) 
-    {
-    if(m_PageHeader->active())
-      next = m_PageHeader;
-    else if(m_PageDICOM->active())
-      next = m_PageDICOM;
-    else
-      next = m_PageSummary;
-    }
-  else if (current == m_PageHeader || current == m_PageDICOM) 
-    {
-    next = m_PageSummary;
-    }    
-  else
-    {
-    assert(0 == "Next page not valid");
-    }
-    
-  // Check if the page is active 
-  if (!next->active())
-    {
-    GoForward(next);
-    return;
-    } 
-    
-  // Flip to the new page
-  m_WizInput->value(next);
-
-  // Call the enter-page method
-  if (next == m_PageHeader)
-    {
-    OnHeaderPageEnter();
-    }
-  else if (next == m_PageDICOM)
-    {
-    OnDICOMPageEnter();
-    }
-  else if (next == m_PageSummary)
-    {
-    OnSummaryPageEnter();
-    }
-}
-
-
-ImageIOWizardLogic::StringType
-ImageIOWizardLogic
-::GetFilePattern(bool forLoading) 
-{
-  // String containing the whole patterns
-  StringType pattern = "";
-  bool patternNeedsTab = false;
-
-  // String containing the "All Image Files" pattern
-  StringType allImageFiles = "All Image Files\t*.{";
-  bool allImageFilesNeedsComma = false;
-
-  // Go through all supported formats
-  for(unsigned int i=0;i < GuidedNativeImageIO::FORMAT_COUNT;i++)
-    {
-    FileFormat fmt = static_cast<FileFormat>(i);
-    GuidedNativeImageIO::FileFormatDescriptor fd = 
-      GuidedNativeImageIO::GetFileFormatDescriptor(fmt);
-
-    // Check if the file format is supported
-    if((forLoading && this->CanLoadFileFormat(fmt)) ||
-       (!forLoading && this->CanSaveFileFormat(fmt)))
-      {
-      // Add comma to allImageFiles
-      if(allImageFilesNeedsComma)
-        allImageFiles += ",";
-      else
-        allImageFilesNeedsComma = true;
-
-      // Add extension to all image files
-      allImageFiles += fd.pattern;
-
-      // Add a tab to the pattern
-      if(patternNeedsTab)
-        pattern += "\n";
-      else
-        patternNeedsTab = true;
-
-      // Construct the pattern
-      pattern += fd.name;
-      pattern += " Files\t*.{";
-      pattern += fd.pattern;
-      pattern += "}";
-      }
-    }
-
-  // Finish the all image pattern
-  allImageFiles += "}\n";
-
-  // Compete the pattern
-  pattern = allImageFiles + pattern;
-  return pattern;
-}
-
-
-
-ImageIOWizardLogic::FileFormat
-ImageIOWizardLogic
-::DetermineFileFormatFromFileName(bool forLoading, const char *testFile) 
-{
-  // Iterate over the known file types
-  for(unsigned int i = 0;i < GuidedNativeImageIO::FORMAT_COUNT;i++)
-    {
-    FileFormat fmt = static_cast<FileFormat>(i);
-    GuidedNativeImageIO::FileFormatDescriptor fd = 
-      GuidedNativeImageIO::GetFileFormatDescriptor(fmt);
-
-    // Check if the file format is supported
-    if((forLoading && this->CanLoadFileFormat(fmt)) ||
-       (!forLoading && this->CanSaveFileFormat(fmt)))
-      {
-      // Create a matching pattern
-      StringType pattern = "*.{" + fd.pattern + "}";
-
-      // Check if the filename matches the pattern
-      if(fl_filename_match(testFile,pattern.c_str()))
-        return fmt;
-      }
-    }
-
-  // Failed: return illegal pattern
-  return GuidedNativeImageIO::FORMAT_COUNT;
-}
-
-
-bool ImageIOWizardLogic
-::CanLoadFileFormat(FileFormat irisNotUsed(format)) const 
-{ 
-  return true; 
-}
-
- 
-
-bool ImageIOWizardLogic
-::CanSaveFileFormat(FileFormat format) const 
-{ 
-  GuidedNativeImageIO::FileFormatDescriptor fd = 
-    GuidedNativeImageIO::GetFileFormatDescriptor(format); 
-  return fd.can_write;
-}
-
-
-void ImageIOWizardLogic
-::OnFilePageBrowse() 
-{
-  // Get the path and pattern for reading in the file 
-  StringType pattern = this->GetFilePattern(true);
-  
-  const char *path = m_InFilePageBrowser->value();
-  path = strlen(path) ? path : NULL;
-
-  // Configure a file dialog
-  const char *fName = NULL;
-  Fl_Native_File_Chooser chooser;
-  chooser.type(Fl_Native_File_Chooser::BROWSE_FILE);
-  chooser.title("Load Image");
-  chooser.preset_file(path);
-  chooser.filter(pattern.c_str());
-  if (chooser.show() == 0)
-   {
-   fName = chooser.filename();
-   }
-
-  // Bring up th choice dialog
-  if (fName && strlen(fName))
-    {
-    // Set the new filename
-    m_InFilePageBrowser->value(fName);
-
-    // Reset the format drop-down box to a null value
-    m_InFilePageFormat->value(0);
-
-    // Run the filename change event
-    OnFilePageFileInputChange();
-    }
-}
-
-
-void 
-ImageIOWizardLogic
-::OnFilePageFileFormatChange()
-{
-  // Activate the next button if there is a format selected
-  if(m_InFilePageFormat->value() > 0)
-    m_BtnFilePageNext->activate();
-  else 
-    m_BtnFilePageNext->deactivate();
-
-  // If the user selects 'raw', update the format
-  FileFormat format = (FileFormat) (m_InFilePageFormat->value() - 1);
-  if (format == GuidedNativeImageIO::FORMAT_RAW)
-    m_PageHeader->activate();
-  else
-    m_PageHeader->deactivate();
-
-  // If the user selects 'dicom' enable the dicom page
-  if(format == GuidedNativeImageIO::FORMAT_DICOM)
-    m_PageDICOM->activate();
-  else 
-    m_PageDICOM->deactivate();
-}
-
-
-void 
-ImageIOWizardLogic
-::OnFilePageFileHistoryChange()
-{
-  // Copy the history to the file box
-  m_InFilePageBrowser->value(
-    m_InFilePageHistory->mvalue()->label());
-
-  // Update everything
-  OnFilePageFileInputChange();
-}
-
-
-void ImageIOWizardLogic
-::OnFilePageFileInputChange() 
-{
-  // Clear the registry
-  m_Registry.Clear();
-
-  // Check the length of the input
-  const char *text = m_InFilePageBrowser->value();
-  if (text != NULL && strlen(text) > 0)
-    {
-    // Try to load the registry associated with this filename
-    if(m_Callback)
-      m_Callback->FindRegistryAssociatedWithImage(
-        m_InFilePageBrowser->value(), m_Registry);
-
-    // If the registry contains a file format, override with that
-    FileFormat fmt = 
-      m_GuidedIO.GetFileFormat(m_Registry, GuidedNativeImageIO::FORMAT_COUNT);
-
-    // Try to select a file format accoring to the file name
-    if(fmt == GuidedNativeImageIO::FORMAT_COUNT)
-      fmt = DetermineFileFormatFromFileName(true, text);
-    
-    // If the filename does not match any format, we do not change the 
-    // format choice box in case that the user has already set it manually
-    if(fmt < GuidedNativeImageIO::FORMAT_COUNT)
-      m_InFilePageFormat->value((int)fmt+1);
-    
-    // Run the format change event
-    OnFilePageFileFormatChange();
-    } 
-  else
-    { m_BtnFilePageNext->deactivate(); }            
-}
-
-
-void ImageIOWizardLogic
-::OnFilePageNext() 
-{
-  // Check if a file has been specified
-  assert(m_InFilePageBrowser->value() 
-    && strlen(m_InFilePageBrowser->value()) > 0);
-
-  // Check that a format has been specified
-  assert(m_InFilePageFormat->value() > 0);
-
-  // Get the selected format and place it in the registry
-  FileFormat format = (FileFormat) (m_InFilePageFormat->value() - 1);
-  m_GuidedIO.SetFileFormat(m_Registry, format);
-
-  // If file format is raw or dicom, go to the next page, o.w., load image
-  switch(format) 
-    {
-    case GuidedNativeImageIO::FORMAT_RAW:
-      GoForward(); 
-      break;
-    case GuidedNativeImageIO::FORMAT_DICOM:
-      if(ProcessDICOMDirectory())
-        GoForward();
-      break;
-    default:
-      if(DoLoadImage())
-        GoForward();
-    }
-}
-
-
-void 
-ImageIOWizardLogic
-::OnCancel() 
-{
-  // Set the status to negative: nothing was loaded
-  m_ImageLoaded = false;
-
-  // Hide this window
-  m_WinInput->hide();
-}
-
-
-void 
-ImageIOWizardLogic
-::OnHeaderPageNext() 
-{
-  // Make sure we're not here by mistake
-  assert(m_InFilePageFormat->value() - 1 == (int) GuidedNativeImageIO::FORMAT_RAW);
-
-  // Set up the registry with the specified values
-  m_Registry["Raw.HeaderSize"] 
-    << (unsigned int) m_InHeaderPageHeaderSize->value();
-
-  // Set the dimensions
-  m_Registry["Raw.Dimensions"] << Vector3i(
-    (int) m_InHeaderPageDimX->value(),
-    (int) m_InHeaderPageDimY->value(),
-    (int) m_InHeaderPageDimZ->value());
-
-  // Set the spacing
-  m_Registry["Raw.Spacing"] << Vector3d(
-    m_InHeaderPageSpacingX->value(),
-    m_InHeaderPageSpacingY->value(),
-    m_InHeaderPageSpacingZ->value());
-
-  // Set the endianness
-  m_Registry["Raw.BigEndian"] 
-    << ( m_InHeaderPageByteAlign->value() == 0 );
-
-  // Set the pixel type
-  int iPixType = ((int)m_InHeaderPageVoxelType->value());
-  GuidedNativeImageIO::RawPixelType pixtype = (iPixType < 0) 
-    ? GuidedNativeImageIO::PIXELTYPE_COUNT
-    : (GuidedNativeImageIO::RawPixelType) iPixType;
-  m_GuidedIO.SetPixelType(m_Registry, pixtype);
-
-  // Do the loading
-  if(DoLoadImage())
-    GoForward();
-}
-
-
-
-bool 
-ImageIOWizardLogic
-::ProcessDICOMDirectory()
-{
-  // Get the directory tree from the file
-  StringType dirname = 
-    itksys::SystemTools::FileIsDirectory(m_InFilePageBrowser->value())
-    ? m_InFilePageBrowser->value()
-    : itksys::SystemTools::GetParentDirectory(m_InFilePageBrowser->value());
-
-  // Put up a wait cursor
-  m_WinInput->cursor(FL_CURSOR_WAIT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-
-  // Try to list the DICOM files in the directory
-  try
-    {
-    m_DICOMLister->SetDirectory(dirname.c_str());
-    m_InFilePageBrowser->value(dirname.c_str());
-    }
-  catch(...)
-    {
-    fl_alert("Error listing DICOM files in directory: \n %s",dirname.c_str());
-    }
-
-  // Restore the cursor
-  m_WinInput->cursor(FL_CURSOR_DEFAULT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-  
-  // Get the list of series in the directory
-  if(m_DICOMLister->GetSeriesUIDs().size() == 0)
-    {
-    fl_alert("No DICOM series found in the directory: \n%s",dirname.c_str());
-    return false;
-    }
-  else return true;
- }
-
-
-void 
-ImageIOWizardLogic
-::OnDICOMPageEnter()
-{
-  // Get the list of sequence ids
-  const std::vector<StringType> &uids = m_DICOMLister->GetSeriesUIDs();
-
-  // Add the ids to the menu
-  m_InDICOMPageSequenceId->clear();
-  for(unsigned int i = 0; i < uids.size(); i++)
-    m_InDICOMPageSequenceId->add(uids[i].c_str());
-
-  // See if one of the sequences in the registry matches
-  StringType last = m_Registry["DICOM.SequenceId"]["NULL"];
-  const Fl_Menu_Item *lastpos = m_InDICOMPageSequenceId->find_item(last.c_str());
-  if(lastpos)
-    m_InDICOMPageSequenceId->value(lastpos);
-  else 
-    m_InDICOMPageSequenceId->value(0);
-}
-
-
-void 
-ImageIOWizardLogic
-::OnDICOMPageNext()
-{
-  // The user will have selected some DICOM series. All we have to do is
-  // specify the series in the registry and load the file
-  m_Registry["DICOM.SequenceId"] << m_InDICOMPageSequenceId->mvalue()->label();
-
-  // In addition, generate an explicit array of filenames for this sequence id. 
-  // This will allow the DICOM loader to load files without having to list the 
-  // directory again
-  const std::vector<StringType> &files = m_DICOMLister->GetFileNames(
-    StringType(m_InDICOMPageSequenceId->mvalue()->label()));
-  m_Registry.Folder("DICOM.SliceFiles").PutArray(files);
-
-  // Try loading the file now
-  if(DoLoadImage())
-    GoForward();
-}
-
-
-void 
-ImageIOWizardLogic
-::OnDICOMPageBack()
-{
-  GoBack();
-}
-
-
-bool 
-ImageIOWizardLogic
-::DoLoadImage()
-{
-  bool rc;
-
-  // Show a wait cursor
-  m_WinInput->cursor(FL_CURSOR_WAIT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-  
-  // Try to load a file
-  try 
-    {     
-    // Since we want to store the image IO, we need to use these two calls 
-    // instead of just calling ReadImage with the registry
-    m_GuidedIO.ReadNativeImage(m_InFilePageBrowser->value(), m_Registry);
-
-    /* 
-    if(this->IsNativeFormatSupported())
-      {
-      RescaleNativeImageToScalar<TPixel> rescale;
-      m_Image = rescale(&m_GuidedIO);
-      m_NativeScale = rescale.GetNativeScale();
-      m_NativeShift = rescale.GetNativeShift();
-      }
-    else if(m_GuidedIO.GetNumberOfComponentsInNativeImage() == 3)
-      {
-      CastNativeImageToRGB<TPixel> cast;
-      m_Image = cast(&m_GuidedIO);
-      m_NativeScale = 1.0; m_NativeShift = 0.0;
-      }
-    else
-      {
-      CastNativeImageToScalar<TPixel> cast;
-      m_Image = cast(&m_GuidedIO);
-      m_NativeScale = 1.0; m_NativeShift = 0.0;
-      }
-
-    // Disconnect the image from the reader to free up memory (?)
-    m_GuidedIO.DeallocateNativeImage();
-    */
-
-    // Check if the image is really valid
-    rc = CheckImageValidity();
-    }
-  catch(itk::ExceptionObject &exc)
-  {
-    // Show the error
-    fl_alert("Error reading image: %s.",exc.GetDescription());
-    rc = false;
-  }
-
-  // Fix the cursor
-  m_WinInput->cursor(FL_CURSOR_DEFAULT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-
-  // Check if the image is valid (subclasses can perform extra tasks here)
-  return rc;
-}
-
-
-void 
-ImageIOWizardLogic
-::OnHeaderPageInputChange() 
-{
-  // Header input has changed
-  if (m_InHeaderPageDimX->value() >= 1 &&
-      m_InHeaderPageDimY->value() >= 1 &&
-      m_InHeaderPageDimZ->value() >= 1 &&
-      m_InHeaderPageSpacingX->value() > 0 &&
-      m_InHeaderPageSpacingY->value() > 0 &&
-      m_InHeaderPageSpacingZ->value() > 0)
-    {
-    m_BtnHeaderPageNext->activate();
-    }
-  else
-    {
-    m_BtnHeaderPageNext->deactivate();
-    }
-}
-
-
-void 
-ImageIOWizardLogic
-::OnHeaderPageBack() 
-{
-  GoBack();
-}
-
-
-void 
-ImageIOWizardLogic
-::OnFilePageEnter()
-{
-
-}
-
-
-void 
-ImageIOWizardLogic
-::OnHeaderPageEnter()
-{
-  // Use the values from the registry to set up the header page
-  m_InHeaderPageHeaderSize->value(m_Registry["Raw.HeaderSize"][0]);
-  
-  // Set the dimensions
-  Vector3i dims = m_Registry["Raw.Dimensions"][Vector3i(0)];
-  m_InHeaderPageDimX->value(dims[0]);
-  m_InHeaderPageDimY->value(dims[1]);
-  m_InHeaderPageDimZ->value(dims[2]);
-
-  // Set the spacing
-  Vector3d spacing = m_Registry["Raw.Spacing"][Vector3d(1.0)];
-  m_InHeaderPageSpacingX->value(spacing[0]);
-  m_InHeaderPageSpacingY->value(spacing[1]);
-  m_InHeaderPageSpacingZ->value(spacing[2]);
-
-  // Set the data type
-  RawPixelType pixtype = 
-    m_GuidedIO.GetPixelType(m_Registry, GuidedNativeImageIO::PIXELTYPE_UCHAR);
-  m_InHeaderPageVoxelType->value((int)pixtype);
-
-  // Set the endianness
-  if(m_Registry["Raw.BigEndian"][true]) 
-    m_InHeaderPageByteAlign->value(0);
-  else
-    m_InHeaderPageByteAlign->value(1);
-}
-
-template<class AnyType>
-bool
-try_print_metadata(std::ostream &sout, itk::MetaDataDictionary &mdd, std::string key)
-  {
-  AnyType value = 0;
-  if(itk::ExposeMetaData<AnyType>(mdd, key, value))
-    {
-    sout << key << " = " << value << std::endl;
-    return true;
-    }
-  else return false;
-  }
-
-
-void 
-ImageIOWizardLogic
-::OnSummaryPageEnter()
-{
-  const char *boTypes[] = 
-    {"Big Endian", "Little Endian","Order Not Applicable"};
-
-  // The object better not be NULL!
-  if(m_GuidedIO.IsNativeImageLoaded())
-    {
-    // Native image
-    itk::ImageBase<3>::Pointer native = m_GuidedIO.GetNativeImage();
-
-    // A stream to simplify converting to string
-    IRISOStringStream sout;    
-
-    // Print file name
-    m_OutSummaryFileName->value(m_GuidedIO.GetFileNameOfNativeImage().c_str());
-
-    // Print file dimensions, spacing and origin
-    for(unsigned int i = 0; i < 3; i++)
-      {
-      m_OutSummaryDimensions[i]->value(native->GetBufferedRegion().GetSize()[i]);
-      m_OutSummarySpacing[i]->value(native->GetSpacing()[i]);
-      m_OutSummaryOrigin[i]->value(native->GetOrigin()[i]);
-      }
-
-    // Print file size in bytes
-    m_OutSummarySize->value((int)(m_GuidedIO.GetFileSizeOfNativeImage() / (1024.0)));
-    
-    // Print out the orientation information
-    sout.str("");
-    vnl_matrix<double> dir = native->GetDirection().GetVnlMatrix();
-    std::string rai = 
-      ImageCoordinateGeometry::ConvertDirectionMatrixToClosestRAICode(dir);
-    if(ImageCoordinateGeometry::IsDirectionMatrixOblique(dir))
-      sout << "Oblique (closest to " << rai << ")";
-    else
-      sout << rai;
-    m_OutSummaryOrientation->value(sout.str().c_str());
-    
-    // TODO: This is a workaround on an itk bug with RawImageIO
-    if(m_GuidedIO.GetComponentTypeInNativeImage() != itk::ImageIOBase::UNKNOWNCOMPONENTTYPE)
-      {
-      // There actually is a type in the IO object
-      m_OutSummaryPixelType->value(
-        m_GuidedIO.GetComponentTypeAsStringInNativeImage().c_str());
-      }
-    else
-      {
-      m_OutSummaryPixelType->value(m_InHeaderPageVoxelType->text());
-      }
-    
-    // Print the byte order
-    m_OutSummaryByteOrder->value(
-       boTypes[(unsigned int)(m_GuidedIO.GetByteOrderInNativeImage() - ImageIOType::BigEndian)]);
-
-    // Populate the metadata table
-    m_TableSummaryMetaData->SetInputImage(m_GuidedIO.GetNativeImage());
-    m_TableSummaryMetaData->SetColumnWidth(345);
-
-    // Dump the contents of the meta data dictionary
-    /*
-    m_SummaryTextBuffer->text("");
-    MetaDataDictionary &mdd = native->GetMetaDataDictionary();
-    for(
-      MetaDataDictionary::ConstIterator itMeta = mdd.Begin();
-      itMeta != mdd.End(); ++itMeta)      
-      {
-      // Get the metadata as a generic object
-      std::string key = itMeta->first, v_string;
-      std::ostringstream sout;
-
-      if(itk::ExposeMetaData<std::string>(mdd, key, v_string))
-        {
-        // For some weird reason, some of the strings returned by this method
-        // contain '\0' characters. We will replace them by spaces
-        std::ostringstream tmpout("");
-        for(unsigned int i = 0; i < v_string.length(); i++)
-          if(v_string[i] >= ' ') 
-            tmpout << v_string[i];
-        v_string = tmpout.str();
-
-        // Make sure the value has more than blanks
-        if(v_string.find_first_not_of(" ") != v_string.npos)
-          sout << key << " = " << v_string << std::endl;
-        }
-      else 
-        {
-        bool rc = false;
-        if(!rc) rc |= try_print_metadata<double>(sout, mdd, key);
-        if(!rc) rc |= try_print_metadata<float>(sout, mdd, key);
-        if(!rc) rc |= try_print_metadata<int>(sout, mdd, key);
-        if(!rc) rc |= try_print_metadata<unsigned int>(sout, mdd, key);
-        if(!rc) rc |= try_print_metadata<long>(sout, mdd, key);
-        if(!rc) rc |= try_print_metadata<unsigned long>(sout, mdd, key);
-        if(!rc) rc |= try_print_metadata<short>(sout, mdd, key);
-        if(!rc) rc |= try_print_metadata<unsigned short>(sout, mdd, key);
-        if(!rc) rc |= try_print_metadata<char>(sout, mdd, key);
-        if(!rc) rc |= try_print_metadata<unsigned char>(sout, mdd, key);
-
-        if(!rc)
-          {
-          sout << key << " of unsupported type " 
-            << itMeta->second->GetMetaDataObjectTypeName() << std::endl;
-          }
-        }
-
-      m_SummaryTextBuffer->append(sout.str().c_str());
-      }
-    */
-    }
-  else 
-    {
-    m_OutSummaryFileName->value("Error loading image.");        
-    m_OutSummarySize->value(0); 
-    m_OutSummaryOrientation->value("n/a");
-    m_OutSummaryPixelType->value("n/a");
-    m_OutSummaryByteOrder->value("n/a");
-    // m_SummaryTextBuffer->text("");
-
-    for(size_t i = 0; i < 3; i++)
-      {
-      m_OutSummaryDimensions[i]->value(0);
-      m_OutSummarySpacing[i]->value(0);
-      m_OutSummaryOrigin[i]->value(0);
-      }
-    }
-}
-
-
-void 
-ImageIOWizardLogic
-::OnSummaryPageFinish() 
-{
-  // Perform a final validity / sanity check
-  if (CheckFinalValidity()) 
-  {
-    // Set the status to positive, the image has been loaded!
-    m_ImageLoaded = true;
-
-    // Save the registry produced in this wizard
-    if(m_Callback)
-      m_Callback->UpdateRegistryAssociatedWithImage(
-        m_InFilePageBrowser->value(), m_Registry);
-
-    // Hide this window
-    m_WinInput->hide();
-  }
-}
-
-
-ImageIOWizardLogic::~ImageIOWizardLogic() 
-{
-  // delete m_SummaryTextBuffer;
-}
-
-
-bool
-ImageIOWizardLogic
-::NonInteractiveInputWizard(const char *file)
-{
-  // Indicate no file loaded yet
-  m_ImageLoaded = false;
-  
-  // Set the GUI filename input with the argument
-  m_InFilePageBrowser->value(file);
-  
-  // Clear the registry
-  m_Registry.Clear();
-
-  // Try to read the file
-  if(file != NULL && strlen(file) > 0)
-    {
-    if(m_Callback)
-      m_Callback->FindRegistryAssociatedWithImage(file, m_Registry);
-
-    // If the registry contains a file format, override with that
-    FileFormat fmt = 
-    m_GuidedIO.GetFileFormat(m_Registry, GuidedNativeImageIO::FORMAT_COUNT);
-
-    // Try to select a file format according to the file name
-    if(fmt == GuidedNativeImageIO::FORMAT_COUNT)
-      fmt = DetermineFileFormatFromFileName(true, file);
-
-    switch(fmt)
-      {
-      case GuidedNativeImageIO::FORMAT_RAW:
-      case GuidedNativeImageIO::FORMAT_DICOM:
-        std::cerr << "Loading RAW or DICOM data from command line is not supported" << std::endl;
-        m_ImageLoaded = false;
-        break;
-      default:
-        m_ImageLoaded = DoLoadImage();
-      }
-    }
-
-  return m_ImageLoaded;
-}
-
-
-bool 
-ImageIOWizardLogic
-::DisplayInputWizard(const char *file, const char *type)
-{
-  // Set up the custom title if type is provided
-  if(type)
-    {
-    std::string title = "Wizard for loading a ";
-    title += type;
-    title += " image";
-    m_WinInput->copy_label(title.c_str());
-    std::string topic = "Select a ";
-    topic += type;
-    topic += " image to load:";
-    m_InFilePage->copy_label(topic.c_str());
-    }
-
-  // The loaded flag is false
-  m_ImageLoaded = false;
-
-  // Point the wizard to the first page
-  m_WizInput->value(m_PageFile);
-
-  // Clear the file name box
-  // TODO: Implement a history list
-  if(file)
-    m_InFilePageBrowser->value(file);
-  
-  OnFilePageFileInputChange();
-
-  // Show the input window
-  m_WinInput->show();
-
-  // Loop until the window has been closed
-  while (m_WinInput->visible())
-    Fl::wait();
-
-  // Whether or not the load has been succesfull
-  return m_ImageLoaded;
-}
-
-
-void 
-ImageIOWizardLogic
-::OnSummaryPageBack() 
-{
-  GoBack();
-}
-
-
-
-bool 
-ImageIOWizardLogic
-::DisplaySaveWizardImpl(const char *file, const char *type)
-{
-  // Set up the custom title if type is provided
-  if(type)
-    {
-    std::string title = "Wizard for saving a ";
-    title += type;
-    title += " image";
-    m_WinOutput->copy_label(title.c_str());
-    std::string topic = "Choose a file name to save the ";
-    topic += type;
-    topic += " image:";
-    m_InSaveFile->copy_label(topic.c_str());
-    }
-
-  // Clear the saved flag
-  m_ImageSaved = false;
-
-  // Clear the file name box
-  if(file)
-    m_InFilePageBrowser->value(file);
-  OnSaveFilePageFileInputChange();
-
-  // Show the input window
-  m_WinOutput->show();
-
-  // Loop until the window has been closed
-  while (m_WinOutput->visible())
-    Fl::wait();
-
-  // Clear the image pointer
-  delete m_SaveCallback;
-
-  // Whether or not the load has been succesfull
-  return m_ImageSaved;
-}
-
-
-void 
-ImageIOWizardLogic
-::OnSaveFilePageFileInputChange()
-{
-  // Clear the registry
-  m_Registry.Clear();
-
-  // Check the length of the input
-  const char *text = m_InSaveFilePageBrowser->value();
-  if (text != NULL && strlen(text) > 0)
-    {
-    // Try to load the registry associated with this filename
-    if(m_Callback)
-      m_Callback->FindRegistryAssociatedWithImage(
-        m_InSaveFilePageBrowser->value(), m_Registry);
-
-    // If the registry contains a file format, override with that
-    FileFormat fmt = 
-      m_GuidedIO.GetFileFormat(m_Registry, GuidedNativeImageIO::FORMAT_COUNT);
-
-    // Try to select a file format accoring to the file name
-    if(fmt == GuidedNativeImageIO::FORMAT_COUNT)
-      fmt = DetermineFileFormatFromFileName(true, text);
-
-    // If the filename does not match any format, we do not change the 
-    // format choice box in case that the user has already set it manually
-    if(fmt < GuidedNativeImageIO::FORMAT_COUNT)
-      m_InSaveFilePageFormat->value((int)fmt+1);
-    
-    // Run the format change event
-    OnSaveFilePageFileFormatChange();
-    } 
-  else
-    { m_BtnSaveFilePageNext->deactivate(); }            
-}
-
-
-void 
-ImageIOWizardLogic
-::OnSaveFilePageFileHistoryChange()
-{
-  // Copy the history to the file box
-  m_InSaveFilePageBrowser->value(
-    m_InSaveFilePageHistory->mvalue()->label());
-
-  // Update everything
-  OnSaveFilePageFileInputChange();
-}
-
-
-void 
-ImageIOWizardLogic
-::OnSaveFilePageFileFormatChange()
-{
-  // Activate the next button if there is a format selected
-  if(m_InSaveFilePageFormat->value() > 0)
-    m_BtnSaveFilePageNext->activate();
-  else 
-    m_BtnSaveFilePageNext->deactivate();
-}
-
-
-void 
-ImageIOWizardLogic
-::OnSaveFilePageBrowse()
-{  
-  // Get the path and pattern for reading in the file 
-  const char *path = m_InSaveFilePageBrowser->value();
-  path = strlen(path) ? path : NULL;
-
-  // Get a pattern
-  StringType pattern = this->GetFilePattern(false);
-
-  // Create a file chooser
-  const char *fName = NULL;
-  Fl_Native_File_Chooser chooser;
-  chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
-  chooser.title("Save Image As");
-  chooser.options(Fl_Native_File_Chooser::NEW_FOLDER);
-  chooser.preset_file(path);
-  chooser.filter(pattern.c_str());
-  if (chooser.show() == 0)
-   {
-   fName = chooser.filename();
-   }
-
-  if (fName && strlen(fName))
-    {
-    // Set the new filename
-    m_InSaveFilePageBrowser->value(fName);
-
-    // Reset the format drop-down box to a null value
-    m_InSaveFilePageFormat->value(0);
-
-    // Run the filename change event
-    OnSaveFilePageFileInputChange();
-    }
-}
-
-
-void 
-ImageIOWizardLogic
-::OnSaveFilePageSave()
-{
-  // There better be a format selected
-  assert(m_InSaveFilePageFormat->value() > 0);
-
-  // Get the selected format and place it in the registry
-  FileFormat format = (FileFormat) (m_InSaveFilePageFormat->value() - 1);
-  m_GuidedIO.SetFileFormat(m_Registry, format);
-
-  // Put up a waiting cursor
-  m_WinOutput->cursor(FL_CURSOR_WAIT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-
-  // Try to save the image using the current format
-  try 
-    {
-    // Try to save the image
-    m_SaveCallback->Save(
-      m_InSaveFilePageBrowser->value(), m_Registry);
-    m_ImageSaved = true;
-
-    // Save the registry produced in this wizard
-    if(m_Callback)
-      m_Callback->UpdateRegistryAssociatedWithImage(
-        m_InFilePageBrowser->value(), m_Registry);
-
-    // Hide the dialog
-    m_WinOutput->hide();
-    }
-  catch(itk::ExceptionObject &exc)
-    { fl_alert("Error saving file: %s",exc.GetDescription()); }
-  
-  // Restore the cursor
-  m_WinOutput->cursor(FL_CURSOR_DEFAULT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-}
-
-
-void 
-ImageIOWizardLogic
-::OnSaveCancel()
-{
-  // Just close the window
-  m_WinOutput->hide();
-}
-
-
-void 
-ImageIOWizardLogic
-::SetHistory(const HistoryType &history)
-{
-  // Store the history
-  m_History = history;
-
-  // Clear the history drop box
-  m_InFilePageHistory->clear();
-  m_InSaveFilePageHistory->clear();
-
-  // Add the history
-  if(history.size() > 0)
-    {  
-    // Add each item to the history menu (history is traversed
-    // backwards)
-    for(HistoryType::reverse_iterator it=m_History.rbegin();
-        it!=m_History.rend();it++)
-      {
-      // FLTK's add() treats slashes as submenu separators, hence this code
-      m_InFilePageHistory->replace(
-        m_InFilePageHistory->add("dummy"),it->c_str());      
-      m_InSaveFilePageHistory->replace(
-        m_InSaveFilePageHistory->add("dummy"),it->c_str());
-      }
-
-    // Activate the history menu    
-    m_InFilePageHistory->activate();
-    m_InSaveFilePageHistory->activate();
-    }
-  else
-    {
-    // Deactivate history
-    m_InFilePageHistory->deactivate();
-    m_InSaveFilePageHistory->deactivate();
-    }
-}
-
diff --git a/UserInterface/ImageIOWizard/ImageIOWizardLogic.h b/UserInterface/ImageIOWizard/ImageIOWizardLogic.h
deleted file mode 100644
index da84396..0000000
--- a/UserInterface/ImageIOWizard/ImageIOWizardLogic.h
+++ /dev/null
@@ -1,329 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ImageIOWizardLogic.h,v $
-  Language:  C++
-  Date:      $Date: 2009/07/23 15:50:58 $
-  Version:   $Revision: 1.9 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __ImageIOWizardLogic_h_
-#define __ImageIOWizardLogic_h_
-
-#if defined(_WIN32)
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <winbase.h>
-#endif
-
-#include <assert.h>
-#include <string>
-#include <vector>
-
-#include "ImageIOWizard.h"
-#include "FL/fl_draw.H"
-#include "itkSmartPointer.h"
-#include "ImageCoordinateGeometry.h"
-#include "Registry.h"
-#include <string>
-#include <vector>
-
-#include "GuidedNativeImageIO.h"
-
-class Fl_Text_Buffer;
-namespace itk 
-{
-  template <unsigned int VDimensions> class Size;
-  template <unsigned int VDimensions> class ImageBase;
-  class ImageIOBase;  
-  class GDCMSeriesFileNames;
-}
-
-/**
- * \class ImageInfoCallbackInterface
- * \brief A virtual class that is used to provide image-specific information to 
- * the ImageIOWizardLogic object 
- */
-class ImageInfoCallbackInterface
-{
-public:
-  virtual ~ImageInfoCallbackInterface() {}
-  virtual bool FindRegistryAssociatedWithImage(
-    const char *file, Registry &registry) = 0;
-
-  virtual void UpdateRegistryAssociatedWithImage(
-    const char *file, Registry &registry) = 0;
-};
-
-
-
-
-/**
- * \class ImageIOWizardLogic
- * The implementation of the Image IO Wizard UI class.  This class defines the
- * callbacks in the user interface for the class.  It is templated over the type
- * of the input that is to be procured.
- */
-class ImageIOWizardLogic : public ImageIOWizard 
-{
-public:
-  
-  // Image IO type definition
-  typedef itk::ImageIOBase ImageIOType;
-  typedef itk::SmartPointer<ImageIOType> ImageIOPointer;
-
-  // Other typedefs
-  typedef std::string StringType;
-  typedef std::vector<StringType> HistoryType;
-
-  /** A constructor */
-  ImageIOWizardLogic();
-
-  /** A descructor */
-  virtual ~ImageIOWizardLogic();
-
-  // Callback methods overridden from the Base class
-  virtual void OnCancel();
-  virtual void OnFilePageBrowse();
-  virtual void OnFilePageNext();
-  virtual void OnFilePageFileInputChange();
-  virtual void OnFilePageFileFormatChange();
-  virtual void OnFilePageFileHistoryChange();
-  virtual void OnHeaderPageNext();
-  virtual void OnHeaderPageBack();
-  virtual void OnHeaderPageInputChange();  
-  virtual void OnDICOMPageNext();
-  virtual void OnDICOMPageBack();
-  virtual void OnSummaryPageFinish();
-  virtual void OnSummaryPageBack();
-
-  // Functions called on entering wizard input pages
-  virtual void OnFilePageEnter();
-  virtual void OnHeaderPageEnter();
-  virtual void OnDICOMPageEnter();
-  virtual void OnSummaryPageEnter();
-
-  // Save related functions
-  virtual void OnSaveFilePageFileInputChange();
-  virtual void OnSaveFilePageFileFormatChange();
-  virtual void OnSaveFilePageFileHistoryChange();
-  virtual void OnSaveFilePageBrowse();
-  virtual void OnSaveFilePageSave();
-  virtual void OnSaveCancel();
-
-  // Custom initialization code
-  virtual void MakeWindow();
-
-  
-  /**
-   * Has the image been loaded successfully?
-   */
-  bool IsImageLoaded() 
-  {
-    return m_ImageLoaded;
-  }
-
-  /**
-   * Unload the image to free memory (do this after retrieving the image for 
-   * use elsewhere)
-   */
-  void ReleaseImage()
-  {
-    m_GuidedIO.DeallocateNativeImage();
-    m_ImageLoaded = false;
-  }
-
-  /**
-   * A method to initialize the pages in the wizard.  Child classes should override
-   * this and enable/disable irrelevant pages and fields.  The method takes as a 
-   * parameter an ImageWrapper, to which it makes changes.
-   *
-   * The method returns true if an image was loaded with success, false in case of cancellation
-   */
-  virtual bool DisplayInputWizard(const char *file, const char *type = NULL);
-
-  /**
-   * A method to save an image using the wizard (at this point it's just a one
-   * page wizard. This method is templated over the image type. This is a half-ass
-   * solution, but it's better than having the whole wizard templated over the image
-   * type. 
-   */
-  template<class TPixel> bool DisplaySaveWizard(
-    itk::OrientedImage<TPixel,3> *image, const char *file, const char *type = NULL)
-    {
-    m_SaveCallback = new TypedSaveCallback<TPixel>(this, image);
-    return DisplaySaveWizardImpl(file, type);
-    }
-
-  // Non-interactive wizard
-  virtual bool NonInteractiveInputWizard(const char *file);
-
-  /**
-   * Get the filename that was loaded
-   */
-  const char *GetFileName() 
-  {
-    return m_InFilePageBrowser->value();
-  }
-
-  /** Get the filename that was saved */
-  const char *GetSaveFileName()
-  {
-    return m_InSaveFilePageBrowser->value();
-  }
-
-  /** Set the history list of recently opened files */
-  void SetHistory(const HistoryType &history);
-
-  /** Set the callback object for retrieving historical information about
-   * previously loaded images */
-  void SetImageInfoCallback(ImageInfoCallbackInterface *iCallback)
-    { this->m_Callback = iCallback; }
-
-  /** Get the native image IO */
-  GuidedNativeImageIO *GetNativeImageIO()
-    { return &m_GuidedIO; }
-
-protected:
-
-  // Base class for save callback system.
-  class TypedSaveCallbackBase
-  {
-  public:
-    TypedSaveCallbackBase() {}
-    virtual ~TypedSaveCallbackBase() {}
-    virtual void Save(const char *fname, Registry &folder) = 0;
-  };
-
-  // Templated class for save callback system.
-  template<class TPixel> class TypedSaveCallback : public TypedSaveCallbackBase
-  {
-  public:
-    typedef itk::OrientedImage<TPixel, 3> ImageType;
-    TypedSaveCallback(ImageIOWizardLogic *client, ImageType *image)
-      : m_Client(client), m_Image(image) {}
-    void Save(const char *fname, Registry &folder)
-      { m_Client->GetNativeImageIO()->SaveImage(fname, folder, m_Image.GetPointer()); }
-  private:
-    ImageIOWizardLogic *m_Client;
-    typename ImageType::Pointer m_Image;
-  };
-
-  /** An image being loaded */
-  // ImagePointer m_Image;
-
-  /** The image IO mechanism */
-  // ImageIOPointer m_ImageIO;
-
-  /** Has the image been loaded? */
-  bool m_ImageLoaded;
-
-  /** Has the image been saved? */
-  bool m_ImageSaved;
-
-  /** A history of recently opened files */
-  HistoryType m_History;
-
-  /** A callback for retrieving image information */
-  ImageInfoCallbackInterface *m_Callback;
-
-  /** DICOM file names lister */
-  itk::SmartPointer<itk::GDCMSeriesFileNames> m_DICOMLister;
-
-  /** The registry associated with the image currently being considered for loading */
-  Registry m_Registry;
-
-  /** A guided image IO object used to load images */
-  GuidedNativeImageIO m_GuidedIO;
-
-  /** Text buffer for one of the summary widgets */
-  Fl_Text_Buffer *m_SummaryTextBuffer;
-
-  // -- Stuff dealing with file formats --
-  typedef GuidedNativeImageIO::FileFormat FileFormat;
-  typedef GuidedNativeImageIO::RawPixelType RawPixelType;
-
-  /** Extensions for different file formats */
-  StringType m_FileFormatPattern[GuidedNativeImageIO::FORMAT_COUNT];
-
-  /** Brief descriptions of different file formats */
-  StringType m_FileFormatDescription[GuidedNativeImageIO::FORMAT_COUNT];  
-  
-  /**
-   * Allow children to specify which file formats they can and can't save
-   */
-  virtual bool CanSaveFileFormat(FileFormat format) const; 
-
-  /**
-   * Allow children to specify which file formats they can and can't load
-   */
-  virtual bool CanLoadFileFormat(FileFormat format) const;
-
-  /**
-   * This method should return a string containing the patterns of files
-   * that this dialog is allowed to read
-   */
-  StringType GetFilePattern(bool forLoading);
-
-  /**
-   * This method checks which of the supported file formats matches a filename
-   * entered by the user
-   */
-  FileFormat DetermineFileFormatFromFileName(bool forLoading, 
-                                             const char *testFileName);
-
-  /**
-   * A method that controls how we propagate forward and back in the dialog.
-   * Fires an assertion if called from where you can't go back or forward.  Inactive
-   * pages are simply skipped.
-   */
-  void GoForward(Fl_Group *current = NULL);
-  void GoBack(Fl_Group *current = NULL);
-
-  // This is called to load the image with a possible custom IO for raw images
-  bool DoLoadImage();
-
-  // List files in the dicom directory
-  bool ProcessDICOMDirectory();
-
-  // Check image validity after the initial load
-  virtual bool CheckImageValidity() { return true; }
-
-  // Check if the image is valid
-  virtual bool CheckFinalValidity() 
-  {
-    return (m_GuidedIO.GetNativeImage());
-  }
-
-  // The body of the save method (not templated)
-  virtual bool DisplaySaveWizardImpl(const char *file, const char *type = NULL);
-    
-  TypedSaveCallbackBase *m_SaveCallback;
-};
-
-#endif // __ImageIOWizardLogic_h_
diff --git a/UserInterface/ImageIOWizard/RestrictedImageIOWizardLogic.cxx b/UserInterface/ImageIOWizard/RestrictedImageIOWizardLogic.cxx
deleted file mode 100755
index e4e10b9..0000000
--- a/UserInterface/ImageIOWizard/RestrictedImageIOWizardLogic.cxx
+++ /dev/null
@@ -1,165 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: RestrictedImageIOWizardLogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/14 16:21:04 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-
-#include "RestrictedImageIOWizardLogic.h"
-#include "FL/fl_ask.H"
-
-RestrictedImageIOWizardLogic
-::RestrictedImageIOWizardLogic()
-{
-  m_NumberOfComponentsRestriction = 0;
-  m_MainImage = 0;
-}
-
-bool
-RestrictedImageIOWizardLogic
-::DisplayInputWizard(const char *file, const char *type)
-{
-  // If there is no main image specified, the restriction is ignored
-  if(m_MainImage)
-    {
-    // Get the size and spacing of the main image
-    SizeType requiredSize = m_MainImage->GetBufferedRegion().GetSize();
-
-    const double *requiredSpacing = m_MainImage->GetSpacing().GetDataPointer();
-
-    // Prepare the header page of the wizard UI
-    this->m_InHeaderPageDimX->value(requiredSize[0]);
-    this->m_InHeaderPageDimY->value(requiredSize[1]);
-    this->m_InHeaderPageDimZ->value(requiredSize[2]);
-    this->m_InHeaderPageSpacingX->value(requiredSpacing[0]);
-    this->m_InHeaderPageSpacingY->value(requiredSpacing[1]);
-    this->m_InHeaderPageSpacingZ->value(requiredSpacing[2]);
-    }
-
-  // Call the parent's method
-  return Superclass::DisplayInputWizard(file, type);
-}
-
-bool
-RestrictedImageIOWizardLogic
-::CheckImageValidity()
-{
-  // Get the native image pointer
-  ImageBaseType *native = this->m_GuidedIO.GetNativeImage();
-
-  // If the main image is specified, compare size, origin, etc to it
-  if(m_MainImage)
-    {
-    // TODO: Move this code to IRISApplications and call from here and from
-    // command-line loading.
-    SizeType requiredSize = m_MainImage->GetBufferedRegion().GetSize();
-    SizeType loadedSize = native->GetBufferedRegion().GetSize();
-
-    // Check whether or not the image size matches the 'forced' image size
-    if(!(requiredSize == loadedSize))
-      {
-      // Bark at the user
-      fl_alert(
-        "The size of the image you are attempting to load does not match "
-        "the size of the main image already loaded.");
-
-      return false;
-      }
-
-    // Check if there is a discrepancy in the header fields. This will not
-    // preclude the user from loading the image, but it will generate a 
-    // warning, hopefully leading users to adopt more flexible file formats
-    bool match_spacing = true, match_origin = true, match_direction = true;
-    for(unsigned int i = 0; i < 3; i++)
-      {
-      if(m_MainImage->GetSpacing()[i] != native->GetSpacing()[i])
-        match_spacing = false;
-
-      if(m_MainImage->GetOrigin()[i] != native->GetOrigin()[i])
-        match_origin = false;
-
-      for(size_t j = 0; j < 3; j++)
-        {
-        double diff = fabs(m_MainImage->GetDirection()(i,j) - native->GetDirection()(i,j));
-        if(diff > 1.0e-4)
-          match_direction = false;
-        }
-      }
-
-    if(!match_spacing || !match_origin || !match_direction)
-      {
-      // Come up with a warning message
-      std::string object, verb;
-      if(!match_spacing && !match_origin && !match_direction)
-        { object = "spacing, origin and orientation"; }
-      else if (!match_spacing && !match_origin)
-        { object = "spacing and origin"; }
-      else if (!match_spacing && !match_direction)
-        { object = "spacing and orientation"; }
-      else if (!match_origin && !match_direction)
-        { object = "origin and orientation";}
-      else if (!match_spacing)
-        { object = "spacing"; }
-      else if (!match_direction)
-        { object = "orientation";}
-      else if (!match_origin)
-        { object = "origin"; }
-
-      // Create an alert box
-      fl_choice(
-        "There is a mismatch between the header of the image that you are\n"
-        "loading and the header of the main image currently open in SNAP.\n\n"
-        "The images have different %s. \n\n"
-        "SNAP will ignore the header information in the image you are loading.\n",
-        "Ok", NULL, NULL,
-        object.c_str());
-
-      // Make the header of the image match that of the main image
-      native->SetOrigin(m_MainImage->GetOrigin());
-      native->SetSpacing(m_MainImage->GetSpacing());
-      native->SetDirection(m_MainImage->GetDirection());
-      }
-    }
-
-  if(m_NumberOfComponentsRestriction > 0)
-    {
-    if(native->GetNumberOfComponentsPerPixel() != m_NumberOfComponentsRestriction)
-      {
-      fl_alert(
-        "The number of components per pixel (%d) in the image you are \n"
-        "attempting to load does not match the required number (%d).", 
-        (int) native->GetNumberOfComponentsPerPixel(),
-        (int) m_NumberOfComponentsRestriction); 
-      return false;
-      }
-    }
-  return true;
-}
diff --git a/UserInterface/ImageIOWizard/RestrictedImageIOWizardLogic.h b/UserInterface/ImageIOWizard/RestrictedImageIOWizardLogic.h
deleted file mode 100644
index f44152d..0000000
--- a/UserInterface/ImageIOWizard/RestrictedImageIOWizardLogic.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: RestrictedImageIOWizardLogic.h,v $
-  Language:  C++
-  Date:      $Date: 2009/07/22 21:06:24 $
-  Version:   $Revision: 1.6 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __RestrictedImageIOWizardLogic_h_
-#define __RestrictedImageIOWizardLogic_h_
-
-#include "ImageIOWizardLogic.h"
-#include "ImageWrapper.h"
-
-/**
- * \class RestrictedImageIOWizardLogic.h
- * \brief A wizard for loading and saving images whose size and spacing are 
- * restricted by another (in our case, greyscale) image
- */
-class RestrictedImageIOWizardLogic : public ImageIOWizardLogic
-{
-public:
-  typedef itk::ImageBase<3> ImageBaseType;
-  typedef ImageIOWizardLogic Superclass;
-  typedef itk::Size<3> SizeType;
-
-  /** Constructor */
-  RestrictedImageIOWizardLogic();
-
-  /** Some extra work is done before displaying the wizard in this method */
-  virtual bool DisplayInputWizard(const char *file, const char *type = NULL);
-
-  /** Set the main image that provides some metadata for loading the 
-   * segmentation image */
-  irisSetMacro(MainImage,ImageBaseType *);
-
-  /** Set a restriction on the number of components */
-  irisSetMacro(NumberOfComponentsRestriction, size_t);
-
-protected:
-
-  // Validity of the image is checked by comparing the image size to the
-  // size of the greyscale image
-  virtual bool CheckImageValidity();
-
-  // The image orientation is set to match the orientation of the source image
-  virtual void GuessImageOrientation() {};
-
-  // Restriction on the number of components
-  size_t m_NumberOfComponentsRestriction;
-
-
-private:
-  /** Main image template */
-  ImageBaseType *m_MainImage;
-};
-
-#endif
-
diff --git a/UserInterface/MainComponents/AppearanceDialogUI.fl b/UserInterface/MainComponents/AppearanceDialogUI.fl
deleted file mode 100644
index 20c1a07..0000000
--- a/UserInterface/MainComponents/AppearanceDialogUI.fl
+++ /dev/null
@@ -1,518 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0300 
-header_name {.h} 
-code_name {.cxx}
-class AppearanceDialogUI {open : AppearanceDialogUIBase
-} {
-  Function {MakeWindow()} {open
-  } {
-    Fl_Window m_WinDisplayOptions {
-      label {Display Options} open
-      xywh {410 378 420 415} type Double box PLASTIC_DOWN_BOX align 0
-      code0 {\#include "AppearanceDialogUIBase.h"}
-      code1 {\#include <FL/Fl_Color_Chooser.H>} non_modal visible
-    } {
-      Fl_Tabs {} {open
-        xywh {10 10 400 360} box PLASTIC_THIN_UP_BOX color 41 labelsize 12 align 0
-      } {
-        Fl_Group {} {
-          label General open selected
-          xywh {10 35 400 335} labelsize 12
-        } {
-          Fl_Check_Button m_ChkOptionsSliceThumbnailOn {
-            label {Show thumbnail when the slice does not fit in the window}
-            xywh {20 50 350 25} down_box DOWN_BOX value 1 labelsize 12
-          }
-          Fl_Group {} {open
-            xywh {30 70 355 55} box PLASTIC_DOWN_BOX
-          } {
-            Fl_Value_Input m_InOptionsSliceThumbnailPercent {
-              label {Thumbnail size, relative to slice (%): }
-              xywh {330 75 50 20} labelsize 11 minimum 5 maximum 100 step 5 value 30 textsize 11
-            }
-            Fl_Value_Input m_InOptionsSliceThumbnailMaxSize {
-              label {Maximum thumbnail size (pixels): }
-              xywh {330 100 50 20} labelsize 11 minimum 10 maximum 400 step 10 value 160 textsize 11
-            }
-          }
-          Fl_Check_Button m_ChkOptionsSliceLinkedZoom {
-            label {By default, use the same zoom in all slice views (linked zoom)}
-            xywh {20 160 375 25} down_box DOWN_BOX labelsize 12
-          }
-          Fl_Check_Button m_ChkOptionsSliceMultisessionZoom {
-            label {By default, synchronize zoom with other ITK-SNAP sessions}
-            xywh {20 180 375 25} down_box DOWN_BOX labelsize 12
-          }
-          Fl_Check_Button m_ChkOptionsSliceMultisessionPan {
-            label {By default, synchronize panning with other ITK-SNAP sessions}
-            xywh {20 200 375 25} down_box DOWN_BOX labelsize 12
-          }
-          Fl_Check_Button m_ChkOptionsFloatingPointWarning {
-            label {Issue warning when loading floating point images}
-            xywh {20 220 375 25} down_box DOWN_BOX labelsize 12
-          }
-          Fl_Check_Button m_ChkOptionsAutoCheckForUpdate {
-            label {Check if newer software version is available at startup}
-            xywh {20 240 375 25} down_box DOWN_BOX labelsize 12
-          }
-          Fl_Button {} {
-            label {&Apply}
-            callback {OnSliceDisplayApplyAction();}
-            xywh {260 335 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX shortcut 0x80061 color 181 labelfont 1 labelsize 12
-          }
-          Fl_Button {} {
-            label {&Reset}
-            callback {OnSliceDisplayResetAction()}
-            xywh {335 335 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX shortcut 0x80072 color 181 labelsize 12
-          }
-          Fl_Check_Button m_ChkOptionsHiddenFeatures {
-            label {Enable undocumented features (for developers only)}
-            xywh {20 275 375 25} down_box DOWN_BOX labelsize 12
-          }
-          Fl_Check_Button m_ChkOptionsSliceAutoPan {
-            label {Pan automatically when cursor is moved near window border}
-            xywh {20 140 375 25} down_box DOWN_BOX labelsize 12
-          }
-        }
-        Fl_Group {} {
-          label Layout open
-          xywh {10 35 400 335} labelsize 12 hide
-        } {
-          Fl_Group {} {
-            label {Available layouts:} open
-            xywh {190 85 205 85} box PLASTIC_DOWN_BOX labelsize 12 align 5
-          } {
-            Fl_Group {} {
-              xywh {195 90 195 75}
-            } {
-              Fl_Round_Button {m_BtnOptionsViews2D[0]} {
-                callback {this->OnSliceAnatomyOptionsChange(0);}
-                xywh {205 95 50 30} type Radio down_box ROUND_DOWN_BOX value 1 align 24 hotspot
-              }
-              Fl_Round_Button {m_BtnOptionsViews2D[1]} {
-                callback {this->OnSliceAnatomyOptionsChange(1);}
-                xywh {205 130 50 30} type Radio down_box ROUND_DOWN_BOX align 24
-              }
-              Fl_Round_Button {m_BtnOptionsViews2D[2]} {
-                callback {this->OnSliceAnatomyOptionsChange(2);}
-                xywh {270 95 50 30} type Radio down_box ROUND_DOWN_BOX align 24
-              }
-              Fl_Round_Button {m_BtnOptionsViews2D[3]} {
-                callback {this->OnSliceAnatomyOptionsChange(3);}
-                xywh {270 130 50 30} type Radio down_box ROUND_DOWN_BOX align 24
-              }
-              Fl_Round_Button {m_BtnOptionsViews2D[4]} {
-                callback {this->OnSliceAnatomyOptionsChange(4);}
-                xywh {335 95 50 30} type Radio down_box ROUND_DOWN_BOX align 24
-              }
-              Fl_Round_Button {m_BtnOptionsViews2D[5]} {
-                callback {this->OnSliceAnatomyOptionsChange(5);}
-                xywh {335 130 50 30} type Radio down_box ROUND_DOWN_BOX align 24
-              }
-            }
-            Fl_Group {} {
-              label A open
-              xywh {225 95 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label C open
-              xywh {240 110 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label S open
-              xywh {240 95 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label { } open
-              xywh {225 110 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label A open
-              xywh {225 130 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label C open
-              xywh {240 130 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label S open
-              xywh {240 145 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label { } open
-              xywh {225 145 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label S open
-              xywh {290 95 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label A open
-              xywh {305 95 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label C open
-              xywh {305 110 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label { } open
-              xywh {290 110 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label S open
-              xywh {290 130 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label C open
-              xywh {305 130 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label A open
-              xywh {305 145 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label { } open
-              xywh {290 145 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label C open
-              xywh {355 95 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label A open
-              xywh {370 95 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label S open
-              xywh {370 110 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label { } open
-              xywh {355 110 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label C open
-              xywh {355 130 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label S open
-              xywh {370 130 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label A open
-              xywh {370 145 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-            Fl_Group {} {
-              label { } open
-              xywh {355 145 15 15} box BORDER_BOX color 30 labelfont 1 labelsize 12 labelcolor 7 align 16
-            } {}
-          }
-          Fl_Group {} {
-            label {Additional options:} open
-            xywh {190 200 205 73} box PLASTIC_DOWN_BOX labelsize 12 align 5
-          } {
-            Fl_Check_Button m_ChkOptionsViews2DNoseLeft {
-              label {Display anterior to the left}
-              tooltip {Select whether patient's anterior is displayed to the left or to the right in the sagittal view.} xywh {200 208 175 18} down_box DOWN_BOX value 1 labelsize 12
-            }
-            Fl_Check_Button m_ChkOptionsViews2DRightIsLeft {
-              label {Patient right is screen left}
-              tooltip {Use this checkbox to switch between radiological and neurological conventions.} xywh {200 228 175 18} down_box DOWN_BOX value 1 labelsize 12
-            }
-            Fl_Check_Button m_ChkOptionsViews2DLinearInterpolation {
-              label {Use linear interpolation}
-              tooltip {By default, SNAP uses nearest neighbor interpolation to render the grey image. This makes voxel edges visible. Select this to use linear interpolation, which blurs voxel edges.} xywh {200 247 175 18} down_box DOWN_BOX labelsize 12
-            }
-          }
-          Fl_Group {} {
-            label {Current screen layout:}
-            xywh {20 85 155 168} box PLASTIC_DOWN_BOX labelsize 12 align 5
-          } {
-            Fl_Output {m_OutDisplayOptionsPanel[0]} {
-              label {2D View 1}
-              xywh {30 97 60 60} box BORDER_BOX color 30 selection_color 0 labelsize 11 align 2 textsize 12 textcolor 7
-            }
-            Fl_Output {m_OutDisplayOptionsPanel[1]} {
-              label {2D View 2}
-              xywh {105 97 60 60} box BORDER_BOX color 30 selection_color 0 labelsize 11 align 2 textsize 12 textcolor 7
-            }
-            Fl_Output {m_OutDisplayOptionsPanel[2]} {
-              label {2D View 3}
-              xywh {105 177 60 60} box BORDER_BOX color 30 selection_color 0 labelsize 11 align 2 textsize 12 textcolor 7
-            }
-            Fl_Output {} {
-              label {3D View}
-              xywh {30 177 60 60} box BORDER_BOX color 30 selection_color 0 labelsize 11 align 2 textsize 12 textcolor 7
-            }
-          }
-          Fl_Group {} {
-            label {2D View Layout:}
-            xywh {20 60 375 5} box ENGRAVED_FRAME labeltype EMBOSSED_LABEL align 5 hide
-          } {}
-          Fl_Button {} {
-            label {&Apply}
-            callback {OnScreenLayoutApplyAction();}
-            xywh {260 335 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX shortcut 0x80061 color 181 labelfont 1 labelsize 12
-          }
-          Fl_Button {} {
-            label {&Reset}
-            callback {OnScreenLayoutResetAction();}
-            xywh {335 335 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX shortcut 0x80072 color 181 labelsize 12
-          }
-        }
-        Fl_Group {} {
-          label Appearance open
-          xywh {10 35 400 335} labelsize 12 hide
-        } {
-          Fl_Choice m_InUIElement {
-            label {Select a user interface element to edit:}
-            callback {OnUIElementSelection(o->value())} open
-            xywh {25 75 370 25} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-          } {
-            MenuItem {} {
-              label {Anatomical coordinate markers}
-              xywh {20 20 100 20} labelsize 12
-            }
-            MenuItem {} {
-              label Crosshairs
-              xywh {0 0 100 20} labelsize 12
-            }
-            MenuItem {} {
-              label {Region of interest}
-              xywh {10 10 100 20} labelsize 12
-            }
-            MenuItem {} {
-              label {Paintbrush Outline}
-              xywh {10 10 100 20} labelsize 12
-            }
-            MenuItem {} {
-              label Rulers
-              xywh {20 20 100 20} labelsize 12
-            }
-            MenuItem {} {
-              label {Window background}
-              xywh {50 50 100 20} labelsize 12 divider
-            }
-            MenuItem {} {
-              label {3D window background}
-              xywh {50 50 100 20} labelsize 12
-            }
-            MenuItem {} {
-              label {3D window crosshairs}
-              xywh {20 20 100 20} labelsize 12
-            }
-            MenuItem {} {
-              label {3D window image cube}
-              xywh {30 30 100 20} labelsize 12
-            }
-            MenuItem {} {
-              label {3D window region of interest}
-              xywh {40 40 100 20} labelsize 12 divider
-            }
-            MenuItem {} {
-              label {Zoom thumbnail}
-              xywh {60 60 100 20} labelsize 12
-            }
-            MenuItem {} {
-              label {Zoom thumbnail crosshairs}
-              xywh {70 70 100 20} labelsize 12 divider
-            }
-            MenuItem {} {
-              label {Polygon outline (drawing mode)}
-              xywh {80 80 100 20} labelsize 12
-            }
-            MenuItem {} {
-              label {Polygon outline (edit mode)}
-              xywh {100 100 100 20} labelsize 12
-            }
-            MenuItem {} {
-              label {Polygon completion line}
-              xywh {90 90 100 20} labelsize 12
-            }
-          }
-          Fl_Group {} {open
-            xywh {25 110 370 215} box PLASTIC_DOWN_BOX
-          } {
-            Fl_Box m_InColorNormal {
-              label {Color in normal state:}
-              callback {OnUIElementUpdate()}
-              xywh {35 135 170 90} box BORDER_BOX labelsize 12 align 5
-              class Fl_Color_Chooser
-            }
-            Fl_Box m_InColorActive {
-              label {Color in active state:}
-              callback {OnUIElementUpdate()}
-              xywh {215 135 170 90} box BORDER_BOX labelsize 12 align 5 deactivate
-              class Fl_Color_Chooser
-            }
-            Fl_Value_Input m_InLineThickness {
-              label {Line thickness:}
-              callback {OnUIElementUpdate()}
-              xywh {155 235 45 25} labelsize 12 textsize 12 deactivate
-            }
-            Fl_Value_Input m_InFontSize {
-              label {Font size:}
-              callback {OnUIElementUpdate()}
-              xywh {155 295 45 25} labelsize 12 textsize 12 deactivate
-            }
-            Fl_Value_Input m_InDashSpacing {
-              label {Dash spacing}
-              callback {OnUIElementUpdate()}
-              xywh {155 265 45 25} labelsize 12 textsize 12 deactivate
-            }
-            Fl_Check_Button m_InVisible {
-              label Visible
-              callback {OnUIElementUpdate()}
-              xywh {215 235 60 20} down_box DOWN_BOX labelsize 12 deactivate
-            }
-            Fl_Check_Button m_InAlphaBlending {
-              label {Alpha blending}
-              callback {OnUIElementUpdate()}
-              xywh {275 235 105 20} down_box DOWN_BOX labelsize 12 deactivate
-            }
-          }
-          Fl_Button {} {
-            label {&Apply}
-            callback {OnElementAppearanceApplyAction();}
-            xywh {180 335 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX shortcut 0x80061 color 181 labelfont 1 labelsize 12
-          }
-          Fl_Button {} {
-            label {&Reset}
-            callback {OnElementAppearanceResetAction();}
-            tooltip {Restore the default settings for the
-current user interface element} xywh {255 335 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX shortcut 0x80072 color 181 labelsize 12
-          }
-          Fl_Button {} {
-            label {Reset All}
-            callback {OnElementAppearanceResetAllAction();}
-            tooltip {Restore the default settings for all
-user interface elements} xywh {330 335 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX shortcut 0x80072 color 181 labelsize 12
-          }
-          Fl_Check_Button m_ChkOptionsHideOverlays {
-            label {Hide all overlays}
-            callback {OnHideOverlaysAction()}
-            xywh {20 335 125 25} down_box DOWN_BOX labelsize 12
-          }
-        }
-        Fl_Group {} {
-          label {3D Rendering} open
-          xywh {10 35 400 335} labelsize 12 hide
-        } {
-          Fl_Group {} {
-            label {3D Rendering Options:}
-            xywh {20 60 375 5} box ENGRAVED_FRAME labeltype EMBOSSED_LABEL align 5 hide
-          } {}
-          Fl_Check_Button m_InUseGaussianSmoothing {
-            label {Gaussian Smoothing (slow, increases display quality)}
-            xywh {20 50 355 20} down_box DOWN_BOX value 1 color 0 selection_color 136 labelsize 12
-          }
-          Fl_Group {} {open
-            xywh {30 70 355 30} box PLASTIC_DOWN_BOX
-          } {
-            Fl_Value_Input m_InRenderOptionsGaussianError {
-              label {Max. approx. error:}
-              xywh {330 75 50 20} labelsize 11 value 0.05 textsize 11
-            }
-            Fl_Value_Input m_InRenderOptionsGaussianStandardDeviation {
-              label {Standard deviation (mm):}
-              xywh {165 75 50 20} labelsize 11 textsize 11
-            }
-          }
-          Fl_Check_Button m_InUseDecimate {
-            label {Decimate 3D mesh (reduces number of polygons)}
-            xywh {20 110 365 20} down_box DOWN_BOX value 1 selection_color 136 labelsize 12
-          }
-          Fl_Group {} {open
-            xywh {30 130 355 85} box PLASTIC_DOWN_BOX
-          } {
-            Fl_Value_Input m_InRenderOptionsDecimateReductions {
-              label {Target reductions:}
-              xywh {165 135 50 20} labelsize 11 textsize 11
-            }
-            Fl_Value_Input m_InRenderOptionsDecimateErrorIncrement {
-              label {Error increment:}
-              xywh {330 135 50 20} labelsize 11 textsize 11
-            }
-            Fl_Value_Input m_InRenderOptionsDecimateInitialError {
-              label {Initial error:}
-              xywh {165 155 50 20} labelsize 11 textsize 11
-            }
-            Fl_Value_Input m_InRenderOptionsDecimateAspectRatio {
-              label {Aspect ratio:}
-              xywh {330 155 50 20} labelsize 11 textsize 11
-            }
-            Fl_Value_Input m_InRenderOptionsDecimateIterations {
-              label {Maximum iterations:}
-              xywh {165 175 50 20} labelsize 11 minimum 1 maximum 10 step 1 value 1 textsize 11
-            }
-            Fl_Value_Input m_InRenderOptionsDecimateFeatureAngle {
-              label {Feature angle:}
-              xywh {330 175 50 20} labelsize 11 textsize 11
-            }
-            Fl_Check_Button m_InRenderOptionsDecimateTopology {
-              label {Preserve Topology}
-              xywh {250 195 135 20} down_box DOWN_BOX labelsize 11
-            }
-          }
-          Fl_Check_Button m_InUseMeshSmoothing {
-            label {Smoothen 3D mesh (slower, increases mesh quality)}
-            xywh {20 225 355 20} down_box DOWN_BOX value 1 selection_color 136 labelsize 12
-          }
-          Fl_Group {} {open
-            xywh {30 245 355 70} box PLASTIC_DOWN_BOX
-          } {
-            Fl_Value_Input m_InRenderOptionsMeshSmoothConvergence {
-              label {Convergence:}
-              xywh {165 250 50 20} labelsize 11 textsize 11
-            }
-            Fl_Value_Input m_InRenderOptionsMeshSmoothFeatureAngle {
-              label {Feature angle:}
-              xywh {330 250 50 20} labelsize 11 textsize 11
-            }
-            Fl_Value_Input m_InRenderOptionsMeshSmoothRelaxation {
-              label {Relaxation:}
-              xywh {330 270 50 20} labelsize 11 textsize 11
-            }
-            Fl_Check_Button m_InRenderOptionsMeshSmoothFeatureEdge {
-              label {Feature Edge Smoothing}
-              xywh {105 295 140 20} down_box DOWN_BOX labelsize 11
-            }
-            Fl_Check_Button m_InRenderOptionsMeshSmoothBoundarySmoothing {
-              label {Boundary Smoothing}
-              xywh {250 295 135 20} down_box DOWN_BOX labelsize 11
-            }
-            Fl_Value_Input m_InRenderOptionsMeshSmoothIterations {
-              label {Iterations:}
-              xywh {165 270 50 20} labelsize 11 textsize 11
-            }
-          }
-          Fl_Button {} {
-            label {&Apply}
-            callback {On3DRenderingApplyAction();}
-            xywh {260 335 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX shortcut 0x80061 color 181 labelfont 1 labelsize 12
-          }
-          Fl_Button {} {
-            label {&Reset}
-            callback {On3DRenderingResetAction();}
-            xywh {335 335 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX shortcut 0x80072 color 181 labelsize 12
-          }
-        }
-      }
-      Fl_Button {} {
-        label Close
-        callback {this->OnCloseAction();}
-        xywh {105 380 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-      Fl_Button {} {
-        label {Export...}
-        callback {this->OnExportAction();}
-        tooltip {Save display options to a file, allowing you to load it later or to send it to another ITK-SNAP user.} xywh {180 380 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-      Fl_Button {} {
-        label {Import...}
-        callback {this->OnImportAction();}
-        tooltip {Load ITK-SNAP display options from a file.} xywh {255 380 65 25} box PLASTIC_UP_BOX down_box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-    }
-  }
-} 
diff --git a/UserInterface/MainComponents/AppearanceDialogUIBase.h b/UserInterface/MainComponents/AppearanceDialogUIBase.h
deleted file mode 100644
index c71298f..0000000
--- a/UserInterface/MainComponents/AppearanceDialogUIBase.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: AppearanceDialogUIBase.h,v $
-  Language:  C++
-  Date:      $Date: 2010/10/09 04:20:08 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __AppearanceDialogUIBase_h_
-#define __AppearanceDialogUIBase_h_
-
-class AppearanceDialogUIBase
-{
-public:
-  virtual ~AppearanceDialogUIBase() {}
-  virtual void OnUIElementUpdate() = 0;
-  virtual void OnUIElementSelection(int value) = 0;
-  virtual void OnSliceAnatomyOptionsChange(unsigned int order) = 0;
-  virtual void OnCloseAction() = 0;
-  virtual void OnExportAction() = 0;
-  virtual void OnImportAction() = 0;
-
-  virtual void OnSliceDisplayApplyAction() = 0;
-  virtual void OnSliceDisplayResetAction() = 0;
-  virtual void OnScreenLayoutApplyAction() = 0;
-  virtual void OnScreenLayoutResetAction() = 0;
-  virtual void On3DRenderingApplyAction() = 0;
-  virtual void On3DRenderingResetAction() = 0;
-  virtual void OnElementAppearanceResetAllAction() = 0;
-  virtual void OnElementAppearanceResetAction() = 0;
-  virtual void OnElementAppearanceApplyAction() = 0;
-
-  virtual void OnOptionsExternalUpdate() = 0;
-  virtual void OnHideOverlaysAction() = 0;
-};
-
-#endif
-
diff --git a/UserInterface/MainComponents/AppearanceDialogUILogic.cxx b/UserInterface/MainComponents/AppearanceDialogUILogic.cxx
deleted file mode 100644
index 28a31cc..0000000
--- a/UserInterface/MainComponents/AppearanceDialogUILogic.cxx
+++ /dev/null
@@ -1,683 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: AppearanceDialogUILogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/19 20:28:56 $
-  Version:   $Revision: 1.14 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "AppearanceDialogUILogic.h"
-#include "SNAPAppearanceSettings.h"
-#include "UserInterfaceBase.h"
-#include "GlobalState.h"
-#include "IRISApplication.h"
-#include "SystemInterface.h"
-#include "FL/Fl_Native_File_Chooser.H"
-#include "FL/fl_ask.H"
-#include <string>
-
-using namespace std;
-
-const int
-AppearanceDialogUILogic
-::m_MapMenuToElementIndex[] = 
-  { 
-    SNAPAppearanceSettings::MARKERS,
-    SNAPAppearanceSettings::CROSSHAIRS,
-    SNAPAppearanceSettings::ROI_BOX,
-    SNAPAppearanceSettings::PAINTBRUSH_OUTLINE,
-    SNAPAppearanceSettings::RULER,
-    SNAPAppearanceSettings::BACKGROUND_2D,
-    SNAPAppearanceSettings::BACKGROUND_3D,
-    SNAPAppearanceSettings::CROSSHAIRS_3D,
-    SNAPAppearanceSettings::IMAGE_BOX_3D,
-    SNAPAppearanceSettings::ROI_BOX_3D,
-    SNAPAppearanceSettings::ZOOM_THUMBNAIL,
-    SNAPAppearanceSettings::CROSSHAIRS_THUMB,
-    SNAPAppearanceSettings::POLY_DRAW_MAIN,
-    SNAPAppearanceSettings::POLY_EDIT,
-    SNAPAppearanceSettings::POLY_DRAW_CLOSE
-  };
-
-AppearanceDialogUILogic
-::AppearanceDialogUILogic()
-{
-  m_DefaultAppearance = new SNAPAppearanceSettings();
-}
-
-AppearanceDialogUILogic
-::~AppearanceDialogUILogic()
-{
-  delete m_DefaultAppearance;
-}
-
-void
-AppearanceDialogUILogic
-::Register(UserInterfaceBase *parent) 
-{
-  m_Parent = parent;
-  m_Appearance = parent->GetAppearanceSettings();
-  m_GlobalState = parent->GetDriver()->GetGlobalState();
-} 
-
-// Close callbacks
-void  
-AppearanceDialogUILogic
-::OnCloseAction()
-{
-  m_WinDisplayOptions->hide();
-}
-
-void
-AppearanceDialogUILogic
-::OnExportAction()
-{
-  // Prompt for the filename
-  Fl_Native_File_Chooser chooser;
-  chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
-  chooser.title("Export Display Options to .txt file");
-  chooser.filter("Text Files\t*.txt");
-  // chooser.directory(...)
-  chooser.preset_file("itksnap_dispopts.txt");
-  const char *fChosen = NULL;
-  if (chooser.show() == 0)
-    fChosen = chooser.filename();
-
-  if(fChosen)
-    {
-    Registry reg;
-    m_Appearance->SaveToRegistry(reg.Folder("UserInterface.AppearanceSettings"));
-    reg.WriteToFile(fChosen);
-    }
-}
-
-void
-AppearanceDialogUILogic
-::OnImportAction()
-{
-  // Prompt for the filename
-  Fl_Native_File_Chooser chooser;
-  chooser.type(Fl_Native_File_Chooser::BROWSE_FILE);
-  chooser.title("Import Display Options from .txt file");
-  chooser.filter("Text Files\t*.txt");
-  // chooser.directory(...)
-  chooser.preset_file("itksnap_dispopts.txt");
-  const char *fChosen = NULL;
-  if (chooser.show() == 0)
-    fChosen = chooser.filename();
-
-  if(fChosen)
-    {
-    try 
-      {
-      Registry reg(fChosen);
-      m_Appearance->LoadFromRegistry(reg.Folder("UserInterface.AppearanceSettings"));
-
-      // Redraw the current control
-      OnUIElementSelection(m_InUIElement->value());
-
-      // Redraw the windows
-      m_Parent->RedrawWindows();
-
-      // Place the options in the registry
-      m_Appearance->SaveToRegistry(
-        m_Parent->GetSystemInterface()->Folder("UserInterface.AppearanceSettings"));  
-      }
-    catch(Registry::IOException &exc)
-      {
-      fl_alert("Unable to open settings file: %s", exc.c_str());
-      }
-    catch(Registry::SyntaxException &exc)
-      {
-      fl_alert("Unable to parse settings: %s", exc.c_str());
-      }
-    }
-}
-
-// General slice options
-void  
-AppearanceDialogUILogic
-::OnSliceDisplayApplyAction()
-{
-  // Store the appearance options
-  m_Appearance->SetFlagDisplayZoomThumbnail(
-    m_ChkOptionsSliceThumbnailOn->value() != 0);
-  
-  m_Appearance->SetFlagAutoPan(
-    m_ChkOptionsSliceAutoPan->value() != 0);
-  
-  m_Appearance->SetFlagLinkedZoomByDefault(
-    m_ChkOptionsSliceLinkedZoom->value() != 0);
-  
-  m_Appearance->SetFlagMultisessionZoomByDefault(
-    m_ChkOptionsSliceMultisessionZoom->value() != 0);
-  
-  m_Appearance->SetFlagMultisessionPanByDefault(
-    m_ChkOptionsSliceMultisessionPan->value() != 0);
-  
-  m_Appearance->SetFlagFloatingPointWarningByDefault(
-    m_ChkOptionsFloatingPointWarning->value() != 0);
-  
-  m_Appearance->SetFlagEnableAutoCheckForUpdateByDefault(
-    m_ChkOptionsAutoCheckForUpdate->value() != 0);
-
-  m_Appearance->SetFlagEnableHiddenFeaturesByDefault(
-    m_ChkOptionsHiddenFeatures->value() != 0);
-
-  m_Appearance->SetZoomThumbnailSizeInPercent(
-    m_InOptionsSliceThumbnailPercent->value());
-  
-  m_Appearance->SetZoomThumbnailMaximumSize(
-    (int) m_InOptionsSliceThumbnailMaxSize->value());
-
-  // Place the options in the registry
-  m_Appearance->SaveToRegistry(
-    m_Parent->GetSystemInterface()->Folder("UserInterface.AppearanceSettings")); 
-  // Handle the hidden features button
-  m_Parent->OnHiddenFeaturesToggleAction();
-
-  // Redraw the UI windows
-  m_Parent->RedrawWindows();
-}
-
-void  
-AppearanceDialogUILogic
-::OnSliceDisplayResetAction()
-{
-  // Restore the appearance options
-  m_Appearance->SetFlagDisplayZoomThumbnail(
-    m_DefaultAppearance->GetFlagDisplayZoomThumbnail());
-  
-  m_Appearance->SetFlagLinkedZoomByDefault(
-    m_DefaultAppearance->GetFlagLinkedZoomByDefault());
-  
-  m_Appearance->SetFlagMultisessionZoomByDefault(
-    m_DefaultAppearance->GetFlagMultisessionZoomByDefault());
-  
-  m_Appearance->SetFlagMultisessionPanByDefault(
-    m_DefaultAppearance->GetFlagMultisessionPanByDefault());
-  
-  m_Appearance->SetFlagFloatingPointWarningByDefault(
-    m_DefaultAppearance->GetFlagFloatingPointWarningByDefault());
-  
-  m_Appearance->SetFlagEnableHiddenFeaturesByDefault(
-    m_DefaultAppearance->GetFlagEnableHiddenFeaturesByDefault());
-  
-  m_Appearance->SetFlagAutoPan(
-    m_DefaultAppearance->GetFlagAutoPan());
-  
-  m_Appearance->SetZoomThumbnailSizeInPercent(
-    m_DefaultAppearance->GetZoomThumbnailSizeInPercent());
-  
-  m_Appearance->SetZoomThumbnailMaximumSize(
-    m_DefaultAppearance->GetZoomThumbnailMaximumSize());
-
-  // Place the options in the registry
-  m_Appearance->SaveToRegistry(
-    m_Parent->GetSystemInterface()->Folder("UserInterface.AppearanceSettings"));  
-  // Redraw the UI windows
-  m_Parent->RedrawWindows();
-
-  // Refill the options
-  FillAppearanceSettings();
-}
-
-// View arrangement callbacks
-void  
-AppearanceDialogUILogic
-::OnScreenLayoutApplyAction()
-{
-  // Search for the selected orientation toggle
-  unsigned int i;
-  for(i=0;i<6;i++)
-    if(m_BtnOptionsViews2D[i]->value())
-      break;
-
-  // Make sure something is selected
-  if(i == 6) return;
-
-  // Update the selected layout
-  m_Appearance->SetSliceLayout(
-    (SNAPAppearanceSettings::UISliceLayout) i);
-  m_Appearance->SetFlagLayoutPatientAnteriorShownLeft(
-    m_ChkOptionsViews2DNoseLeft->value() == 0 ? false : true);
-  m_Appearance->SetFlagLayoutPatientRightShownLeft(
-    m_ChkOptionsViews2DRightIsLeft->value() == 0 ? false : true);
-
-  // Finally handle the linear interpolation option
-  m_Appearance->SetGreyInterpolationMode(
-    m_ChkOptionsViews2DLinearInterpolation->value() ? 
-    SNAPAppearanceSettings::LINEAR : SNAPAppearanceSettings::NEAREST);
-
-  // Place the options in the registry
-  m_Appearance->SaveToRegistry(
-    m_Parent->GetSystemInterface()->Folder("UserInterface.AppearanceSettings"));  
-
-  // Get the RAI codes
-  string rai[3];
-  m_Appearance->GetAnatomyToDisplayTransforms(rai[0], rai[1], rai[2]);
-
-  // Update geometry only if one of these three RAIs is different from the current
-  for(size_t j = 0; j < 3; j++)
-    if(m_Parent->GetDriver()->GetDisplayToAnatomyRAI(j) != rai[j])
-      {
-      m_Parent->GetDriver()->SetDisplayToAnatomyRAI(
-        rai[0].c_str(), rai[1].c_str(), rai[2].c_str());
-      m_Parent->OnImageGeometryUpdate();
-      break;
-      }
-
-  // Update the user interface
-  m_Parent->RedrawWindows();
-}
-
-void  
-AppearanceDialogUILogic
-::OnScreenLayoutResetAction()
-{
-  for(size_t i=0; i < 6; i++)
-    m_BtnOptionsViews2D[i]->value(i==0 ? 1 : 0);
-  m_ChkOptionsViews2DNoseLeft->value(1);
-  m_ChkOptionsViews2DRightIsLeft->value(1);
-  m_ChkOptionsViews2DLinearInterpolation->value(0);
-  OnSliceAnatomyOptionsChange(0);
-  OnScreenLayoutApplyAction();  
-}
-
-void  
-AppearanceDialogUILogic
-::OnSliceAnatomyOptionsChange(unsigned int order)
-{
-  // Depending on the order, put appropriate text
-  const char *axial = "Axial", *coronal = "Coronal", *sagittal = "Sagittal";
-  const char *v1=NULL, *v2=NULL, *v3=NULL;
-  switch(order)
-    {
-    case SNAPAppearanceSettings::LAYOUT_ACS:
-      v1 = axial; v2 = coronal; v3 = sagittal; break;
-    case SNAPAppearanceSettings::LAYOUT_ASC:
-      v1 = axial; v2 = sagittal; v3 = coronal; break;
-    case SNAPAppearanceSettings::LAYOUT_CAS:
-      v1 = coronal; v2 = axial; v3 = sagittal; break;
-    case SNAPAppearanceSettings::LAYOUT_CSA:
-      v1 = coronal; v2 = sagittal; v3 = axial; break;
-    case SNAPAppearanceSettings::LAYOUT_SAC:
-      v1 = sagittal; v2 = axial; v3 = coronal; break;
-    case SNAPAppearanceSettings::LAYOUT_SCA:
-      v1 = sagittal; v2 = coronal; v3 = axial; break;
-    };
-
-  // Place the text in the boxes
-  m_OutDisplayOptionsPanel[0]->value(v1);
-  m_OutDisplayOptionsPanel[1]->value(v2);
-  m_OutDisplayOptionsPanel[2]->value(v3);
-}
-
-// 3D Rendering callbacks
-void  
-AppearanceDialogUILogic
-::On3DRenderingApplyAction()
-{
-  // Get the current mesh options
-  MeshOptions mops;
-
-  // Set the Gaussian properties
-  mops.SetGaussianStandardDeviation(
-    m_InRenderOptionsGaussianStandardDeviation->value());
-  mops.SetUseGaussianSmoothing(
-    m_InUseGaussianSmoothing->value());
-  mops.SetGaussianError(
-    m_InRenderOptionsGaussianError->value());
-
-  // Triangle Decimation
-  mops.SetUseDecimation(
-    m_InUseDecimate->value());
-  mops.SetDecimateAspectRatio(
-    m_InRenderOptionsDecimateAspectRatio->value());
-  mops.SetDecimateErrorIncrement(
-    m_InRenderOptionsDecimateErrorIncrement->value());
-  mops.SetDecimateFeatureAngle(
-    m_InRenderOptionsDecimateFeatureAngle->value());
-  mops.SetDecimateInitialError(
-    m_InRenderOptionsDecimateInitialError->value());
-  mops.SetDecimateMaximumIterations(
-    (unsigned int)m_InRenderOptionsDecimateIterations->value());
-  mops.SetDecimatePreserveTopology(
-    m_InRenderOptionsDecimateTopology->value());
-  mops.SetDecimateTargetReduction(
-    m_InRenderOptionsDecimateReductions->value());
-
-  // Mesh Smoothing
-  mops.SetUseMeshSmoothing(
-    m_InUseMeshSmoothing->value());  
-  mops.SetMeshSmoothingBoundarySmoothing(
-    m_InRenderOptionsMeshSmoothBoundarySmoothing->value());
-  mops.SetMeshSmoothingConvergence(
-    m_InRenderOptionsMeshSmoothConvergence->value());
-  mops.SetMeshSmoothingFeatureAngle(
-    m_InRenderOptionsMeshSmoothFeatureAngle->value());
-  mops.SetMeshSmoothingFeatureEdgeSmoothing(
-    m_InRenderOptionsMeshSmoothFeatureEdge->value());
-  mops.SetMeshSmoothingIterations(
-    (unsigned int)m_InRenderOptionsMeshSmoothIterations->value());
-  mops.SetMeshSmoothingRelaxationFactor(
-    m_InRenderOptionsMeshSmoothRelaxation->value());
-
-  // Save the mesh options
-  m_GlobalState->SetMeshOptions(mops); 
-  
-  // Enable the update button on the 3D window
-  m_Parent->OnIRISMeshDisplaySettingsUpdate();
-}
-
-void  
-AppearanceDialogUILogic
-::On3DRenderingResetAction()
-{
-  // Reset the options in the system to defaults
-  MeshOptions mops;
-  m_GlobalState->SetMeshOptions(mops);
-
-  // Refill the options
-  FillRenderingOptions();
-}
-
-// Element appearance callbacks
-void  
-AppearanceDialogUILogic
-::OnUIElementUpdate()
-{
-  // Nothing for now
-}
-
-void  
-AppearanceDialogUILogic
-::OnUIElementSelection(int value)
-{
-  // Must have a value!
-  if(value < 0) return;
-
-  // Find out the which element was selected
-  int iElement = m_MapMenuToElementIndex[value];
-
-  // Make sure a legit element was found
-  if(iElement == SNAPAppearanceSettings::ELEMENT_COUNT)
-    return;
-
-  // Set the user interface properties 
-  SNAPAppearanceSettings::Element &e = m_Appearance->GetUIElement(iElement);
-  m_InColorNormal->rgb( e.NormalColor[0], e.NormalColor[1], e.NormalColor[2] );
-  m_InColorActive->rgb( e.ActiveColor[0], e.ActiveColor[1], e.ActiveColor[2] );
-  m_InLineThickness->value( e.LineThickness ); 
-  m_InDashSpacing->value( e.DashSpacing ); 
-  m_InFontSize->value( e.FontSize ); 
-  m_InVisible->value( e.Visible );
-  m_InAlphaBlending->value( e.AlphaBlending );
-
-  // Create an array of widgets for cleaner code
-  Fl_Widget *w[] = 
-    { m_InColorNormal, m_InColorActive, m_InLineThickness,
-      m_InDashSpacing, m_InFontSize, m_InVisible, m_InAlphaBlending };
-
-  // Set the active/inactive status
-  for(unsigned int iWidget = 0; iWidget < SNAPAppearanceSettings::FEATURE_COUNT; iWidget++)
-    {
-    if(m_Appearance->IsFeatureApplicable(iElement, iWidget))
-      {
-      w[iWidget]->activate();
-      if(iWidget < 2) w[iWidget]->show();
-      }
-    else
-      {
-      w[iWidget]->deactivate();
-      if(iWidget < 2) w[iWidget]->hide();
-      }
-    }  
-}
-
-void  
-AppearanceDialogUILogic
-::OnElementAppearanceResetAllAction()
-{
-  // Reset each element
-  for(unsigned int i = 0; i < SNAPAppearanceSettings::ELEMENT_COUNT; i++)
-    m_Appearance->SetUIElement(i,m_DefaultAppearance->GetUIElement(i));
-
-  // Redraw the current control
-  OnUIElementSelection(m_InUIElement->value());
-
-  // Redraw the windows
-  m_Parent->RedrawWindows();
-  
-  // Place the options in the registry
-  m_Appearance->SaveToRegistry(
-    m_Parent->GetSystemInterface()->Folder("UserInterface.AppearanceSettings"));  
-}
-
-void  
-AppearanceDialogUILogic
-::OnElementAppearanceResetAction()
-{
-  // Must have a value!
-  if(m_InUIElement->value() < 0) return;
-
-  // Find out the which element was selected
-  int iElement = m_MapMenuToElementIndex[m_InUIElement->value()];
-
-  // Make sure a legit element was found
-  if(iElement == SNAPAppearanceSettings::ELEMENT_COUNT)
-    return;
-
-  // Reset the element
-  m_Appearance->SetUIElement(
-    iElement,m_DefaultAppearance->GetUIElement(iElement));
-
-  // Redraw the controls
-  OnUIElementSelection(m_InUIElement->value());
-
-  // Redraw the windows
-  m_Parent->RedrawWindows();
-  
-  // Place the options in the registry
-  m_Appearance->SaveToRegistry(
-    m_Parent->GetSystemInterface()->Folder("UserInterface.AppearanceSettings"));  
-}
-
-void  
-AppearanceDialogUILogic
-::OnElementAppearanceApplyAction()
-{
-  // Must have a value!
-  if(m_InUIElement->value() < 0) return;
-
-  // Find out the which element was selected
-  int iElement = m_MapMenuToElementIndex[m_InUIElement->value()];
-
-  // Make sure a legit element was found
-  if(iElement == SNAPAppearanceSettings::ELEMENT_COUNT)
-    return;
-
-  // Set the element's properties
-  SNAPAppearanceSettings::Element &e = m_Appearance->GetUIElement(iElement);
-  e.NormalColor[0] = (float) m_InColorNormal->r();
-  e.NormalColor[1] = (float) m_InColorNormal->g();
-  e.NormalColor[2] = (float) m_InColorNormal->b();
-  e.ActiveColor[0] = (float) m_InColorActive->r();
-  e.ActiveColor[1] = (float) m_InColorActive->g();
-  e.ActiveColor[2] = (float) m_InColorActive->b();
-  e.LineThickness = (float) m_InLineThickness->value();
-  e.DashSpacing = (float) m_InDashSpacing->value();
-  e.FontSize = (int) m_InFontSize->value();
-  e.AlphaBlending = m_InAlphaBlending->value() != 0;
-  e.Visible = m_InVisible->value() != 0;
-  
-  // Redraw the windows
-  m_Parent->RedrawWindows();
-  
-  // Place the options in the registry
-  m_Appearance->SaveToRegistry(
-    m_Parent->GetSystemInterface()->Folder("UserInterface.AppearanceSettings"));  
-}
-
-void 
-AppearanceDialogUILogic
-::ShowDialog()
-{
-  // Reset to options
-  OnOptionsExternalUpdate();
-
-  // Show the dialog
-  m_WinDisplayOptions->show();
-}
-
-void
-AppearanceDialogUILogic
-::OnOptionsExternalUpdate()
-{
-  // Fill out the panels of the dialog
-  FillAppearanceSettings();
-  FillSliceLayoutOptions();
-  FillRenderingOptions();
-
-  // Describe the currently selected UI element
-  OnUIElementSelection( m_InUIElement->value() );
-}
-
-void 
-AppearanceDialogUILogic
-::FillRenderingOptions() 
-{
-  // Get the current mesh options
-  MeshOptions mops = m_GlobalState->GetMeshOptions();
-
-  // Set the Gaussian properties
-  m_InRenderOptionsGaussianStandardDeviation->value(
-    mops.GetGaussianStandardDeviation());
-  m_InUseGaussianSmoothing->value(
-    mops.GetUseGaussianSmoothing());
-  m_InRenderOptionsGaussianError->value(
-    mops.GetGaussianError());
-
-  // Triangle Decimation
-  m_InUseDecimate->value(
-    mops.GetUseDecimation());
-  m_InRenderOptionsDecimateAspectRatio->value(
-    mops.GetDecimateAspectRatio());
-  m_InRenderOptionsDecimateErrorIncrement->value(
-    mops.GetDecimateErrorIncrement());
-  m_InRenderOptionsDecimateFeatureAngle->value(
-    mops.GetDecimateFeatureAngle());
-  m_InRenderOptionsDecimateInitialError->value(
-    mops.GetDecimateInitialError());
-  m_InRenderOptionsDecimateIterations->value(
-    (double)mops.GetDecimateMaximumIterations());
-  m_InRenderOptionsDecimateTopology->value(
-    mops.GetDecimatePreserveTopology());
-  m_InRenderOptionsDecimateReductions->value(
-    mops.GetDecimateTargetReduction());
-
-  // Mesh Smoothing
-  m_InUseMeshSmoothing->value(
-    mops.GetUseMeshSmoothing());  
-  m_InRenderOptionsMeshSmoothBoundarySmoothing->value(
-    mops.GetMeshSmoothingBoundarySmoothing());
-  m_InRenderOptionsMeshSmoothConvergence->value(
-    mops.GetMeshSmoothingConvergence());
-  m_InRenderOptionsMeshSmoothFeatureAngle->value(
-    mops.GetMeshSmoothingFeatureAngle());
-  m_InRenderOptionsMeshSmoothFeatureEdge->value(
-    mops.GetMeshSmoothingFeatureEdgeSmoothing());
-  m_InRenderOptionsMeshSmoothIterations->value(
-    (double)mops.GetMeshSmoothingIterations());
-  m_InRenderOptionsMeshSmoothRelaxation->value(
-    mops.GetMeshSmoothingRelaxationFactor());
-}
-
-void 
-AppearanceDialogUILogic
-::FillSliceLayoutOptions() 
-{
-  // Select the appropriate display layout
-  size_t layout_index = (size_t ) m_Appearance->GetSliceLayout();
-  for(size_t i = 0; i < 6; i++)
-    m_BtnOptionsViews2D[i]->value(i == layout_index ? 1 : 0);
-
-  // Set the checkbox values accordingly
-  m_ChkOptionsViews2DNoseLeft->value(
-    m_Appearance->GetFlagLayoutPatientAnteriorShownLeft() ? 1 : 0);
-  m_ChkOptionsViews2DRightIsLeft->value(
-    m_Appearance->GetFlagLayoutPatientRightShownLeft() ? 1 : 0);
-  m_ChkOptionsViews2DLinearInterpolation->value(
-    m_Appearance->GetGreyInterpolationMode() == SNAPAppearanceSettings::LINEAR
-    ? 1 : 0);
-
-  // Update the display as if the user changed it
-  OnSliceAnatomyOptionsChange(layout_index);  
-}
-
-void 
-AppearanceDialogUILogic
-::FillAppearanceSettings()
-{
-  // Propagate the settings to the controls 
-  m_ChkOptionsSliceThumbnailOn->value(
-    m_Appearance->GetFlagDisplayZoomThumbnail() ? 1 : 0);
-  m_ChkOptionsSliceAutoPan->value(
-    m_Appearance->GetFlagAutoPan() ? 1 : 0);
-  m_ChkOptionsSliceLinkedZoom->value(
-    m_Appearance->GetFlagLinkedZoomByDefault() ? 1 : 0);
-  m_ChkOptionsSliceMultisessionZoom->value(
-    m_Appearance->GetFlagMultisessionZoomByDefault() ? 1 : 0);
-  m_ChkOptionsSliceMultisessionPan->value(
-    m_Appearance->GetFlagMultisessionPanByDefault() ? 1 : 0);
-  m_ChkOptionsFloatingPointWarning->value(
-    m_Appearance->GetFlagFloatingPointWarningByDefault() ? 1 : 0);
-  m_ChkOptionsAutoCheckForUpdate->value(
-    m_Appearance->GetFlagEnableAutoCheckForUpdateByDefault() ? 1 : 0);
-  m_ChkOptionsHiddenFeatures->value(
-    m_Appearance->GetFlagEnableHiddenFeaturesByDefault() ? 1 : 0);
-  m_InOptionsSliceThumbnailPercent->value(
-    m_Appearance->GetZoomThumbnailSizeInPercent());
-  m_InOptionsSliceThumbnailMaxSize->value(
-    (double) m_Appearance->GetZoomThumbnailMaximumSize());
-
-  // Overall visibility
-  m_ChkOptionsHideOverlays->value(
-    m_Appearance->GetOverallVisibility() ? 0 : 1);
-}
-
-void
-AppearanceDialogUILogic
-::OnHideOverlaysAction()
-{
-  m_Appearance->SetOverallVisibility(
-    m_ChkOptionsHideOverlays->value() > 0 ? false : true);
-  
-  m_Parent->RedrawWindows();
-}
diff --git a/UserInterface/MainComponents/AppearanceDialogUILogic.h b/UserInterface/MainComponents/AppearanceDialogUILogic.h
deleted file mode 100644
index 6f0d8f3..0000000
--- a/UserInterface/MainComponents/AppearanceDialogUILogic.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: AppearanceDialogUILogic.h,v $
-  Language:  C++
-  Date:      $Date: 2010/10/09 04:20:08 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __AppearanceDialogUILogic_h_
-#define __AppearanceDialogUILogic_h_
-
-#if defined(_MSC_VER)
-#pragma warning ( disable : 4786 )
-#endif
-
-#include "AppearanceDialogUI.h"
-
-class UserInterfaceBase;
-class SNAPAppearanceSettings;
-class GlobalState;
-
-class AppearanceDialogUILogic : public AppearanceDialogUI
-{
-public:
-  AppearanceDialogUILogic();
-  virtual ~AppearanceDialogUILogic();
-
-  void Register( UserInterfaceBase *parent );
-
-  /* Show the dialog */
-  void ShowDialog();
-  
-  // Close callbacks
-  void OnCloseAction() ;
-
-  // Import/export
-  void OnImportAction();
-  void OnExportAction();
-
-  // General slice options
-  void OnSliceDisplayApplyAction();
-  void OnSliceDisplayResetAction();
-
-  // View arrangement callbacks
-  void OnScreenLayoutApplyAction();
-  void OnScreenLayoutResetAction();
-  void OnSliceAnatomyOptionsChange(unsigned int order) ;
-
-  // 3D Rendering callbacks
-  void On3DRenderingApplyAction();
-  void On3DRenderingResetAction();
-
-  // Element appearance callbacks
-  void OnUIElementUpdate() ;
-  void OnUIElementSelection(int value) ;
-  void OnElementAppearanceResetAllAction();
-  void OnElementAppearanceResetAction();
-  void OnElementAppearanceApplyAction();
-
-
-  void OnOptionsExternalUpdate();
-  void OnHideOverlaysAction();
-
-private:
-  // Referece to the parent
-  UserInterfaceBase *m_Parent;
-
-  // Pointer to the appearance settings, from parent.
-  SNAPAppearanceSettings *m_Appearance;
-
-  // Default appearance settings
-  SNAPAppearanceSettings *m_DefaultAppearance;
-
-  // global state pointer
-  GlobalState *m_GlobalState;
-
-  // Fill some global options
-  void FillSliceLayoutOptions();
-  void FillRenderingOptions();
-  void FillAppearanceSettings();
-
-  // Apply the global options
-  void ApplyRenderingOptions();
-  void ApplySliceLayoutOptions();
-  void ApplyAppearanceSettings();
-
-  // A mapping from SNAP appearance elements to menu indices
-  const static int m_MapMenuToElementIndex[];
-};
-
-#endif
diff --git a/UserInterface/MainComponents/Artwork/crosshair.gif b/UserInterface/MainComponents/Artwork/crosshair.gif
deleted file mode 100644
index 1229551..0000000
Binary files a/UserInterface/MainComponents/Artwork/crosshair.gif and /dev/null differ
diff --git a/UserInterface/MainComponents/Artwork/crosshair3D.gif b/UserInterface/MainComponents/Artwork/crosshair3D.gif
deleted file mode 100644
index 4234e36..0000000
Binary files a/UserInterface/MainComponents/Artwork/crosshair3D.gif and /dev/null differ
diff --git a/UserInterface/MainComponents/Artwork/paintbrush.gif b/UserInterface/MainComponents/Artwork/paintbrush.gif
deleted file mode 100644
index 2b57cc4..0000000
Binary files a/UserInterface/MainComponents/Artwork/paintbrush.gif and /dev/null differ
diff --git a/UserInterface/MainComponents/Artwork/poly.gif b/UserInterface/MainComponents/Artwork/poly.gif
deleted file mode 100644
index b4cf025..0000000
Binary files a/UserInterface/MainComponents/Artwork/poly.gif and /dev/null differ
diff --git a/UserInterface/MainComponents/Artwork/rotate3d.gif b/UserInterface/MainComponents/Artwork/rotate3d.gif
deleted file mode 100644
index 7203d34..0000000
Binary files a/UserInterface/MainComponents/Artwork/rotate3d.gif and /dev/null differ
diff --git a/UserInterface/MainComponents/Artwork/scalpel.gif b/UserInterface/MainComponents/Artwork/scalpel.gif
deleted file mode 100644
index 02ba50b..0000000
Binary files a/UserInterface/MainComponents/Artwork/scalpel.gif and /dev/null differ
diff --git a/UserInterface/MainComponents/Artwork/snake.gif b/UserInterface/MainComponents/Artwork/snake.gif
deleted file mode 100644
index 4e7387b..0000000
Binary files a/UserInterface/MainComponents/Artwork/snake.gif and /dev/null differ
diff --git a/UserInterface/MainComponents/Artwork/spray.gif b/UserInterface/MainComponents/Artwork/spray.gif
deleted file mode 100644
index 6c48936..0000000
Binary files a/UserInterface/MainComponents/Artwork/spray.gif and /dev/null differ
diff --git a/UserInterface/MainComponents/Artwork/zoom.gif b/UserInterface/MainComponents/Artwork/zoom.gif
deleted file mode 100644
index 630952a..0000000
Binary files a/UserInterface/MainComponents/Artwork/zoom.gif and /dev/null differ
diff --git a/UserInterface/MainComponents/HelpViewer.fl b/UserInterface/MainComponents/HelpViewer.fl
deleted file mode 100644
index ab6595d..0000000
--- a/UserInterface/MainComponents/HelpViewer.fl
+++ /dev/null
@@ -1,40 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0104
-header_name {.h} 
-code_name {.cxx}
-class HelpViewer {open : { private HelpViewerBase }
-} {
-  Function {MakeWindow()} {open
-  } {
-    Fl_Window m_WinHelp {
-      label {SNAP/IRIS Help Window} open
-      xywh {133 98 612 710} type Double color 53 hide
-      code0 {\#include "HelpViewerBase.h"}
-    } {
-      Fl_Help_View m_BrsHelp {
-        callback {OnLinkAction();} selected
-        xywh {5 5 600 660} box BORDER_BOX
-      }
-      Fl_Button {} {
-        label {&Contents}
-        callback {OnContentsAction()}
-        xywh {140 675 75 25} box PLASTIC_UP_BOX shortcut 0x80063 color 180 labelsize 12
-      }
-      Fl_Button m_BtnBack {
-        label {@<-  Back}
-        callback {OnBackAction();}
-        xywh {225 675 75 25} box PLASTIC_UP_BOX shortcut 0xff08 color 180 labelsize 12 deactivate
-      }
-      Fl_Button m_BtnForward {
-        label {@->  &Forward}
-        callback {OnForwardAction();}
-        xywh {310 675 80 25} box PLASTIC_UP_BOX shortcut 0x80066 color 180 labelsize 12 deactivate
-      }
-      Fl_Button m_BtnClose {
-        label Close
-        callback {OnCloseAction();}
-        xywh {400 675 70 25} box PLASTIC_UP_BOX shortcut 0xff1b color 180 labelsize 12
-      }
-    }
-  }
-} 
diff --git a/UserInterface/MainComponents/HelpViewerBase.h b/UserInterface/MainComponents/HelpViewerBase.h
deleted file mode 100644
index 72fa54e..0000000
--- a/UserInterface/MainComponents/HelpViewerBase.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: HelpViewerBase.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:17 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __HelpViewerBase_h_
-#define __HelpViewerBase_h_
-
-class HelpViewerBase {
-public:
-    virtual ~HelpViewerBase () {}
-  virtual void OnLinkAction() = 0;
-  virtual void OnBackAction() = 0;
-  virtual void OnForwardAction() = 0;
-  virtual void OnCloseAction() = 0;
-  virtual void OnContentsAction() = 0;
-};
-
-#endif // __HelpViewerBase_h_
diff --git a/UserInterface/MainComponents/HelpViewerLogic.cxx b/UserInterface/MainComponents/HelpViewerLogic.cxx
deleted file mode 100644
index 10865a4..0000000
--- a/UserInterface/MainComponents/HelpViewerLogic.cxx
+++ /dev/null
@@ -1,188 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: HelpViewerLogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:17 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "HelpViewerLogic.h"
-#include <FL/Fl_Shared_Image.H>
-#include <FL/filename.H>
-
-using namespace std;
-
-// Callback for when links are clicked
-const char *HelpViewerLogicLinkCallback(Fl_Widget *w, const char *uri)
-{
-  // Only deal with visited html
-  const char *ext = fl_filename_ext(uri);
-  if(strcmp(ext,".html") != 0 && strcmp(ext,".HTML") != 0)
-    return uri;
-
-  // Pass on to the class
-  HelpViewerLogic *hvl = static_cast<HelpViewerLogic *>(w->user_data());
-  return hvl->LinkCallback(uri);  
-}
-
-HelpViewerLogic
-::HelpViewerLogic()
-{
-  // Make sure that Fl is set up for GIF/PNG images
-  fl_register_images();
-
-  // Clear the linked list
-  m_Iterator = m_LinkList.begin();  
-}
-  
-HelpViewerLogic
-::~HelpViewerLogic()
-{
-}
-
-void 
-HelpViewerLogic
-::ShowHelp(const char *url)
-{
-  // Put the url into the history list
-  PushURL(url);
-  
-  // Configure the browser
-  m_BrsHelp->link(HelpViewerLogicLinkCallback);
-  m_BrsHelp->user_data(this);
-  m_BrsHelp->load(url); 
-
-  // Show the window
-  if(!m_WinHelp->shown())
-    m_WinHelp->show();
-}
-
-const char *
-HelpViewerLogic
-::LinkCallback(const char *url)
-{
-  // Put the url into the history list
-  PushURL(url);
-
-  // Return the URL unchanged
-  return url;
-}
-
-void 
-HelpViewerLogic
-::PushURL(const char *url)
-{
-  // If the link is the same as our current location, don't do anything
-  if(m_Iterator != m_LinkList.end() && 
-     0 == strcmp(m_Iterator->c_str(),url))
-    return;
-
-  // Clear the forward stack
-  if(m_Iterator != m_LinkList.end())
-    m_LinkList.erase(++m_Iterator,m_LinkList.end());
-
-  // Add the new link to the list
-  m_LinkList.push_back(string(url));
-
-  // Point to the end of the list
-  m_Iterator = m_LinkList.end();
-  m_Iterator--;
-
-  // Disable the forward button
-  m_BtnForward->deactivate();
-
-  // Activate the back button if there is a back link
-  if(m_Iterator != m_LinkList.begin())
-    m_BtnBack->activate();
-  else
-    m_BtnBack->deactivate();    
-}
-
-void 
-HelpViewerLogic
-::OnLinkAction()
-{
-}
-
-void 
-HelpViewerLogic
-::OnBackAction()
-{
-  // Can't be at the head of the list
-  assert(m_Iterator != m_LinkList.begin());
-  
-  // Go back with the iterator
-  --m_Iterator;
-
-  // Enable the forward button
-  m_BtnForward->activate();
-
-  // Perhaps disable the back button
-  if(m_Iterator == m_LinkList.begin())
-    m_BtnBack->deactivate();
-
-  // Show the current link
-  m_BrsHelp->load(m_Iterator->c_str());
-}
-
-void 
-HelpViewerLogic
-::OnForwardAction()
-{
-  // Can't be at the end of the list
-  assert(++m_Iterator != m_LinkList.end());
-
-  // Enable the back button
-  m_BtnBack->activate();
-
-  // Perhaps disable the forward button
-  LinkIterator itTest = m_Iterator;
-  if(++itTest == m_LinkList.end())
-    m_BtnForward->deactivate();
-
-  // Show the current link
-  m_BrsHelp->load(m_Iterator->c_str());
-}
-
-void 
-HelpViewerLogic
-::OnCloseAction()
-{
-  m_WinHelp->hide();
-}
-
-void 
-HelpViewerLogic
-::OnContentsAction()
-{
-  // Go to the contents page
-  ShowHelp(m_ContentsLink.c_str());  
-}
-
-
diff --git a/UserInterface/MainComponents/HelpViewerLogic.h b/UserInterface/MainComponents/HelpViewerLogic.h
deleted file mode 100644
index 693215c..0000000
--- a/UserInterface/MainComponents/HelpViewerLogic.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: HelpViewerLogic.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:17 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __HelpViewerLogic_h_
-#define __HelpViewerLogic_h_
-
-#include "HelpViewer.h"
-#include "SNAPCommonUI.h"
-
-#include <list>
-
-
-/**
- * \class HelpViewerLogic
- * \brief UI logic for a help viewer window 
- */ 
-class HelpViewerLogic : public HelpViewer {
-public:
-  
-  HelpViewerLogic();
-  virtual ~HelpViewerLogic();
-
-  /** Set the 'Contents' link */
-  irisSetStringMacro(ContentsLink);
-
-  /** Display the help window on a particular page */
-  void ShowHelp(const char *url);
-  
-  void OnLinkAction();
-  void OnBackAction();
-  void OnForwardAction();
-  void OnCloseAction();
-  void OnContentsAction();
-
-  // Callback for when a link is followed
-  const char *LinkCallback(const char *uri);
-
-private:
-  // The list of visited links (back and forth)
-  typedef std::list<std::string> LinkListType;
-  LinkListType m_LinkList;
-
-  // The current place on the list
-  typedef LinkListType::iterator LinkIterator;
-  LinkIterator m_Iterator;
-  
-  // Contents page
-  std::string m_ContentsLink;
-  
-  // A method to push a URL onto the history stack
-  void PushURL(const char *url);
-};
-
-#endif // __HelpViewerLogic_h_
-
diff --git a/UserInterface/MainComponents/LabelEditorUI.fl b/UserInterface/MainComponents/LabelEditorUI.fl
deleted file mode 100644
index b16976f..0000000
--- a/UserInterface/MainComponents/LabelEditorUI.fl
+++ /dev/null
@@ -1,214 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0300 
-header_name {.h} 
-code_name {.cxx}
-class LabelEditorUI {open : {private LabelEditorUIBase}
-} {
-  Function {MakeWindow()} {open
-  } {
-    Fl_Window m_WinMain {
-      label {Segmentation Label Editor - ITK-SNAP} open
-      xywh {811 254 440 405} type Double
-      code0 {\#include "LabelEditorUIBase.h"} visible
-    } {
-      Fl_Group {} {
-        label {Available labels:} open
-        xywh {10 25 200 320} box BORDER_BOX selection_color 0 labelfont 1 labelsize 12 align 5
-      } {
-        Fl_Browser m_BrsLabelList {
-          callback {OnLabelSelectAction()}
-          xywh {15 35 190 305} type Hold labelsize 12 textfont 4 textsize 11
-        }
-      }
-      Fl_Tabs {} {
-        label {Selected Label:} open
-        xywh {220 25 210 320} box PLASTIC_THIN_UP_BOX selection_color 53 labelfont 1 labelsize 12 align 5
-      } {
-        Fl_Group {} {
-          label Appearance open selected
-          xywh {220 50 210 295} labelsize 12
-        } {
-          Fl_Input m_InLabelName {
-            label {Description:}
-            callback {OnLabelPropertyChange()}
-            xywh {225 75 200 20} color 53 labelsize 12 align 5 when 1 textsize 12
-          }
-          Fl_Value_Slider m_InLabelOpacity {
-            label {Opacity:}
-            callback {OnLabelPropertyChange()}
-            xywh {225 240 200 20} type Horizontal color 53 selection_color 12 labelsize 12 align 5 value 0.2
-          }
-          Fl_Group m_GrpLabelColor {
-            label {Color:}
-            callback {OnLabelPropertyChange()} open
-            xywh {225 120 200 95} box PLASTIC_DOWN_BOX labelsize 12 align 5
-            code0 {\#include <FL/Fl_Color_Chooser.H>}
-            class Fl_Color_Chooser
-          } {}
-          Fl_Group {} {
-            label {Visibility:} open
-            xywh {225 285 200 50} box PLASTIC_DOWN_BOX labelsize 12 align 5
-          } {
-            Fl_Check_Button m_ChkVisibility {
-              label {Hide label in all windows}
-              callback {OnLabelPropertyChange()}
-              xywh {235 310 180 20} down_box DOWN_BOX selection_color 180 labelsize 12
-            }
-            Fl_Check_Button m_ChkMeshVisibility {
-              label {Hide label in the 3D window}
-              callback {OnLabelPropertyChange()}
-              xywh {235 290 180 20} down_box DOWN_BOX selection_color 180 labelsize 12
-            }
-          }
-        }
-        Fl_Group {} {
-          label {Label Id} open
-          xywh {220 50 210 295} labelsize 12 hide
-        } {
-          Fl_Group {} {
-            label {Label's position in the list:} open
-            xywh {225 75 200 85} box PLASTIC_DOWN_BOX labelsize 12 align 5
-          } {
-            Fl_Button {} {
-              label {Move up}
-              callback {OnMoveUpAction()}
-              xywh {250 125 75 25} box PLASTIC_UP_BOX color 48 labelsize 12
-            }
-            Fl_Button {} {
-              label {Move down}
-              callback {OnMoveDownAction()}
-              xywh {335 125 75 25} box PLASTIC_UP_BOX color 48 labelsize 12
-            }
-            Fl_Value_Input m_InLabelId {
-              label {Numeric Id:}
-              xywh {310 90 50 25} labelsize 12 when 4 textsize 12
-            }
-            Fl_Button m_BtnSetId {
-              label Set
-              callback {OnSetIdAction()}
-              xywh {365 90 45 25} box PLASTIC_UP_BOX color 48 labelsize 12
-            }
-          }
-          Fl_Check_Button m_ChkPromptId {
-            label {Allow me to enter label ids when adding new labels}
-            xywh {225 205 195 20} down_box DOWN_BOX selection_color 180 labelsize 12 align 149
-          }
-        }
-      }
-      Fl_Button {} {
-        label New
-        callback {OnNewAction()}
-        xywh {10 370 65 25} box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-      Fl_Button {} {
-        label Delete
-        callback {OnDeleteAction()}
-        xywh {160 370 65 25} box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-      Fl_Button {} {
-        label Duplicate
-        callback {OnDuplicateAction()}
-        xywh {85 370 65 25} box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-      Fl_Button {} {
-        label Close
-        callback {OnCloseAction()}
-        xywh {360 370 70 25} box PLASTIC_UP_BOX color 180 labelfont 1 labelsize 12
-      }
-      Fl_Button {} {
-        label {Tools...}
-        callback {OnToolsDialogAction()}
-        xywh {235 370 65 25} box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-      Fl_Group {} {
-        label {Note: changes to label ids and deletion of labels can not be undone!} open
-        xywh {10 345 420 20} labelsize 10 align 20
-      } {}
-    }
-    Fl_Window m_WinTools {
-      label {Label Tools - ITK-SNAP} open
-      xywh {826 625 295 270} type Double modal visible
-    } {
-      Fl_Button m_BtnToolsApply {
-        label Apply
-        callback {OnToolsApplyAction()}
-        xywh {80 235 65 25} box PLASTIC_UP_BOX color 180 labelfont 1 labelsize 12
-      }
-      Fl_Button {} {
-        label Close
-        callback {OnToolsCloseAction();}
-        xywh {155 235 65 25} box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-      Fl_Choice m_InToolsOperation {
-        label {Operation:}
-        callback {OnToolsOperationChange();} open
-        xywh {15 25 265 20} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-      } {
-        MenuItem {} {
-          label {Replace label by another}
-          xywh {5 5 30 20} labelsize 12
-        }
-        MenuItem {} {
-          label {Topology-preserving merge}
-          xywh {10 10 30 20} labelsize 12
-        }
-        MenuItem {} {
-          label {Enforce well-composed property}
-          xywh {20 20 30 20} labelsize 12
-        }
-      }
-      Fl_Wizard m_WizToolControls {open
-        xywh {15 55 265 160} box PLASTIC_DOWN_BOX
-      } {
-        Fl_Group {m_GrpToolPage[0]} {open
-          xywh {15 55 265 160} labelsize 11 align 21
-        } {
-          Fl_Choice {m_InToolPageLabel[0]} {
-            label {Source label:} open
-            xywh {30 135 235 20} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-          } {}
-          Fl_Choice {m_InToolPageLabel[1]} {
-            label {Target label:} open
-            xywh {30 180 235 20} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-          } {}
-          Fl_Group {} {
-            label {This operation simply relabels all voxels assigned
- the source label with the target label.} open
-            xywh {20 60 255 50} labelsize 11 align 21
-          } {}
-        }
-        Fl_Group {m_GrpToolPage[1]} {open
-          xywh {15 55 265 160} labelsize 11 align 21 hide
-        } {
-          Fl_Choice {m_InToolPageLabel[2]} {
-            label {Source label:} open
-            xywh {30 135 235 20} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-          } {}
-          Fl_Choice {m_InToolPageLabel[3]} {
-            label {Target label:} open
-            xywh {30 180 235 20} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-          } {}
-          Fl_Group {} {
-            label {This tool grows the source label into the target label
-preserving the topology of the source label.} open
-            xywh {20 60 255 50} labelsize 11 align 21
-          } {}
-        }
-        Fl_Group {m_GrpToolPage[2]} {open
-          xywh {15 55 265 160} labelsize 11 align 21 hide
-        } {
-          Fl_Choice {m_InToolPageLabel[4]} {
-            label {Target label:} open
-            xywh {30 135 235 20} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-          } {}
-          Fl_Group {} {
-            label {This tool makes the segmentation for the target label
-well-composed. Well-composed segmentations have
-non-ambiguous topology and lead to better meshes.} open
-            xywh {20 60 255 50} labelsize 11 align 21
-          } {}
-        }
-      }
-    }
-  }
-} 
diff --git a/UserInterface/MainComponents/LabelEditorUIBase.h b/UserInterface/MainComponents/LabelEditorUIBase.h
deleted file mode 100644
index 55e658d..0000000
--- a/UserInterface/MainComponents/LabelEditorUIBase.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: LabelEditorUIBase.h,v $
-  Language:  C++
-  Date:      $Date: 2008/11/17 19:38:23 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __LabelEditorUIBase_h_
-#define __LabelEditorUIBase_h_
-
-/**
- * \class LabelEditorUIBase
- * \brief Base class for Label editor UI logic
- */
-class LabelEditorUIBase {
-public:
-    virtual ~LabelEditorUIBase() {}
-  // Callbacks
-  virtual void OnNewAction() = 0;
-  virtual void OnDuplicateAction() = 0;
-  virtual void OnDeleteAction() = 0;
-  virtual void OnSetIdAction() = 0;
-  virtual void OnMoveUpAction() = 0;
-  virtual void OnMoveDownAction() = 0;
-  virtual void OnCloseAction() = 0;
-  virtual void OnLabelSelectAction() = 0;
-  virtual void OnLabelPropertyChange() = 0;
-  virtual void OnToolsDialogAction() = 0;
-  virtual void OnToolsApplyAction() = 0;
-  virtual void OnToolsCloseAction() = 0;
-  virtual void OnToolsOperationChange() = 0;
-};
-
-#endif
diff --git a/UserInterface/MainComponents/LabelEditorUILogic.cxx b/UserInterface/MainComponents/LabelEditorUILogic.cxx
deleted file mode 100644
index d11f2a4..0000000
--- a/UserInterface/MainComponents/LabelEditorUILogic.cxx
+++ /dev/null
@@ -1,644 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: LabelEditorUILogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/07/01 21:40:24 $
-  Version:   $Revision: 1.10 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "LabelEditorUILogic.h"
-#include "UserInterfaceLogic.h"
-#include "GlobalState.h"
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-
-#include <iostream>
-#include <iomanip>
-#include <sstream>
-#include <FL/fl_ask.H>
-
-LabelEditorUILogic
-::LabelEditorUILogic()
-{
-  m_Parent = NULL;
-  m_Driver = NULL;
-  m_GlobalState = NULL;
-}
-
-LabelEditorUILogic
-::~LabelEditorUILogic()
-{
-}
-
-void
-LabelEditorUILogic
-::Register(UserInterfaceBase *parent)
-{
-  m_Parent = parent;
-  m_Driver = parent->GetDriver();
-  m_GlobalState = m_Driver->GetGlobalState();
-}
-
-const ColorLabel &
-LabelEditorUILogic
-::GetColorLabel(size_t iLabel)
-{ 
-  return m_Driver->GetColorLabelTable()->GetColorLabel(iLabel); 
-}
-
-void
-LabelEditorUILogic
-::SetColorLabel(size_t iLabel, const ColorLabel &xLabel)
-{ 
-  m_Driver->GetColorLabelTable()->SetColorLabel(iLabel, xLabel); 
-}
-
-void 
-LabelEditorUILogic
-::DisplayWindow()
-{
-  m_WinMain->show();  
-}
-
-void 
-LabelEditorUILogic
-::OnCloseAction()
-{
-  m_WinMain->hide();
-}
-
-void 
-LabelEditorUILogic
-::OnLabelListUpdate(unsigned int iCurrentLabel)
-{
-  // Clear the list of labels
-  m_BrsLabelList->clear();
-
-  // We will also find the first valid label
-  size_t iFirstValidLabel = 0;
-
-  // Get the list of labels from the system and populate the browser
-  for(size_t i = 1; i < MAX_COLOR_LABELS; i++)
-    {
-    ColorLabel cl = GetColorLabel(i);
-    if(cl.IsValid())
-      {
-      // Create a label string
-      std::ostringstream oss;
-      oss << std::setw(3) << i << ": " << cl.GetLabel();
-      
-      // Add to the list the label and and the id (as a special data)
-      m_BrsLabelList->add(oss.str().c_str(), (void *)(i));
-
-      // Set the first valid label
-      if(iFirstValidLabel == 0) iFirstValidLabel = i;
-      }
-    }
-
-  // Set the current label's display, or if 0 is passed in initialize 
-  // at the very first label
-  SetEditorLabel(iCurrentLabel > 0 ? iCurrentLabel : iFirstValidLabel);
-}
-
-void
-LabelEditorUILogic
-::SetEditorLabel(unsigned int iLabel)
-{
-  // The label must be valid!
-  assert(GetColorLabel(iLabel).IsValid());
-  
-  // Find the label in the browser, and select it
-  for(size_t i = 1; i <= static_cast<size_t>(m_BrsLabelList->size()); i++)
-    {
-    size_t id = (size_t) m_BrsLabelList->data(i);
-    if(id == iLabel) 
-      {
-      m_BrsLabelList->select(i);
-      break;
-      }
-    }
-  
-  // Get the label object
-  ColorLabel cl = GetColorLabel(iLabel);
-
-  // Fill out the form
-  m_InLabelName->value(cl.GetLabel());
-  m_InLabelOpacity->value(cl.GetAlpha() / 255.0 );
-  m_GrpLabelColor->rgb( cl.GetRGB(0)/255.0, cl.GetRGB(1)/255.0, cl.GetRGB(2)/255.0 );
-  m_InLabelId->value(iLabel);
-  m_ChkVisibility->value(!cl.IsVisible());
-  m_ChkMeshVisibility->value(!cl.IsVisibleIn3D());
-}
-
-int 
-LabelEditorUILogic
-::FindSpaceForNewLabel()
-{
-  // Find a place to stick in the new label
-  size_t iLabel = 0;
-  for(size_t i = 1; i < MAX_COLOR_LABELS; i++)
-    if(!GetColorLabel(i).IsValid())
-      { iLabel = i; break; }
-
-  // Make sure we actually found a space
-  if(iLabel == 0)
-    {
-    fl_alert(
-      "It is not possible to define more than %d labels in SNAP. \n"
-      "Delete some of the existing labels to make room for the \n"
-      "label that you wish to add. \n", MAX_COLOR_LABELS);
-    return 0;
-    }
-
-  if(m_ChkPromptId->value())
-    {
-    // Show the prompt asking for the label Id
-    std::ostringstream oss; oss << iLabel; 
-    std::string sMessage = "";
-    bool flagChosen = false;
-
-    while(!flagChosen)
-      {
-      const char *sAnswer = 
-        fl_input("What id would you like to assign to this label?",oss.str().c_str());
-
-      // What if they click cancel?
-      if(!sAnswer)
-        return 0;
-
-      try {
-        int iAnswer = atoi(sAnswer);
-        if(iAnswer <= 0 || iAnswer > MAX_COLOR_LABELS)
-          fl_message("ERROR: You must enter a number between 1 and %d!\n", MAX_COLOR_LABELS);
-        else if(GetColorLabel(iAnswer).IsValid())
-          fl_message("ERROR: That label is already in use!\n");
-        else
-          { iLabel = iAnswer; flagChosen = true; }
-      } 
-      catch(...)
-        { 
-        fl_message("ERROR: You must enter a number between 1 and %d!\n", MAX_COLOR_LABELS);
-        }
-      }
-    }
-
-  // If the space is not the last one in the list, alert the user that we 
-  // are sticking the label in the first available slot
-  else if(iLabel < static_cast<size_t>(m_BrsLabelList->size()))
-    {
-    fl_message(
-      "The label will be assigned the first available ID, which is %d\n"
-      "To assign a different ID to the label or to move it to the \n"
-      "bottom of the list of labels, use the 'Label Id' tab \n", static_cast<int>(iLabel));
-    }
- 
-  return iLabel;
-}
-
-void
-LabelEditorUILogic
-::OnNewAction()
-{
-  // Find the space for this new label
-  unsigned int iLabel = FindSpaceForNewLabel();
-  if(iLabel == 0) return;
-  
-  // Get the default color label for this position
-  ColorLabel cl = m_Driver->GetColorLabelTable()->GetDefaultColorLabel(iLabel);
-  cl.SetValid(true);
-
-  // Set the label
-  SetColorLabel(iLabel, cl);
-
-  // Update the state of the widget
-  OnLabelListUpdate(iLabel);
-
-  // Update the list in the parent UI
-  m_Parent->OnLabelListUpdate();
-}
-
-void 
-LabelEditorUILogic
-::OnDuplicateAction()
-{
-  // Only valid if a label is selected
-  assert(m_BrsLabelList->value() > 0);
-  
-  // Find the space for this new label
-  unsigned int iNewLabel = FindSpaceForNewLabel();
-  if(iNewLabel == 0) return;
-
-  // Get the copy label (currently selected)
-  size_t iCurrentLabel = (size_t) m_BrsLabelList->data(m_BrsLabelList->value());
- 
-  // Get the old and the new label 
-  ColorLabel clNew = GetColorLabel(iNewLabel);
-  const ColorLabel &clOld = GetColorLabel(iCurrentLabel);
-  
-  // Copy the label properties
-  clNew.SetValid(true);
-  clNew.SetPropertiesFromColorLabel(clOld);
-  
-  // Set the description
-  std::ostringstream oss;
-  oss << clOld.GetLabel() << "(Copy)";
-  clNew.SetLabel(oss.str().c_str());
-
-  // Store the label
-  SetColorLabel(iNewLabel, clNew);
-
-  // Update the state of the widget
-  OnLabelListUpdate(iNewLabel);
-
-  // Update the list in the parent UI
-  m_Parent->OnLabelListUpdate();
-}
-
-size_t
-LabelEditorUILogic
-::GetSelectedLabelId()
-{
-  if(m_BrsLabelList->value() == 0) return 0;
-  return (size_t) m_BrsLabelList->data(m_BrsLabelList->value());
-}
-
-void 
-LabelEditorUILogic
-::OnDeleteAction()
-{
-  // Must have a current label
-  size_t iCurrentLabel = GetSelectedLabelId();
-  assert(iCurrentLabel > 0);
-
-  // Find the next label for us to activate
-  size_t iNextLabel = 0;
-  for(size_t i = iCurrentLabel + 1; i < MAX_COLOR_LABELS; i++)
-    if(GetColorLabel(i).IsValid())
-      { iNextLabel = i; break; }
-
-  if(iNextLabel == 0)
-    {
-    // Turns out we are deleting the last label. Search back to the first label
-    for(size_t j = iCurrentLabel - 1; j > 0; j--)
-      if(GetColorLabel(j).IsValid())
-        { iNextLabel = j; break; }
-    }
-
-  if(iNextLabel == 0)
-    {
-    // We're removing the only label. We can't allow that!
-    fl_alert(
-      "SNAP can not operate without any labels. Please add \n"
-      "some new labels before deleting this one.");
-    return;
-    }
-     
-  // Delete the label in the system, replacing it with zero
-  size_t nUpdated = m_Driver->GetCurrentImageData()->GetSegmentation()
-    ->ReplaceIntensity(iCurrentLabel, 0);
-
-  // Set the label current label as invalid
-  m_Driver->GetColorLabelTable()->SetColorLabelValid(iCurrentLabel, false);
-
-  // If the label is a current paint-over label or a drawing label, 
-  // reposition the currently selected label
-  if(iCurrentLabel == m_GlobalState->GetDrawingColorLabel())
-    m_GlobalState->SetDrawingColorLabel(
-      m_Driver->GetColorLabelTable()->GetFirstValidLabel());
-  if(iCurrentLabel == m_GlobalState->GetOverWriteColorLabel())
-    m_GlobalState->SetOverWriteColorLabel(0);
-  
-  // Rebuild the list of labels
-  OnLabelListUpdate(iNextLabel);
-
-  // The segmentation image has been modified, let the parent know
-  if(nUpdated > 0)
-    {
-    // This operation can not be undone!
-    m_Parent->ClearUndoPoints();
-    m_Parent->OnSegmentationImageUpdate(false);    
-    }
-    
-  // Update the label list
-  m_Parent->OnLabelListUpdate();
-
-}
-  
-void
-LabelEditorUILogic
-::OnSetIdAction()
-{
-  // Must have a current label
-  size_t iCurrentLabel = GetSelectedLabelId();
-  assert(iCurrentLabel > 0);
-
-  // Get the id and check that it's valid
-  unsigned int iNewId = (unsigned int) m_InLabelId->value();
-  if(iNewId <= 0 || iNewId > MAX_COLOR_LABELS)
-    {
-    fl_alert("The label id must be a number between 1 and %d", MAX_COLOR_LABELS);
-    return;
-    }
-
-  // Check if the id is already in use
-  ColorLabel clTarget = GetColorLabel(iNewId);
-  if(clTarget.IsValid())
-    {
-    fl_alert("Label %d is already in use! Please select a different id", iNewId);
-    return;
-    }
-
-  // Move the label into the new slot
-  clTarget.SetPropertiesFromColorLabel(GetColorLabel(iCurrentLabel));
-  clTarget.SetValid(true);
-  SetColorLabel(iNewId, clTarget);
-
-  // Update the new labels
-  m_Driver->GetColorLabelTable()->SetColorLabelValid(iCurrentLabel, false);
-
-  // If the label was a current drawing label, we need to update that
-  if(iCurrentLabel == m_GlobalState->GetDrawingColorLabel())
-    m_GlobalState->SetDrawingColorLabel(iNewId);
-  if(iCurrentLabel == m_GlobalState->GetOverWriteColorLabel())
-    m_GlobalState->SetOverWriteColorLabel(iNewId);
-
-  // Replace label iOld with iNew in the segmentation image
-  size_t nUpdated = m_Driver->GetCurrentImageData()->GetSegmentation()
-    ->ReplaceIntensity(iCurrentLabel, iNewId);
-
-  // Rebuild the list of labels
-  OnLabelListUpdate(iNewId);
-
-  // The segmentation image has been modified, let the parent know
-  if(nUpdated > 0)
-    {
-    // This operation can not be undone!
-    m_Parent->ClearUndoPoints();
-    m_Parent->OnSegmentationImageUpdate(false);    
-    }
-}
-  
-void
-LabelEditorUILogic
-::OnLabelPropertyChange()
-{
-  // Make sure there is a selected label
-  size_t iCurrentLabel = GetSelectedLabelId();
-  assert(iCurrentLabel > 0);
-
-  // Get the label
-  ColorLabel cl = GetColorLabel(iCurrentLabel);
-
-  // Get the color values
-  unsigned char rgba[4];
-  rgba[0] = (unsigned char) (255 * m_GrpLabelColor->r());
-  rgba[1] = (unsigned char) (255 * m_GrpLabelColor->g());
-  rgba[2] = (unsigned char) (255 * m_GrpLabelColor->b());
-  rgba[3] = (unsigned char) (255 * m_InLabelOpacity->value());
-
-  // Set the values of the label
-  cl.SetLabel(m_InLabelName->value());
-  cl.SetRGBAVector(rgba); 
-
-  // If visibility has changed, we need to enable mesh update
-  bool old_visible = cl.IsVisible(), old_vis3d = cl.IsVisibleIn3D();
-  cl.SetVisible(m_ChkVisibility->value() == 0);
-  cl.SetVisibleIn3D(m_ChkMeshVisibility->value() == 0);
-  if((!old_vis3d && cl.IsVisibleIn3D()) || (!old_visible && cl.IsVisible()))
-    {
-    m_Parent->OnIRISMeshDisplaySettingsUpdate();
-    }
-
-  // Store the new label
-  SetColorLabel(iCurrentLabel, cl);
-
-  // Update the label list
-  // OnLabelListUpdate(iCurrentLabel);
- 
-  // Update the text in the browser
-  std::ostringstream oss;
-  oss << std::setw(3) << iCurrentLabel << ": " << cl.GetLabel();
-  m_BrsLabelList->text(m_BrsLabelList->value(), oss.str().c_str());
-
-  // Update the list in the parent UI
-  m_Parent->OnLabelListUpdate();
-}
-  
-void
-LabelEditorUILogic
-::OnMoveUpAction()
-{
-}
-
-void
-LabelEditorUILogic
-::OnMoveDownAction()
-{
-}
-  
-void
-LabelEditorUILogic
-::OnLabelSelectAction()
-{
-  SetEditorLabel(GetSelectedLabelId());
-}
-
-const size_t 
-LabelEditorUILogic
-::TOOL_PAGE_LABEL_MENU_COUNT = 5;
-
-void
-LabelEditorUILogic
-::OnToolsDialogAction()
-{
-  // Flags decribing whether each dropdown includes the clear label
-  int flagIncludeClear[TOOL_PAGE_LABEL_MENU_COUNT] = { 0, 1, 1, 0, 0 };
-  int flagInitToCurrent[TOOL_PAGE_LABEL_MENU_COUNT] = { 0, 1, 1, 0, 1 };
-  int flagInitToDrawOver[TOOL_PAGE_LABEL_MENU_COUNT] = { 1, 0, 0, 1, 0 };
-
-  // Initialize the menus
-  m_ToolPageLabelMenu = new Fl_Menu_Item*[TOOL_PAGE_LABEL_MENU_COUNT];
-
-  // Populate the label dropdowns
-  for(size_t i = 0; i < TOOL_PAGE_LABEL_MENU_COUNT; i++)
-    {
-    // Populate the dropdown
-    m_ToolPageLabelMenu[i] = m_Parent->GenerateColorLabelMenu(
-      false, false, flagIncludeClear[i]);
-    m_InToolPageLabel[i]->menu(m_ToolPageLabelMenu[i]);
-
-    // Find an item to select
-    LabelType selected = this->GetSelectedLabelId();
-    LabelType drawover = m_Driver->GetGlobalState()->GetOverWriteColorLabel();
-    for(Fl_Menu_Item *p = m_ToolPageLabelMenu[i]; p->text; ++p)
-      {
-      LabelType id = (LabelType)(size_t)p->user_data();
-      if(flagInitToCurrent[i] && id == selected)
-        m_InToolPageLabel[i]->value(p);
-      else if(flagInitToDrawOver[i] && id == drawover)
-        m_InToolPageLabel[i]->value(p);
-      }
-    }  
-  
-  // Show the dialog
-  UserInterfaceLogic::CenterChildWindowInParentWindow(m_WinTools, m_WinMain);
-  m_WinTools->show();
-}
-
-#include "itkTopologyPreservingDigitalSurfaceEvolutionImageFilter.h"
-#include "itkBinaryThresholdImageFilter.h"
-
-void
-LabelEditorUILogic
-::OnToolsApplyAction()
-{
-  // Relabeling operation
-  if(m_InToolsOperation->value() == 0)
-    {
-    // Get the labels
-    LabelType src = (LabelType) (size_t) m_InToolPageLabel[0]->mvalue()->user_data();
-    LabelType trg = (LabelType) (size_t) m_InToolPageLabel[1]->mvalue()->user_data();
-
-    // Do the simple merge
-    size_t nChanged = m_Driver->ReplaceLabel(trg, src);
-    if(nChanged == 0)
-      fl_alert("No voxels were affected by this operation!");
-    else
-      {
-      m_Parent->StoreUndoPoint("Relabeling");
-      m_Parent->OnSegmentationImageUpdate(false);
-      }
-    }
-
-  // Topological merge operation
-  else if(m_InToolsOperation->value() == 1)
-    {
-    // Get the segmentation image
-    typedef itk::OrientedImage<LabelType, 3> LabelImageType;
-    LabelImageType::Pointer iSeg =
-      m_Driver->GetCurrentImageData()->GetSegmentation()->GetImage();
-
-    // Get the labels
-    LabelType l_src = (LabelType) (size_t) m_InToolPageLabel[0]->mvalue()->user_data();
-    LabelType l_trg = (LabelType) (size_t) m_InToolPageLabel[1]->mvalue()->user_data();
-
-    // Extract binary images for each label
-    typedef itk::BinaryThresholdImageFilter<LabelImageType,LabelImageType> ThreshType;
-    ThreshType::Pointer tsrc = ThreshType::New();
-    tsrc->SetInput(iSeg);
-    tsrc->SetLowerThreshold(l_src);
-    tsrc->SetUpperThreshold(l_src);
-    tsrc->SetInsideValue(1);
-    tsrc->SetOutsideValue(0);
-    tsrc->Update();
-    
-    ThreshType::Pointer ttrg = ThreshType::New();
-    ttrg->SetInput(iSeg);
-    ttrg->SetLowerThreshold(l_trg);
-    ttrg->SetUpperThreshold(l_trg);
-    ttrg->SetInsideValue(1);
-    ttrg->SetOutsideValue(0);
-    ttrg->Update();
-
-    // Create a progress object
-    typedef itk::MemberCommand<UserInterfaceBase> CommandType;
-    CommandType::Pointer pcom = CommandType::New();
-    pcom->SetCallbackFunction(m_Parent, &UserInterfaceBase::OnITKProgressEvent);
-
-    // Create the evolution filter
-    typedef itk::TopologyPreservingDigitalSurfaceEvolutionImageFilter<LabelImageType> FilterType;
-    FilterType::Pointer filter = FilterType::New();
-    filter->SetInput(tsrc->GetOutput());
-    filter->SetTargetImage(ttrg->GetOutput());
-    filter->SetNumberOfIterations(100);
-    filter->SetForegroundValue(1);
-    filter->SetUseInversionMode(false);
-    filter->InPlaceOn();
-    filter->AddObserver(itk::AnyEvent(), pcom);
-    filter->Update();
-
-    // Merge back into the segmentation
-    typedef itk::ImageRegionIterator<LabelImageType> IteratorType;
-    IteratorType itseg(iSeg, iSeg->GetBufferedRegion());
-    IteratorType itnew(filter->GetOutput(), iSeg->GetBufferedRegion());
-    size_t nChanged = 0;
-    while(!itseg.IsAtEnd())
-      {
-      if(itnew.Get())
-        {
-        itseg.Set(l_src);
-        ++nChanged;
-        }
-      ++itseg; ++itnew;
-      }
-
-    // Let parent know something happened
-    if(nChanged)
-      {
-      iSeg->Modified();
-      m_Parent->StoreUndoPoint("Topological Merge");
-      m_Parent->OnSegmentationImageUpdate(false);
-      }
-    else
-      {
-      fl_alert("No voxel labels were changed");
-      }
-    }
-
-  // Topological merge operation
-  else if(m_InToolsOperation->value() == 2)
-    {
-    fl_alert("This operation is not yet implemented");
-    }
-}
-
-void
-LabelEditorUILogic
-::OnToolsOperationChange()
-{
-  m_WizToolControls->value(
-    m_WizToolControls->child(m_InToolsOperation->value()));
-}
-
-void
-LabelEditorUILogic
-::OnToolsCloseAction()
-{
-  // Empty all menus
-  for(size_t i = 0; i < TOOL_PAGE_LABEL_MENU_COUNT; i++)
-    {
-    // Populate the dropdown
-    m_InToolPageLabel[i]->clear();
-    m_Parent->DeleteColorLabelMenu(m_ToolPageLabelMenu[i]);
-    m_ToolPageLabelMenu[i] = NULL;
-    }
-  delete m_ToolPageLabelMenu;
-  m_WinTools->hide();
-}
-
diff --git a/UserInterface/MainComponents/LabelEditorUILogic.h b/UserInterface/MainComponents/LabelEditorUILogic.h
deleted file mode 100644
index 99d8cab..0000000
--- a/UserInterface/MainComponents/LabelEditorUILogic.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: LabelEditorUILogic.h,v $
-  Language:  C++
-  Date:      $Date: 2008/11/17 19:38:23 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __LabelEditorUILogic
-#define __LabelEditorUILogic
-
-#include "LabelEditorUI.h"
-#include "ColorLabel.h"
-#include <map>
-#include <vector>
-
-// Forward references to some classes
-class IRISApplication;
-class GlobalState;
-class UserInterfaceBase;
-
-/**
- * \class LabelEditorUILogic
- * \brief Logic class for Label editor UI logic
- */
-class LabelEditorUILogic : public LabelEditorUI {
-public:
-  LabelEditorUILogic();
-  virtual ~LabelEditorUILogic();
-
-  /** Register with the parent user interface */
-  void Register(UserInterfaceBase *parent);
-
-  /** Set the active label */
-  void SetEditorLabel(unsigned int iLabel);
-
-  /** Respond to an update in the list of labels, setting the current 
-   * label to iLabel */
-  void OnLabelListUpdate(unsigned int iCurrentLabel);
-
-  /** Display the editor window */
-  void DisplayWindow();
-  
-  // Callbacks from the user interface
-  void OnNewAction();
-  void OnDuplicateAction();
-  void OnDeleteAction();
-  void OnSetIdAction();
-  void OnMoveUpAction();
-  void OnMoveDownAction();
-  void OnCloseAction();
-  void OnLabelSelectAction();
-  void OnLabelPropertyChange();
-  void OnToolsDialogAction();
-  void OnToolsApplyAction();
-  void OnToolsCloseAction();
-  void OnToolsOperationChange();
-
-private:
-  UserInterfaceBase *m_Parent;
-  GlobalState *m_GlobalState;
-  IRISApplication *m_Driver;
-
-  // Internal menus
-  static const size_t TOOL_PAGE_LABEL_MENU_COUNT;
-  Fl_Menu_Item **m_ToolPageLabelMenu;
-
-  // Internal functions
-  int FindSpaceForNewLabel();
-  size_t GetSelectedLabelId();
-
-  // Quick access to color labels
-  const ColorLabel &GetColorLabel(size_t iLabel);
-  void SetColorLabel(size_t iLabel, const ColorLabel &xLabel);
-};
-
-#endif
diff --git a/UserInterface/MainComponents/LayerInspectorUI.fl b/UserInterface/MainComponents/LayerInspectorUI.fl
deleted file mode 100644
index af0444e..0000000
--- a/UserInterface/MainComponents/LayerInspectorUI.fl
+++ /dev/null
@@ -1,412 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0109
-use_FL_COMMAND 
-header_name {.h} 
-code_name {.cxx}
-class LayerInspectorUI {open : LayerInspectorUIBase
-} {
-  Function {MakeWindow()} {open
-  } {
-    Fl_Window m_WinLayerUI {
-      label {ITK-SNAP: Layer Inspector} open
-      xywh {688 132 584 485} type Double box PLASTIC_DOWN_BOX resizable
-      code0 {\#include "LayerInspectorUIBase.h"} visible
-    } {
-      Fl_Tabs m_LayerUITabs {
-        callback {this->DisplayWindow();} open
-        xywh {180 5 390 475} box PLASTIC_THIN_UP_BOX color 41
-      } {
-        Fl_Group m_ImageContrastTab {
-          label Contrast open
-          xywh {180 25 390 455} labelsize 12 hide
-        } {
-          Fl_Group {} {
-            label {Window and Level:} open
-            xywh {190 55 370 45} box PLASTIC_DOWN_BOX color 55 labelfont 1 labelsize 12 align 5
-          } {
-            Fl_Value_Input m_InLevel {
-              label {Level:}
-              callback {this->OnWindowLevelChange();}
-              xywh {235 65 70 25} labelsize 12 when 4 step 0.01 textsize 12
-            }
-            Fl_Value_Input m_InWindow {
-              label {Window:}
-              callback {this->OnWindowLevelChange();}
-              xywh {370 65 70 25} labelsize 12 when 4 step 0.01 textsize 12
-            }
-            Fl_Button {} {
-              label {&Auto}
-              callback {this->OnAutoFitWindow();}
-              tooltip {Automatically fit window and level based on the image histogram} xywh {475 65 70 25} box PLASTIC_UP_BOX shortcut 0x80061 labelsize 12
-            }
-          }
-          Fl_Group {} {
-            label {Curve-Based Adjustment:} open
-            xywh {190 125 370 250} box PLASTIC_DOWN_BOX labelfont 1 labelsize 12 align 5
-          } {
-            Fl_Box m_BoxCurve {
-              label {Curve Display Area}
-              xywh {210 135 340 180} box BORDER_BOX color 246 labelfont 1 labelsize 12 align 16
-              code0 {\#include "IntensityCurveBox.h"}
-              class IntensityCurveBox
-            }
-            Fl_Button {} {
-              label {&Reset}
-              callback {this->OnCurveReset();}
-              tooltip {Reset the curve, making it linear} xywh {500 340 50 25} box PLASTIC_UP_BOX shortcut 0x80072 labelsize 12
-            }
-            Fl_Group {} {
-              label {input image intensity} open
-              xywh {210 315 340 10} labelsize 11 align 24
-            } {}
-            Fl_Group {} {open
-              image {Artwork/outputintensity.gif} xywh {198 135 15 125} align 24
-            } {}
-            Fl_Button {} {
-              label {+}
-              callback {this->OnControlPointMoreAction();}
-              tooltip {Insert a control point into the curve} xywh {440 340 25 25} box PLASTIC_UP_BOX shortcut 0x3d labelfont 4 labelsize 18
-            }
-            Fl_Button m_BtnCurveLessControlPoint {
-              label {-}
-              callback {this->OnControlPointLessAction();}
-              tooltip {Delete the current control point} xywh {470 340 25 25} box PLASTIC_UP_BOX shortcut 0x2d labelfont 4 labelsize 18
-            }
-            Fl_Value_Input m_InControlX {
-              label {Input Intensity:}
-              callback {this->OnControlPointTextBoxUpdate();}
-              tooltip {Image intensity (x coordinate) of the selected control point} xywh {210 340 90 25} labelsize 12 align 5 when 4 step 0.01 textsize 12
-            }
-            Fl_Value_Input m_InControlY {
-              label {Output Intensity:}
-              callback {this->OnControlPointTextBoxUpdate();}
-              tooltip {Y coordinate of the selected control point (between 0 and 1)} xywh {315 340 90 25} labelsize 12 align 5 when 4 step 0.01 textsize 12
-            }
-          }
-          Fl_Group {} {
-            label {Histogram Options:} open
-            xywh {190 400 370 45} box PLASTIC_DOWN_BOX color 55 labelfont 1 labelsize 12 align 5
-          } {
-            Fl_Value_Input m_InHistogramMaxLevel {
-              label {Cutoff (%):}
-              callback {this->OnUpdateHistogram();}
-              tooltip {Affects vertical scaling of the histogram. Use it when histogram is dominated by one or two very tall bars.} xywh {385 410 55 25} labelsize 12 when 4 maximum 100 step 0.5 value 100 textsize 12
-            }
-            Fl_Value_Input m_InHistogramBinSize {
-              label {Bin size:}
-              callback {this->OnUpdateHistogram();}
-              xywh {250 410 55 25} labelsize 12 when 4 minimum 1 maximum 65535 step 1 value 5 textsize 12
-            }
-            Fl_Check_Button m_ChkHistogramLog {
-              label {Log scale}
-              callback {this->OnUpdateHistogram();}
-              tooltip {Toggle between linear and logarithmic scale for the histogram y axis} xywh {470 410 80 25} down_box DOWN_BOX labelsize 12
-            }
-            Fl_Button {} {
-              label {Update Histogram}
-              callback {this->OnUpdateHistogram();}
-              xywh {445 440 115 5} box PLASTIC_UP_BOX shortcut 0xff1b selection_color 38 labelsize 12 hide deactivate
-            }
-          }
-        }
-        Fl_Group m_ColorMapTab {
-          label {Color Map} open
-          xywh {180 25 390 455} labelsize 12 hide
-        } {
-          Fl_Group {} {
-            label {Color Map Editor:} open
-            xywh {190 135 370 200} box PLASTIC_DOWN_BOX labelfont 1 labelsize 12 align 5
-          } {
-            Fl_Box m_BoxColorMap {
-              label {OpenGL Colormap Display}
-              xywh {200 143 350 69} box BORDER_BOX color 246 labelfont 1 labelsize 12
-              code0 {\#include "ColorMapWidget.h"}
-              class ColorMapWidget
-            }
-            Fl_Box m_InColorMapRGBA {
-              label {color chooser}
-              callback {this->OnColorMapRGBAUpdate()}
-              xywh {330 219 220 107} box BORDER_BOX labelsize 11
-              code0 {\#include <FL/Fl_Color_Chooser.H>}
-              class Fl_Color_Chooser
-            }
-            Fl_Value_Input m_InColorMapIndex {
-              label {Color Index:}
-              callback {this->OnColorMapIndexUpdate();}
-              tooltip {The x-coordinate of the selected control point. This corresponds to the y-coordinate of the contrast adjustment curve.} xywh {200 235 65 25} labelsize 12 align 5 when 4 step 0.01 textsize 12
-            }
-            Fl_Choice m_InColorMapSide {
-              label {Side:}
-              callback {this->OnColorMapSideUpdate();} open
-              tooltip {Color map may be discontinuous at control points. Select 'Left' or 'Right' to introduce a discontinuity. Select 'Both' to make a control point continuous.} xywh {200 280 70 25} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-            } {
-              MenuItem m_MenuColorMapBoth {
-                label Both
-                xywh {5 5 31 20} labelsize 12
-              }
-              MenuItem m_MenuColorMapLeft {
-                label Left
-                xywh {15 15 31 20} labelsize 12
-              }
-              MenuItem m_MenuColorMapRight {
-                label Right
-                xywh {25 25 31 20} labelsize 12
-              }
-            }
-            Fl_Button m_BtnColorMapDeletePoint {
-              label delete
-              callback {this->OnColorMapPointDelete();}
-              tooltip {Delete the current control point} xywh {275 235 45 25} box PLASTIC_UP_BOX shortcut 0x2d labelsize 10
-            }
-          }
-          Fl_Group {} {
-            label {Presets:} open
-            xywh {190 55 370 55} box PLASTIC_DOWN_BOX labelfont 1 labelsize 12 align 5
-          } {
-            Fl_Button {} {
-              label {+}
-              callback {this->OnColorMapAddPresetAction();}
-              tooltip {Save current color map as a preset for future use} xywh {495 75 25 25} box PLASTIC_UP_BOX shortcut 0x3d labelfont 4 labelsize 18
-            }
-            Fl_Button {} {
-              label {-}
-              callback {this->OnColorMapDeletePresetAction();}
-              tooltip {Delete selected preset} xywh {525 75 25 25} box PLASTIC_UP_BOX shortcut 0x2d labelfont 4 labelsize 18
-            }
-            Fl_Choice m_InColorMapPreset {
-              label {Select a color map::}
-              callback {this->OnColorMapPresetUpdate()} open
-              xywh {200 75 280 25} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-            } {}
-          }
-        }
-        Fl_Group m_ImageInfoTab {
-          label Information open selected
-          xywh {180 25 390 455} labelsize 12
-        } {
-          Fl_Group {} {
-            label Dimensions open
-            xywh {190 59 370 1} box BORDER_FRAME color 8 labelfont 1 labelsize 12 align 5
-          } {}
-          Fl_Value_Output {m_OutImageInfoDimensions[0]} {
-            label {x:}
-            xywh {325 65 65 25} labelsize 12 textsize 12
-          }
-          Fl_Value_Output {m_OutImageInfoDimensions[1]} {
-            label {y:}
-            xywh {410 65 65 25} labelsize 12 textsize 12
-          }
-          Fl_Value_Output {m_OutImageInfoDimensions[2]} {
-            label {z:}
-            xywh {495 65 65 25} labelsize 12 textsize 12
-          }
-          Fl_Group {} {
-            label {Voxel Spacing (mm)} open
-            xywh {190 114 370 1} box BORDER_FRAME color 8 labelfont 1 labelsize 12 align 5
-          } {}
-          Fl_Value_Output {m_OutImageInfoSpacing[0]} {
-            label {x:}
-            xywh {325 120 65 25} labelsize 12 step 4 textsize 12
-            code0 {\#include "SNAPValueOutput.h"}
-            class SNAPValueOutput
-          }
-          Fl_Value_Output {m_OutImageInfoSpacing[1]} {
-            label {y:}
-            xywh {410 120 65 25} labelsize 12 step 4 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Value_Output {m_OutImageInfoSpacing[2]} {
-            label {z:}
-            xywh {495 120 65 25} labelsize 12 step 4 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Group {} {
-            label {Origin and Orientation} open
-            xywh {190 169 370 1} box BORDER_FRAME color 8 labelfont 1 labelsize 12 align 5
-          } {}
-          Fl_Value_Output {m_OutImageInfoOrigin[0]} {
-            label {x:}
-            xywh {325 175 65 25} labelsize 12 step 4 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Value_Output {m_OutImageInfoOrigin[1]} {
-            label {y:}
-            xywh {410 175 65 25} labelsize 12 step 4 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Value_Output {m_OutImageInfoOrigin[2]} {
-            label {z:}
-            xywh {495 175 65 25} labelsize 12 step 4 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Output m_OutImageInfoOriginRAICode {
-            label {RAI Code:}
-            xywh {410 206 150 23} color 49 labelsize 12 textsize 12
-          }
-          Fl_Group {} {
-            label {Crosshair Position} open
-            xywh {190 254 370 1} box BORDER_FRAME color 8 labelfont 1 labelsize 12 align 5
-          } {}
-          Fl_Value_Output {m_OutImageInfoCursorPosition[0]} {
-            label {x:}
-            xywh {325 290 65 25} labelsize 12 step 4 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Value_Output {m_OutImageInfoCursorPosition[1]} {
-            label {y:}
-            xywh {410 290 65 25} labelsize 12 step 4 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Value_Output {m_OutImageInfoCursorPosition[2]} {
-            label {z:}
-            xywh {495 290 65 25} labelsize 12 step 4 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Value_Output {m_OutImageInfoCursorNIFTIPosition[0]} {
-            label {x:}
-            xywh {325 320 65 25} labelsize 12 step 4 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Value_Output {m_OutImageInfoCursorNIFTIPosition[1]} {
-            label {y:}
-            xywh {410 320 65 25} labelsize 12 step 4 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Value_Output {m_OutImageInfoCursorNIFTIPosition[2]} {
-            label {z:}
-            xywh {495 320 65 25} labelsize 12 step 4 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Value_Input {m_InImageInfoCursorIndex[0]} {
-            label {x:}
-            callback {this->OnImageInformationVoxelCoordinatesUpdate();}
-            xywh {325 260 65 25} labelsize 12 textsize 12
-          }
-          Fl_Value_Input {m_InImageInfoCursorIndex[1]} {
-            label {y:}
-            callback {this->OnImageInformationVoxelCoordinatesUpdate();}
-            xywh {410 260 65 25} labelsize 12 textsize 12
-          }
-          Fl_Value_Input {m_InImageInfoCursorIndex[2]} {
-            label {z:}
-            callback {this->OnImageInformationVoxelCoordinatesUpdate();}
-            xywh {495 260 65 25} labelsize 12 textsize 12
-          }
-          Fl_Group {} {open
-            xywh {300 260 15 24}
-          } {}
-          Fl_Group {} {
-            label {Voxel
-coordinates} open
-            xywh {210 260 90 25} labelsize 11 labelcolor 30 align 20
-          } {}
-          Fl_Group {} {
-            label {World (ITK)
-coordinates} open
-            xywh {210 290 90 25} labelsize 11 labelcolor 30 align 20
-          } {}
-          Fl_Group {} {
-            label {World (NIFTI)
-coordinates} open
-            xywh {210 320 90 25} labelsize 11 labelcolor 30 align 20
-          } {}
-          Fl_Group {} {
-            label {Intensity Range} open
-            xywh {190 374 370 1} box BORDER_FRAME color 8 labelfont 1 labelsize 12 align 5
-          } {}
-          Fl_Value_Output {m_OutImageInfoRange[0]} {
-            label {min:}
-            xywh {325 380 95 25} labelsize 12 step 6 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Value_Output {m_OutImageInfoRange[1]} {
-            label {max:}
-            xywh {465 380 95 25} labelsize 12 step 6 textsize 12
-            class SNAPValueOutput
-          }
-          Fl_Group {} {
-            label {Voxel Under the Cursor} open
-            xywh {190 429 370 1} box BORDER_FRAME color 8 labelfont 1 labelsize 12 align 5
-          } {}
-          Fl_Wizard m_WizImageInfoVoxelValue {open
-            xywh {200 435 360 25} box NO_BOX
-          } {
-            Fl_Group m_GrpWizImageInfoVoxelPageGray {open
-              xywh {200 435 350 25} hide
-            } {
-              Fl_Value_Output m_OutImageInfoVoxelGray {
-                label {Intensity:}
-                xywh {455 435 95 25} labelsize 12 step 6 textsize 12
-                class SNAPValueOutput
-              }
-            }
-            Fl_Group m_GrpWizImageInfoVoxelPageRGB {open
-              xywh {200 435 360 25}
-            } {
-              Fl_Value_Output {m_OutImageInfoVoxelRGB[0]} {
-                label {R:}
-                xywh {325 435 65 25} labelsize 12 step 4 textsize 12
-                class SNAPValueOutput
-              }
-              Fl_Value_Output {m_OutImageInfoVoxelRGB[1]} {
-                label {G:}
-                xywh {410 435 65 25} labelsize 12 step 4 textsize 12
-                class SNAPValueOutput
-              }
-              Fl_Value_Output {m_OutImageInfoVoxelRGB[2]} {
-                label {B:}
-                xywh {495 435 65 25} labelsize 12 step 4 textsize 12
-                class SNAPValueOutput
-              }
-            }
-          }
-        }
-        Fl_Group m_ImageAdvancedInfoTab {
-          label {Advanced Info} open
-          xywh {180 25 390 455} labelsize 12 hide
-        } {
-          Fl_Box m_TableMetaData {
-            label label
-            xywh {190 58 370 200} selection_color 246 labeltype NO_LABEL
-            code0 {\#include "MetaDataTable.h"}
-            class MetaDataTable
-          }
-          Fl_Group {} {
-            label {Image Header Contents} open
-            xywh {190 54 370 1} box BORDER_FRAME color 8 labelfont 1 labelsize 12 align 5
-          } {}
-        }
-      }
-      Fl_Group {} {open
-        xywh {0 0 170 490} box FLAT_BOX labeltype ENGRAVED_LABEL labelsize 16 align 17 resizable
-      } {
-        Fl_Group {} {
-          label {Layer Inspector} open
-          xywh {10 25 150 1} box FLAT_BOX color 0 labeltype EMBOSSED_LABEL labelfont 1 labelcolor 136 align 5
-        } {}
-        Fl_Value_Slider m_InOverallOpacity {
-          label {Overall opacity:}
-          callback {this->OnOverallOpacityUpdate()}
-          xywh {10 185 150 20} type Horizontal labelsize 12 align 5 textsize 11
-        }
-        Fl_Button {} {
-          label Close
-          callback {this->OnCloseAction()}
-          xywh {45 455 80 25} box PLASTIC_UP_BOX color 139 labelfont 1 labelsize 12
-        }
-        Fl_Browser m_BrsLayers {
-          label {Image Layers:}
-          callback {this->OnLayerSelectionUpdate()}
-          xywh {10 60 150 100} type Hold labelsize 12 align 5 textsize 11
-        }
-        Fl_Group {} {
-          label {Use Q,W,E keys to adjust} open
-          xywh {10 205 150 25} labelsize 10 labelcolor 96 align 17
-        } {}
-      }
-      Fl_Group {} {open
-        xywh {170 0 1 490} box FLAT_BOX color 0
-      } {}
-    }
-  }
-} 
diff --git a/UserInterface/MainComponents/LayerInspectorUIBase.h b/UserInterface/MainComponents/LayerInspectorUIBase.h
deleted file mode 100644
index 6aa7f9f..0000000
--- a/UserInterface/MainComponents/LayerInspectorUIBase.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: LayerInspectorUIBase.h,v $
-  Language:  C++
-  Date:      $Date: 2009/09/16 20:03:13 $
-  Version:   $Revision: 1.6 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __LayerInspectorUIBase_h_
-#define __LayerInspectorUIBase_h_
-
-/**
- * \class LayerInspectorUIBase
- * \brief Base class for Layer editor UI logic
- */
-class LayerInspectorUIBase 
-{
-public:
-  virtual ~LayerInspectorUIBase() {}
-
-  // Callbacks for the main pane
-  virtual void DisplayWindow() = 0;
-  virtual void OnLayerSelectionUpdate() = 0;
-  virtual void OnOverallOpacityUpdate() = 0;
-  virtual void OnCloseAction() = 0;
-
-  // Callbacks for the contrast adjustment page
-  virtual void DisplayImageContrastTab() = 0;
-  virtual void OnCurveReset() = 0;
-  virtual void OnAutoFitWindow() = 0;
-  virtual void OnWindowLevelChange() = 0;
-  virtual void OnUpdateHistogram() = 0;
-  virtual void OnControlPointMoreAction() = 0;
-  virtual void OnControlPointLessAction() = 0;
-  virtual void OnControlPointTextBoxUpdate() = 0;
-  virtual void OnControlPointUpdate() = 0;
-
-  // Callbacks for the color map page
-  virtual void DisplayColorMapTab() = 0;
-  virtual void OnColorMapPresetUpdate() = 0;
-  virtual void OnColorMapAddPresetAction() = 0;
-  virtual void OnColorMapDeletePresetAction() = 0;
-  virtual void OnColorMapIndexUpdate() = 0;
-  virtual void OnColorMapSideUpdate() = 0;
-  virtual void OnColorMapPointDelete() = 0;
-  virtual void OnColorMapRGBAUpdate() = 0;
-
-  // Callbacks for the image info page
-  virtual void DisplayImageInfoTab() = 0;
-  virtual void OnImageInformationVoxelCoordinatesUpdate() = 0;
-};
-
-#endif
diff --git a/UserInterface/MainComponents/LayerInspectorUILogic.cxx b/UserInterface/MainComponents/LayerInspectorUILogic.cxx
deleted file mode 100644
index 98990ec..0000000
--- a/UserInterface/MainComponents/LayerInspectorUILogic.cxx
+++ /dev/null
@@ -1,1115 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: LayerInspectorUILogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2011/04/18 15:06:07 $
-  Version:   $Revision: 1.27 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-
-#include "LayerInspectorUILogic.h"
-#include "IntensityCurveVTK.h"
-#include "UserInterfaceLogic.h"
-#include "IRISApplication.h"
-#include "GenericImageData.h"
-#include "GreyImageWrapper.h"
-
-LayerInspectorUILogic
-::LayerInspectorUILogic(UserInterfaceLogic *parent)
-{
-  m_Parent = parent;
-  m_Driver = m_Parent->GetDriver();
-  m_MainWrapper = NULL;
-  m_OverlayWrappers = NULL;
-  m_SelectedWrapper = NULL;
-  m_GreyWrapper = NULL;
-  m_Curve = NULL;
-}
-
-void
-LayerInspectorUILogic
-::Initialize()
-{
-  // Color map
-  m_BoxColorMap->SetParent(this);
-  PopulateColorMapPresets();
-
-  // Intensity curve
-  m_BoxCurve->SetParent(this);
-
-  // Opacity
-  m_InOverallOpacity->maximum(255);
-  m_InOverallOpacity->minimum(0);
-  m_InOverallOpacity->step(1);
-}
-
-void
-LayerInspectorUILogic
-::SetImageWrappers()
-{
-  // Connect the image wrappers
-  m_MainWrapper = m_Driver->GetCurrentImageData()->GetMain();
-  m_OverlayWrappers = m_Driver->GetCurrentImageData()->GetOverlays();
-
-  // Build layer browser entries
-  m_BrsLayers->clear();
-  GreyImageWrapper *wrapper = dynamic_cast<GreyImageWrapper *>(m_MainWrapper);
-  if (wrapper)
-    m_BrsLayers->add("Main Image (Greyscale)");
-  else
-    m_BrsLayers->add("Main Image (RGB)");
-
-  WrapperIterator it = m_OverlayWrappers->begin();
-  while (it != m_OverlayWrappers->end())
-    {
-    GreyImageWrapper *wrapper = dynamic_cast<GreyImageWrapper *>(*it);
-    if (wrapper)
-      m_BrsLayers->add("Overlay (Greyscale)");
-    else
-      m_BrsLayers->add("Overlay (RGB)");
-    ++it;
-    }
-
-  // Select the last loaded image by default
-  m_BrsLayers->select(1 + m_OverlayWrappers->size());
-  OnLayerSelectionUpdate();
-}
-
-void
-LayerInspectorUILogic
-::DisplayWindow()
-{
-  if (m_LayerUITabs->value() == m_ImageContrastTab)
-    {
-    DisplayImageContrastTab(); 
-    }
-  else if (m_LayerUITabs->value() == m_ColorMapTab)
-    {
-    DisplayColorMapTab();
-    }
-  else if (m_LayerUITabs->value() == m_ImageInfoTab)
-    {
-    DisplayImageInfoTab();
-    }
-  else if (m_LayerUITabs->value() == m_ImageAdvancedInfoTab)
-    {
-    DisplayImageAdvancedInfoTab();
-    }
-}
-
-void
-LayerInspectorUILogic
-::DisplayImageContrastTab()
-{
-  m_BoxColorMap->hide();
-  m_WinLayerUI->show();
-  m_LayerUITabs->value(m_ImageContrastTab);
-  if (m_ImageContrastTab->active())
-    {
-    UpdateWindowAndLevel();
-    m_BoxCurve->redraw();
-    m_BoxCurve->show();
-    }
-}
-
-void
-LayerInspectorUILogic
-::DisplayColorMapTab()
-{
-  m_BoxCurve->hide();
-  m_WinLayerUI->show();
-  m_LayerUITabs->value(m_ColorMapTab);
-  if (m_ColorMapTab->active())
-    {
-    // Determine the currently used color map
-    ColorMap cm = m_GreyWrapper->GetColorMap();
-    // Update the GUI
-    m_InColorMapPreset->value(cm.GetSystemPreset());
-    m_BoxColorMap->SetColorMap(cm);
-    m_BoxColorMap->redraw();
-    m_BoxColorMap->show();
-    this->OnColorMapSelectedPointUpdate();
-    }
-}
-
-void
-LayerInspectorUILogic
-::DisplayImageInfoTab()
-{
-  m_BoxCurve->hide();
-  m_BoxColorMap->hide();
-  m_WinLayerUI->show();
-  m_LayerUITabs->value(m_ImageInfoTab);
-  UpdateImageProbe();
-}
-
-
-void
-LayerInspectorUILogic
-::DisplayImageAdvancedInfoTab()
-{
-  m_BoxCurve->hide();
-  m_BoxColorMap->hide();
-  m_WinLayerUI->show();
-  m_LayerUITabs->value(m_ImageAdvancedInfoTab);
-}
-
-
-void
-LayerInspectorUILogic
-::RedrawWindow()
-{
-  // Intensity curve
-  if (m_LayerUITabs->value() == m_ImageContrastTab && m_ImageContrastTab->active())
-    {
-    UpdateWindowAndLevel();
-    m_BoxCurve->redraw();
-    m_BoxCurve->show();
-    }
-  // Color map
-  else if (m_LayerUITabs->value() == m_ColorMapTab && m_ColorMapTab->active())
-    {
-    // Determine the currently used color map
-    ColorMap cm = m_GreyWrapper->GetColorMap();
-    // Update the GUI
-    m_InColorMapPreset->value(cm.GetSystemPreset());
-    m_BoxColorMap->SetColorMap(cm);
-    m_BoxColorMap->redraw();
-    m_BoxColorMap->show();
-    }
-  // Image info
-  else if (m_LayerUITabs->value() == m_ImageInfoTab)
-    {
-    UpdateImageProbe();
-    }
-  else if (m_LayerUITabs->value() == m_ImageAdvancedInfoTab)
-    {
-    }
-}
-
-bool
-LayerInspectorUILogic
-::Shown()
-{
-  return m_WinLayerUI->shown();
-}
-
-// Callbacks for the main pane
-void 
-LayerInspectorUILogic
-::OnLayerSelectionUpdate()
-{
-  // If user click the empty space in the browser window
-  if (m_BrsLayers->value() == 0)
-    return;
-
-  // Determine the corresponding image wrapper
-  if (m_BrsLayers->value() == 1)
-    {
-    m_SelectedWrapper = m_MainWrapper;
-    m_InOverallOpacity->deactivate();
-    }
-  else
-    {
-    WrapperIterator it = m_OverlayWrappers->begin();
-    for (int i = 2; i < m_BrsLayers->value(); ++i)
-      ++it;
-    assert(it != m_OverlayWrappers->end());
-    m_SelectedWrapper = *it;
-    m_InOverallOpacity->activate();
-    }
-
-  // Overall Opacity
-  m_InOverallOpacity->value(m_SelectedWrapper->GetAlpha());
-
-  // Hook it up with the GUI
-  m_GreyWrapper = dynamic_cast<GreyImageWrapper *>(m_SelectedWrapper);
-  if (m_GreyWrapper)
-    {
-    m_ImageContrastTab->activate();
-    m_ColorMapTab->activate();
-    // associate with intensity curve UI
-    m_Curve = m_GreyWrapper->GetIntensityMapFunction();
-    if (m_Curve->GetControlPointCount() == 3)
-      m_BtnCurveLessControlPoint->deactivate();
-    m_BoxCurve->SetCurve(m_Curve);
-    m_BoxCurve->SetHistogramBinSize(1);
-    m_BoxCurve->ComputeHistogram(m_GreyWrapper, 4);
-
-    m_InHistogramMaxLevel->value(m_BoxCurve->GetHistogramMaxLevel() * 100.f);
-    m_InHistogramBinSize->value(m_BoxCurve->GetHistogramBinSize());
-    m_ChkHistogramLog->value(m_BoxCurve->IsHistogramLog());
-    // associate with color map UI (if needed)
-    // associate with image info: greyscale specific
-    m_OutImageInfoRange[0]->value(m_GreyWrapper->GetImageMinNative());
-    m_OutImageInfoRange[1]->value(m_GreyWrapper->GetImageMaxNative());
-    }
-  else
-    {
-    m_ImageContrastTab->deactivate();
-    m_BoxCurve->hide();
-    m_ColorMapTab->deactivate();
-    m_BoxColorMap->hide();
-    // associate with image info: RGB specific
-    m_OutImageInfoRange[0]->value(0);
-    m_OutImageInfoRange[1]->value(0);
-    }
-
-  // associate with image info: common
-  for (unsigned int d = 0; d < 3; ++d)
-    {
-    m_OutImageInfoDimensions[d]->value(m_SelectedWrapper->GetSize()[d]);
-    m_OutImageInfoOrigin[d]->value(m_SelectedWrapper->GetImageBase()->GetOrigin()[d]);
-    m_OutImageInfoOrigin[d]->maximum(m_OutImageInfoOrigin[d]->value());
-    m_OutImageInfoOrigin[d]->minimum(m_OutImageInfoOrigin[d]->value());
-    m_OutImageInfoSpacing[d]->value(m_SelectedWrapper->GetImageBase()->GetSpacing()[d]);
-    m_OutImageInfoSpacing[d]->maximum(m_OutImageInfoSpacing[d]->value());
-    m_OutImageInfoSpacing[d]->minimum(m_OutImageInfoSpacing[d]->value());
-    m_InImageInfoCursorIndex[d]->maximum(m_SelectedWrapper->GetSize()[d] - 1);
-    m_InImageInfoCursorIndex[d]->minimum(0);
-    m_InImageInfoCursorIndex[d]->step(1);
-    }
-
-  // get the RAI code
-  ImageCoordinateGeometry::DirectionMatrix dmat =
-    m_Driver->GetCurrentImageData()->GetImageGeometry().GetImageDirectionCosineMatrix();
-  string raicode =
-    ImageCoordinateGeometry::ConvertDirectionMatrixToClosestRAICode(dmat);
-  string raitext;
-  if (ImageCoordinateGeometry::IsDirectionMatrixOblique(dmat))
-    raitext = string("Oblique (closest to ") + raicode + string(")");
-  else
-    raitext = raicode;
-  m_OutImageInfoOriginRAICode->value(raitext.c_str());
-
-  // Uodate the information table
-  m_TableMetaData->SetInputImage(m_SelectedWrapper->GetImageBase());
-  m_TableMetaData->SetColumnWidth(370);
-
-  // update GUI
-  if (Shown())
-    RedrawWindow();
-}
-
-void 
-LayerInspectorUILogic
-::OnOverallOpacityUpdate()
-{
-  m_SelectedWrapper->SetAlpha((unsigned char) m_InOverallOpacity->value());
-  m_Parent->RedrawWindows();
-}
-
-void
-LayerInspectorUILogic
-::AdjustOverlayOpacity(double delta)
-{
-  // If the selected wrapper is an overlay, adjust it's opacity
-  if(m_SelectedWrapper != m_MainWrapper)
-    {
-    double alpha = (double) m_SelectedWrapper->GetAlpha() + delta;
-    if(alpha < 0) alpha = 0;
-    if(alpha > 255) alpha = 255;
-    m_SelectedWrapper->SetAlpha((unsigned char) alpha);
-    m_InOverallOpacity->value(alpha);
-    }
-
-  // Otherwise, adjust all the overlays
-  else
-    {
-    for(WrapperList::iterator it = m_OverlayWrappers->begin();
-      it != m_OverlayWrappers->end(); it++)
-      {
-      double alpha = (double) (*it)->GetAlpha() + delta;
-      if(alpha < 0) alpha = 0;
-      if(alpha > 255) alpha = 255;
-      (*it)->SetAlpha((unsigned char) alpha);
-      }
-    }
-
-  m_Parent->RedrawWindows();
-}
-
-void
-LayerInspectorUILogic
-::ToggleOverlayVisibility()
-{
-  // If the selected wrapper is an overlay, adjust it's opacity
-  if(m_SelectedWrapper != m_MainWrapper)
-    {
-    // Get current alpha value
-    m_SelectedWrapper->ToggleVisibility();
-    m_InOverallOpacity->value(m_SelectedWrapper->GetAlpha());
-    }
-
-  // Otherwise, adjust all the overlays
-  else
-    {
-    for(WrapperList::iterator it = m_OverlayWrappers->begin();
-      it != m_OverlayWrappers->end(); it++)
-      {
-      (*it)->ToggleVisibility();
-      }
-    }  
-
-  m_Parent->RedrawWindows();
-}
-
-void 
-LayerInspectorUILogic
-::OnCloseAction()
-{
-  m_WinLayerUI->hide();
-}
-
-// Callbacks for the contrast adjustment page
-void 
-LayerInspectorUILogic
-::OnCurveReset()
-{
-  // Reinitialize the curve
-  m_Curve->Initialize();
-
-  // Update the controlX/controlY
-  OnControlPointUpdate();
-
-  // Fire the reset event
-  OnCurveChange();
-}
-
-void
-LayerInspectorUILogic
-::UpdateWindowAndLevel()
-{
-  // Need a curve and a wrapper
-  assert(m_Curve && m_GreyWrapper);
-
-  // This is the range of the curve in unit coordinates (0 to 1)
-  float t0,x0,t1,x1;
-
-  // Get the starting and ending control points
-  m_Curve->GetControlPoint(0,t0,x0);
-  m_Curve->GetControlPoint(m_Curve->GetControlPointCount()-1,t1,x1);
-
-  // Get 'absolute' image intensity range, i.e., the largest and smallest
-  // intensity in the whole image
-  double iAbsMin = m_GreyWrapper->GetImageMinNative();
-  double iAbsMax = m_GreyWrapper->GetImageMaxNative();
-  double iAbsSpan = (iAbsMax - iAbsMin);
-
-  // The the curve intensity range
-  double iMin = iAbsMin + iAbsSpan * t0; 
-  double iMax = iAbsMin + iAbsSpan * t1;
-
-  // Compute the level and window in intensity units
-  double level = iMin;
-  double window = iMax - iMin;
-
-  // The step is set dynamically, so that there are on the order of 
-  // 1000 steps to cover the whole intensity range. That should give
-  // a good tradeoff between precision and control. 
-  double step = pow(10, floor(0.5 + log10(iAbsSpan) - 3)); 
-  m_InWindow->step(step);
-  m_InWindow->step(step);
-  m_InControlX->step(step);
-
-  // Compute and constrain the level 
-  m_InLevel->value(level);
-  m_InLevel->minimum(iAbsMin);
-  m_InLevel->maximum(iAbsMax - window);
-
-  // Compute and constrain the window
-  m_InWindow->value(window);
-  m_InWindow->minimum(step);
-  m_InWindow->maximum(iAbsMax - level);
-
-  // In addition to window and level, we set up the valuators for
-  // the current control point
-  int cp = m_BoxCurve->GetInteractor()->GetMovingControlPoint();
-  if(cp >= 0)
-    {
-    if(cp == 0)
-      {
-      m_InControlX->minimum(iAbsMin);
-      }
-    else
-      {
-      m_Curve->GetControlPoint(cp - 1, t0, x0);
-      m_InControlX->minimum(iAbsMin + iAbsSpan * t0 + step);
-      }
-
-    if(cp == (int)(m_Curve->GetControlPointCount() - 1))
-      {
-      m_InControlX->maximum(iAbsMax);
-      }
-    else
-      {
-      m_Curve->GetControlPoint(cp + 1, t1, x1);
-      m_InControlX->maximum(iAbsMin + iAbsSpan * t1 - step);
-      }
-
-    if(cp == 0 || cp == (int)(m_Curve->GetControlPointCount() - 1))
-      {
-      m_InControlY->deactivate();
-      }
-    else
-      {
-      m_InControlY->activate();
-      m_InControlY->minimum(x0 + 0.01);
-      m_InControlY->maximum(x1 + 0.01);
-      m_InControlY->step(0.01);
-      }    
-
-    // Set the actual value
-    float t, x;
-    m_Curve->GetControlPoint(cp, t, x);
-    m_InControlX->activate();
-    m_InControlX->value(iAbsMin + iAbsSpan * t);
-    m_InControlY->value(x);
-    }
-  else
-    {
-    m_InControlX->deactivate();
-    m_InControlY->deactivate();
-    }
-}
-
-void
-LayerInspectorUILogic
-::OnCurveChange()
-{
-  m_BoxColorMap->hide();
-  // Update the values of the window and level
-  UpdateWindowAndLevel();
-
-  // Redraw the window
-  m_BoxCurve->redraw();
-  m_BoxCurve->show();
-
-  // Update the image wrapper
-  m_GreyWrapper->UpdateIntensityMapFunction();
-
-  // Redraw parent
-  m_Parent->RedrawWindows();
-}
-
-void 
-LayerInspectorUILogic
-::OnAutoFitWindow()
-{
-  // Get the histogram
-  const std::vector<unsigned int> &hist = m_BoxCurve->GetHistogram();
-
-  // Integrate the histogram until reaching 0.1%
-  GreyType imin = m_GreyWrapper->GetImageMin();
-  GreyType ilow = imin;
-  size_t accum = 0;
-  size_t accum_goal = m_GreyWrapper->GetNumberOfVoxels() / 1000;
-  for(size_t i = 0; i < hist.size(); i++)
-    {
-    if(accum + hist[i] < accum_goal)
-      {
-      accum += hist[i];
-      ilow += m_BoxCurve->GetHistogramBinSize();
-      }
-    else break;
-    }
-
-  // Same, but from above
-  GreyType imax = m_GreyWrapper->GetImageMax();
-  GreyType ihigh = imax;
-  accum = 0;
-  for(size_t i = hist.size() - 1; i >= 0; i--)
-    {
-    if(accum + hist[i] < accum_goal)
-      {
-      accum += hist[i];
-      ihigh -= m_BoxCurve->GetHistogramBinSize();
-      }
-    else break;
-    }
-
-  // If for some reason the window is off, we set everything to max/min
-  if(ilow >= ihigh)
-    { ilow = imin; ihigh = imax; }
-
-  // Compute and constrain the window
-  GreyTypeToNativeFunctor native = m_GreyWrapper->GetNativeMapping();
-  double ilowNative = native(ilow);
-  double ihighNative = native(ihigh);
-  double imaxNative = native(imax);
-  double iwin = ihighNative - ilowNative;
-
-  m_InWindow->maximum(imaxNative - ilowNative);
-  m_InWindow->value(iwin);
-
-  m_InLevel->maximum(imaxNative - iwin);
-  m_InLevel->value(ilowNative);  
-
-  OnWindowLevelChange();
-}
-
-
-void 
-LayerInspectorUILogic
-::OnWindowLevelChange()
-{
-  // Assure that input and output outside of the image range
-  // is handled gracefully
-  // m_InLevel->value(m_InLevel->clamp(m_InLevel->value()));
-  // m_InWindow->value(m_InWindow->clamp(m_InWindow->value()));
-
-  // Get 'absolute' image intensity range, i.e., the largest and smallest
-  // intensity in the whole image
-  double iAbsMin = m_GreyWrapper->GetImageMinNative();
-  double iAbsMax = m_GreyWrapper->GetImageMaxNative();
-
-  // Get the new values of min and max
-  double iMin = m_InLevel->value();
-  double iMax = iMin + m_InWindow->value();
-
-  // Min better be less than max
-  assert(iMin < iMax);
-
-  // Compute the unit coordinate values that correspond to min and max
-  float factor = 1.0f / (iAbsMax - iAbsMin);
-  float t0 = factor * (iMin - iAbsMin);
-  float t1 = factor * (iMax - iAbsMin);
-
-  // Update the curve boundary
-  m_Curve->ScaleControlPointsToWindow(t0,t1);
-
-  // Update the controlX/controlY
-  OnControlPointUpdate();
-
-  // Fire the reset event
-  OnCurveChange();
-}
-
-void 
-LayerInspectorUILogic
-::OnUpdateHistogram()
-{
-  // Recompute the histogram and redisplay
-  m_BoxCurve->SetHistogramBinSize((size_t) m_InHistogramBinSize->value());
-  m_BoxCurve->SetHistogramMaxLevel(m_InHistogramMaxLevel->value() / 100.0f);
-  m_BoxCurve->SetHistogramLog(m_ChkHistogramLog->value() ? true : false);
-  m_BoxCurve->ComputeHistogram(m_GreyWrapper, 1);
-  m_BoxCurve->redraw();
-
-  // The histogram controls may have changed. Update them
-  m_InHistogramMaxLevel->value(m_BoxCurve->GetHistogramMaxLevel() * 100.0);
-  m_InHistogramBinSize->value(m_BoxCurve->GetHistogramBinSize());
-}
-
-void 
-LayerInspectorUILogic
-::OnControlPointMoreAction()
-{
-  m_Curve->Initialize(m_Curve->GetControlPointCount() + 1);
-  if (m_Curve->GetControlPointCount() > 3)
-    m_BtnCurveLessControlPoint->activate();
-  OnWindowLevelChange();
-}
-
-void 
-LayerInspectorUILogic
-::OnControlPointLessAction()
-{
-  if (m_Curve->GetControlPointCount() > 3)
-    {
-    m_Curve->Initialize(m_Curve->GetControlPointCount() - 1);
-    m_BoxCurve->GetInteractor()->SetMovingControlPoint(0);
-    OnWindowLevelChange();
-    }
-  if (m_Curve->GetControlPointCount() == 3)
-    m_BtnCurveLessControlPoint->deactivate();
-}
-
-void
-LayerInspectorUILogic
-::OnControlPointTextBoxUpdate()
-{
-  // Get the values of the control points
-  int cp = m_BoxCurve->GetInteractor()->GetMovingControlPoint();
-  if(cp >= 0)
-    {
-    // Get the range of the intensity
-    double imin = m_GreyWrapper->GetImageMinNative();
-    double imax = m_GreyWrapper->GetImageMaxNative();
-    double delta = imax - imin;
-
-    // Update the point, although the curve may reject these values
-    float tnew = (m_InControlX->value() - imin) / delta;
-    float xnew = m_InControlY->value();
-    bool accept = m_BoxCurve->UpdateControlPoint((size_t) cp, tnew, xnew);
-
-    // Update the text boxes with actual values
-    if(!accept)
-      {
-      float told, xold;
-      m_Curve->GetControlPoint(cp, told, xold);
-      m_InControlX->value(told * delta + imin);
-      m_InControlY->value(xold);
-      }
-    else
-      {
-      this->OnCurveChange();
-      }
-    }
-}
-
-
-
-void 
-LayerInspectorUILogic
-::OnControlPointUpdate()
-{
-  int cp = m_BoxCurve->GetInteractor()->GetMovingControlPoint();
-  float fx, fy;
-  m_Curve->GetControlPoint(cp, fx, fy);
-  const double min = m_GreyWrapper->GetImageMinNative();
-  const double max = m_GreyWrapper->GetImageMaxNative();
-  const double delta = max - min;
-  m_InControlX->value(fx*delta + min);
-  m_InControlY->value(fy);
-}
-
-// Callbacks for the color map page
-LayerInspectorUILogic::PresetInfo
-LayerInspectorUILogic::m_PresetInfo[] = {
-  {"Grayscale", 0x00ff0000},
-  {"Jet", 0x00000000},
-  {"Hot", 0x00000000},
-  {"Cool", 0x00000000},
-  {"Black to red", 0x00ff0000},
-  {"Black to green", 0xff000000},
-  {"Black to blue", 0xff000000},
-  {"Spring", 0x00000000},
-  {"Summer", 0x00000000},
-  {"Autumn", 0x00000000},
-  {"Winter", 0x00000000},
-  {"Copper", 0x00000000},
-  {"HSV", 0x00000000},
-  {"Blue, white and red", 0x00000000},
-  {"Red, white and blue", 0x00000000}};
-
-
-void
-LayerInspectorUILogic
-::OnColorMapChange()
-{
-  m_GreyWrapper->SetColorMap(m_BoxColorMap->GetColorMap());
-  m_GreyWrapper->UpdateIntensityMapFunction();
-  this->OnColorMapSelectedPointUpdate();
-
-  // Redraw parent
-  m_Parent->RedrawWindows();
-}
-
-void
-LayerInspectorUILogic
-::SelectNextColorMap()
-{
-  if(m_InColorMapPreset->size() <= 1)
-    return;
-
-  // Cycle through the available colormaps
-  int val = m_InColorMapPreset->value();
-  int newval = ( (val < 0 ? 0 : val) + 1) % (m_InColorMapPreset->size() - 1);
-  if(newval != val)
-    m_InColorMapPreset->value(newval);
-  this->OnColorMapPresetUpdate();
-}
-
-void 
-LayerInspectorUILogic
-::PopulateColorMapPresets()
-{
-  // Set the system presets
-  m_InColorMapPreset->clear();
-  for(int i = 0; i < ColorMap::COLORMAP_SIZE; i++)
-    {
-    if(i == ColorMap::COLORMAP_SIZE - 1)
-      {
-      string text = string("_") + m_PresetInfo[i].name;
-      m_InColorMapPreset->add(text.c_str());
-      }
-    else
-      {
-      m_InColorMapPreset->add(m_PresetInfo[i].name.c_str());
-      }
-    }
-
-  // Now add the custom presets
-  std::vector<string> saved = 
-    m_Driver->GetSystemInterface()->GetSavedObjectNames("ColorMaps");
-  for(int i = 0; i < (int) saved.size(); i++)
-    m_InColorMapPreset->add(saved[i].c_str());
-}
-
-void 
-LayerInspectorUILogic
-::OnColorMapPresetUpdate()
-{
-  ColorMap cm;
-  m_BoxCurve->hide();
-
-  // Apply the current preset
-  int sel = m_InColorMapPreset->value();
-  if(sel < 0)
-    return;
-
-  if(sel < ColorMap::COLORMAP_SIZE)
-    {
-    ColorMap::SystemPreset preset = 
-      (ColorMap::SystemPreset) (ColorMap::COLORMAP_GREY + sel);
-    
-    // Update the color map
-    cm.SetToSystemPreset(preset);
-    }
-  else
-    {
-    try 
-      {
-      Registry reg = 
-        m_Driver->GetSystemInterface()->ReadSavedObject(
-          "ColorMaps", m_InColorMapPreset->text(sel));
-      cm.LoadFromRegistry(reg);
-      }
-    catch(IRISException &exc)
-      {
-      fl_alert("Failed to read preset from file: \n%s", exc.what());
-      return;
-      }    
-    }
-
-  m_BoxColorMap->SetColorMap(cm);
-  m_BoxColorMap->SetSelectedCMPoint(-1);
-  m_BoxColorMap->redraw();
-  m_BoxColorMap->show();
-
-  // Update the image
-  m_GreyWrapper->SetColorMap(cm);
-  m_GreyWrapper->UpdateIntensityMapFunction();
-  
-  // Redraw parent
-  m_Parent->RedrawWindows();
-
-  this->OnColorMapSelectedPointUpdate();
-}
-
-void 
-LayerInspectorUILogic
-::OnColorMapAddPresetAction()
-{
-  // What default to recommend?
-  int sel = m_InColorMapPreset->value();
-  string deflt = (sel < ColorMap::COLORMAP_SIZE)
-    ? string("My ") + m_InColorMapPreset->text(sel)
-    : m_InColorMapPreset->text(sel);
-
-  // Prompt the user for the name
-  const char *name = fl_input("How do you want to name your preset?", deflt.c_str());
-  if(!name || strlen(name) == 0)
-    return;
-
-  // Create a registry
-  Registry reg;
-  m_BoxColorMap->GetColorMap().SaveToRegistry(reg);
-
-  // Write to file
-  m_Driver->GetSystemInterface()->UpdateSavedObject("ColorMaps",name,reg);
-
-  // Refresh the list of presents
-  PopulateColorMapPresets();
-
-  // Set the current preset as the selection
-  m_InColorMapPreset->value(-1);
-  for(int i = 0; i < m_InColorMapPreset->size(); i++)
-    if(!strcmp(m_InColorMapPreset->text(i), name))
-      { m_InColorMapPreset->value(i); break; }
-}
-
-void 
-LayerInspectorUILogic
-::OnColorMapDeletePresetAction()
-{
-  int sel = m_InColorMapPreset->value();
-  if(sel >= ColorMap::COLORMAP_SIZE)
-    {
-    // Delete the bad one
-    string name = m_InColorMapPreset->text(sel);
-    m_Driver->GetSystemInterface()->DeleteSavedObject("ColorMaps",name.c_str());
-
-    // Refresh the list of presents
-    PopulateColorMapPresets();
-
-    // Select the next color map
-    if(sel < m_InColorMapPreset->size()-1)
-      m_InColorMapPreset->value(sel);
-    else
-      m_InColorMapPreset->value(m_InColorMapPreset->size() - 2);
-    this->OnColorMapPresetUpdate();
-    }
-}
-
-void 
-LayerInspectorUILogic
-::OnColorMapSelectedPointUpdate()
-{
-  // Get the selected color map point
-  int sel = m_BoxColorMap->GetSelectedCMPoint();
-  ColorMapWidget::Side side = m_BoxColorMap->GetSelectedSide();
-
-  if(sel >= 0)
-    {
-    // Activate relevant widgets
-    m_InColorMapSide->activate();
-    m_InColorMapIndex->activate();
-    // m_InColorMapRGBA->activate();
-
-    // Get color
-    ColorMap &cm = this->m_BoxColorMap->GetColorMap();
-    ColorMap::CMPoint p = cm.GetCMPoint(sel);
-
-    // Handle continuous points
-    if(p.m_Type == ColorMap::CONTINUOUS)
-      {
-      // Set the RGB value
-      m_InColorMapRGBA->rgb(p.m_RGBA[0][0] / 255.0, p.m_RGBA[0][1] / 255.0, p.m_RGBA[0][2] / 255.0);
-
-      // Set the location to 'both'
-      m_InColorMapSide->value(0);
-      }
-    else if(side == ColorMapWidget::LEFT)
-      {
-      // Set the RGB value
-      m_InColorMapRGBA->rgb(p.m_RGBA[0][0] / 255.0, p.m_RGBA[0][1] / 255.0, p.m_RGBA[0][2] / 255.0);
-
-      // Set the location to 'both'
-      m_InColorMapSide->value(1);
-      }
-    else if(side == ColorMapWidget::RIGHT)
-      {
-      // Set the RGB value
-      m_InColorMapRGBA->rgb(p.m_RGBA[1][0] / 255.0, p.m_RGBA[1][1] / 255.0, p.m_RGBA[1][2] / 255.0);
-
-      // Set the location to 'both'
-      m_InColorMapSide->value(2);
-      }
-
-    // Set the index value
-    m_InColorMapIndex->value(p.m_Index);
-
-    // Set the max/min of the value
-    if(sel == 0)
-      {
-      m_InColorMapIndex->minimum(0.0);
-      m_InColorMapIndex->maximum(0.0);
-      m_MenuColorMapBoth->deactivate();
-      m_BtnColorMapDeletePoint->deactivate();
-      }
-    else if(sel == (int) cm.GetNumberOfCMPoints() - 1)
-      {
-      m_InColorMapIndex->minimum(1.0);
-      m_InColorMapIndex->maximum(1.0);
-      m_MenuColorMapBoth->deactivate();
-      m_BtnColorMapDeletePoint->deactivate();
-      }
-    else
-      {
-      m_InColorMapIndex->minimum(cm.GetCMPoint(sel-1).m_Index);
-      m_InColorMapIndex->maximum(cm.GetCMPoint(sel+1).m_Index);
-      m_MenuColorMapBoth->activate();
-      m_BtnColorMapDeletePoint->activate();
-      }
-    }
-  else
-    {
-    m_BtnColorMapDeletePoint->deactivate();
-    m_InColorMapSide->deactivate();
-    m_InColorMapIndex->deactivate();
-    // m_InColorMapRGBA->deactivate();
-    }
-}
-
-void 
-LayerInspectorUILogic
-::OnColorMapIndexUpdate()
-{
-  int sel = this->m_BoxColorMap->GetSelectedCMPoint();
-  if(sel >= 0)
-    {
-    m_InColorMapIndex->value(m_InColorMapIndex->clamp(m_InColorMapIndex->value()));
-    ColorMap::CMPoint p = this->m_BoxColorMap->GetColorMap().GetCMPoint(sel);
-    p.m_Index = m_InColorMapIndex->value();
-    this->m_BoxColorMap->GetColorMap().UpdateCMPoint(sel, p);
-    m_BoxColorMap->redraw();
-    this->OnColorMapChange();
-    }
-}
-
-void 
-LayerInspectorUILogic
-::OnColorMapSideUpdate()
-{
-  int sel = this->m_BoxColorMap->GetSelectedCMPoint();
-  if(sel >= 0)
-    {
-    ColorMap &cm = this->m_BoxColorMap->GetColorMap();
-    ColorMap::CMPoint p = cm.GetCMPoint(sel);
-    size_t val = m_InColorMapSide->value();
-
-    if(val == 0)
-      {
-      if(p.m_Type != ColorMap::CONTINUOUS)
-        {
-        // Make everything like the left
-        p.m_Type = ColorMap::CONTINUOUS;
-        p.m_RGBA[1] = p.m_RGBA[0];
-        cm.UpdateCMPoint(sel, p);
-        m_BoxColorMap->SetSelectedSide(ColorMapWidget::BOTH);
-        m_BoxColorMap->redraw();
-        this->OnColorMapChange();
-        }
-      }
-    else
-      {
-      if(p.m_Type == ColorMap::CONTINUOUS)
-        {
-        // Split the point into two
-        p.m_Type = ColorMap::DISCONTINUOUS;
-        cm.UpdateCMPoint(sel, p);
-        }
-      m_BoxColorMap->SetSelectedSide(
-        val == 1 ? ColorMapWidget::LEFT : ColorMapWidget::RIGHT);
-      m_BoxColorMap->redraw();
-      this->OnColorMapChange();
-      }
-    }
-}
-
-void 
-LayerInspectorUILogic
-::OnColorMapPointDelete()
-{
-  int sel = m_BoxColorMap->GetSelectedCMPoint();
-  if(sel > 0 && sel < (int)(m_BoxColorMap->GetColorMap().GetNumberOfCMPoints() - 1))
-    {
-    m_BoxColorMap->SetSelectedCMPoint(-1);
-    m_BoxColorMap->GetColorMap().DeleteCMPoint(sel);
-    m_BoxColorMap->redraw();
-    this->OnColorMapChange();
-    }
-}
-
-void 
-LayerInspectorUILogic
-::OnColorMapRGBAUpdate()
-{
-  int sel = this->m_BoxColorMap->GetSelectedCMPoint();
-  if(sel >= 0)
-    {
-    ColorMap::CMPoint p = this->m_BoxColorMap->GetColorMap().GetCMPoint(sel);
-    if(p.m_Type == ColorMap::CONTINUOUS || m_InColorMapSide->value() == 1)
-      {
-      p.m_RGBA[0][0] = (unsigned char) (255 * m_InColorMapRGBA->r());
-      p.m_RGBA[0][1] = (unsigned char) (255 * m_InColorMapRGBA->g());
-      p.m_RGBA[0][2] = (unsigned char) (255 * m_InColorMapRGBA->b());
-      }
-    if(p.m_Type == ColorMap::CONTINUOUS || m_InColorMapSide->value() == 2)
-      {
-      p.m_RGBA[1][0] = (unsigned char) (255 * m_InColorMapRGBA->r());
-      p.m_RGBA[1][1] = (unsigned char) (255 * m_InColorMapRGBA->g());
-      p.m_RGBA[1][2] = (unsigned char) (255 * m_InColorMapRGBA->b());
-      }
-
-    this->m_BoxColorMap->GetColorMap().UpdateCMPoint(sel, p);
-    m_BoxColorMap->redraw();
-    this->OnColorMapChange();
-    }
-
-}
-
-// Callbacks for the image info page
-void
-LayerInspectorUILogic
-::UpdateImageProbe()
-{
-  // Code common to SNAP and IRIS
-  Vector3ui crosshairs = m_Driver->GetCursorPosition();
-  Vector3d xPosition = m_SelectedWrapper->TransformVoxelIndexToPosition(crosshairs);
-  Vector3d xNIFTI = m_SelectedWrapper->TransformVoxelIndexToNIFTICoordinates(to_double(crosshairs));
-  for (size_t d = 0; d < 3; ++d)
-    {
-    m_InImageInfoCursorIndex[d]->value(crosshairs[d]);
-    m_OutImageInfoCursorPosition[d]->value(xPosition[d]);
-    m_OutImageInfoCursorPosition[d]->maximum(
-        m_OutImageInfoCursorPosition[d]->value());
-    m_OutImageInfoCursorPosition[d]->minimum(
-        m_OutImageInfoCursorPosition[d]->value());
-    m_OutImageInfoCursorNIFTIPosition[d]->value(xNIFTI[d]);
-    m_OutImageInfoCursorNIFTIPosition[d]->maximum(
-        m_OutImageInfoCursorNIFTIPosition[d]->value());
-    m_OutImageInfoCursorNIFTIPosition[d]->minimum(
-        m_OutImageInfoCursorNIFTIPosition[d]->value());
-    }
-
-  if (m_GreyWrapper)
-    {
-    m_WizImageInfoVoxelValue->value(m_GrpWizImageInfoVoxelPageGray);
-    m_OutImageInfoVoxelGray->value(m_GreyWrapper->GetVoxelMappedToNative(crosshairs));
-    }
-  else
-    {
-    m_WizImageInfoVoxelValue->value(m_GrpWizImageInfoVoxelPageRGB);
-    RGBImageWrapper *rgb = dynamic_cast<RGBImageWrapper *>(m_SelectedWrapper);
-    m_OutImageInfoVoxelRGB[0]->value(rgb->GetVoxel(crosshairs)[0]);
-    m_OutImageInfoVoxelRGB[1]->value(rgb->GetVoxel(crosshairs)[1]);
-    m_OutImageInfoVoxelRGB[2]->value(rgb->GetVoxel(crosshairs)[2]);
-    }
-}
-
-void 
-LayerInspectorUILogic
-::OnImageInformationVoxelCoordinatesUpdate()
-{
-  // Read the cursor values
-  Vector3ui cpos;
-  for (size_t d = 0; d < 3; ++d)
-    {
-    cpos[d] = (unsigned int) m_InImageInfoCursorIndex[d]->clamp(
-        m_InImageInfoCursorIndex[d]->round(
-          m_InImageInfoCursorIndex[d]->value()));
-    }
-  m_Driver->SetCursorPosition(cpos);
-  m_Parent->OnCrosshairPositionUpdate();
-  m_Parent->RedrawWindows();
-}
-
diff --git a/UserInterface/MainComponents/LayerInspectorUILogic.h b/UserInterface/MainComponents/LayerInspectorUILogic.h
deleted file mode 100644
index 145739a..0000000
--- a/UserInterface/MainComponents/LayerInspectorUILogic.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: LayerInspectorUILogic.h,v $
-  Language:  C++
-  Date:      $Date: 2011/04/18 15:06:07 $
-  Version:   $Revision: 1.14 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __LayerInspectorUILogic_h_
-#define __LayerInspectorUILogic_h_
-
-#include "LayerInspectorUI.h"
-#include "ImageWrapper.h"
-
-class UserInterfaceLogic;
-class IRISApplication;
-class GreyImageWrapper;
-
-/**
- * \class LayerInspectorUILogic
- * \brief Logic class for Layer editor UI logic
- */
-class LayerInspectorUILogic : public LayerInspectorUI
-{
-  typedef std::list<ImageWrapperBase *> WrapperList;
-  typedef WrapperList::iterator WrapperIterator;
-  typedef WrapperList::const_iterator WrapperConstIterator;
-
-public:
-  LayerInspectorUILogic(UserInterfaceLogic *);
-  virtual ~LayerInspectorUILogic() {};
-
-  // Initialization
-  void Initialize();
-
-  // Hook to the image wrappers
-  void SetImageWrappers();
-
-  // Callbacks for the main pane
-  void OnLayerSelectionUpdate();
-  void OnOverallOpacityUpdate();
-  void OnCloseAction();
-
-  // Callbacks for the contrast adjustment page
-  void UpdateWindowAndLevel();
-  void OnCurveChange();
-  void OnCurveReset();
-  void OnAutoFitWindow();
-  void OnWindowLevelChange();
-  void OnUpdateHistogram();
-  void OnControlPointMoreAction();
-  void OnControlPointLessAction();
-  void OnControlPointTextBoxUpdate();
-  void OnControlPointUpdate();
-
-  // Callbacks for the color map page
-  void OnColorMapChange();
-  void OnColorMapPresetUpdate();
-  void OnColorMapAddPresetAction();
-  void OnColorMapDeletePresetAction();
-  void OnColorMapIndexUpdate();
-  void OnColorMapSideUpdate();
-  void OnColorMapPointDelete();
-  void OnColorMapRGBAUpdate();
-  void OnColorMapSelectedPointUpdate();
-
-  // Callbacks for the image info page
-  void UpdateImageProbe();
-  void OnImageInformationVoxelCoordinatesUpdate();
-
-  // Display the dialog
-  void DisplayWindow();
-  void RedrawWindow();
-  bool Shown();
-  void DisplayImageContrastTab();
-  void DisplayColorMapTab();
-  void DisplayImageInfoTab();
-  void DisplayImageAdvancedInfoTab();
-
-  // External update to visibility of overlays
-  void AdjustOverlayOpacity(double delta);
-  void ToggleOverlayVisibility();
-
-  // External update to colormap
-  void SelectNextColorMap();
-
-protected:
-
-  void PopulateColorMapPresets();
-
-  // Info about the presets
-  struct PresetInfo 
-    {
-    std::string name;
-    int cline, ccirc;
-    };
-
-  static PresetInfo m_PresetInfo[];
-
-  // The intensity curve (same pointer stored in the m_BoxCurve)
-  IntensityCurveInterface *m_Curve;
-
-  // Pointer to the Parent GUI
-  UserInterfaceLogic *m_Parent;
-
-  // Pointer to the IRIS application object
-  IRISApplication *m_Driver;
-
-  // Main image wrapper and overlay wrapper lists
-  ImageWrapperBase *m_MainWrapper;
-  WrapperList *m_OverlayWrappers;
-
-  // Currently selected wrapper
-  ImageWrapperBase *m_SelectedWrapper;
-
-  // Grey image wrapper for intensity curve
-  GreyImageWrapper *m_GreyWrapper;
-};
-
-#endif
diff --git a/UserInterface/MainComponents/PreprocessingUI.fl b/UserInterface/MainComponents/PreprocessingUI.fl
deleted file mode 100644
index 3913f98..0000000
--- a/UserInterface/MainComponents/PreprocessingUI.fl
+++ /dev/null
@@ -1,163 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0107 
-header_name {.h} 
-code_name {.cxx}
-class PreprocessingUI {open : {private PreprocessingUIBase}
-} {
-  Function {MakeWindow()} {open
-  } {
-    Fl_Window m_WinInOut {
-      label {Intensity Region Filter} open
-      xywh {988 69 399 350} type Double box PLASTIC_DOWN_BOX
-      code0 {\#include "PreprocessingUIBase.h"} non_modal visible
-    } {
-      Fl_Value_Slider m_InThresholdSteepness {
-        label Smoothness
-        callback {o->take_focus();
-this->OnThresholdSettingsChange();}
-        tooltip {Set the smoothness of the speed function} xywh {25 265 200 20} type Horizontal color 51 selection_color 197 labelsize 12 align 5 step 0.01 value 0.25
-      }
-      Fl_Group m_GrpThresholdDirection {
-        label {Threshold direction:} open
-        xywh {250 175 135 70} labelsize 12 align 5
-      } {
-        Fl_Round_Button m_RadioThresholdAbove {
-          callback {this->OnThresholdDirectionChange();}
-          xywh {260 200 120 20} type Radio down_box ROUND_DOWN_BOX
-        }
-        Fl_Round_Button m_RadioThresholdBelow {
-          callback {this->OnThresholdDirectionChange();}
-          tooltip {Select this for a one-sided threshold, where values with low intensities are treated as 'background'} xywh {260 180 120 20} type Radio down_box ROUND_DOWN_BOX
-        }
-        Fl_Round_Button m_RadioThresholdBoth {
-          callback {this->OnThresholdDirectionChange();}
-          tooltip {Select this for a two-sided threshold, where values between the lower and upper thresholds are considered 'object' and values outside the thresholds are 'background'} xywh {260 220 120 20} type Radio down_box ROUND_DOWN_BOX value 1
-        }
-        Fl_Group {} {
-          label Below open
-          xywh {275 180 80 20} labelsize 12 align 20
-        } {}
-        Fl_Group {} {
-          label Above open
-          tooltip {Select this for a one-sided threshold, where values with high intensities are treated as 'background'} xywh {275 200 80 20} labelsize 12 align 20
-        } {}
-        Fl_Group {} {
-          label {Below and Above} open
-          xywh {275 220 105 20} labelsize 12 align 20
-        } {}
-      }
-      Fl_Button m_BtnThresholdOk {
-        label Okay
-        callback {this->OnThresholdOk();}
-        tooltip {Accept the speed image and close the window} xywh {170 300 65 25} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0x1ff0d color 180 selection_color 134 labelfont 1 labelsize 12
-      }
-      Fl_Button m_BtnThresholdApply {
-        label {&Apply}
-        callback {this->OnThresholdApply();}
-        tooltip {Accept the speed image, but do not close the window} xywh {245 300 65 25} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0x80061 color 180 selection_color 134 labelsize 12
-      }
-      Fl_Button m_BtnThresholdClose {
-        label Close
-        callback {this->OnThresholdClose();} selected
-        xywh {320 300 65 25} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0xff1b color 180 selection_color 134 labelsize 12
-      }
-      Fl_Check_Button m_InThresholdPreview {
-        label {Preview result}
-        callback {this->OnThresholdPreviewChange();}
-        tooltip {Select this to have the main program windows update automatically as you change threshold parameters} xywh {250 245 105 25} down_box DOWN_BOX value 1 labelsize 12
-      }
-      Fl_Check_Button m_InThresholdOverlay {
-        label {Combined display}
-        callback {this->OnThresholdOverlayChange();}
-        tooltip {When this option is selected, the voxels where the speed function is positive will be overlaid with the current segmentation label} xywh {250 265 125 25} down_box DOWN_BOX labelsize 12 align 148
-      }
-      Fl_Group {} {
-        label {The thresholding function} open
-        xywh {25 15 350 120} box BORDER_FRAME color 0 labelsize 11 align 2
-      } {
-        Fl_Box m_BoxThresholdFunctionPlot {
-          tooltip {This window displays a mapping from the input image intensity to the 'speed' function. The mapping is controlled by setting an upper and lower threshold. Intensities falling between the thresholds are mapped to +1 and intensities outside the threshold are set to -1. The mapping is fuzzy and its softness is controlled by the smoothness parameter} xywh {25 15 350 120}
-          class FunctionPlot2DBox
-        }
-      }
-      Fl_Slider m_OutThresholdProgress {
-        xywh {0 335 400 15} type {Horz Fill} selection_color 180 labelsize 12 align 0 value 1 deactivate
-      }
-      Fl_Value_Input m_InLowerThresholdText {
-        label {Lower threshold}
-        callback {this->OnThresholdLowerChange(o->value());}
-        tooltip {Set the threshold below which the speed function will be negative} xywh {25 175 40 20} color 51 labelsize 12 align 5 maximum 100 step 0.01 textsize 10
-      }
-      Fl_Slider m_InLowerThreshold {
-        callback {o->take_focus();
-this->OnThresholdLowerChange(o->value());}
-        tooltip {Set the threshold below which the speed function will be negative} xywh {70 175 155 20} type Horizontal color 51 selection_color 197 value 0.01
-      }
-      Fl_Value_Input m_InUpperThresholdText {
-        label {Upper threshold}
-        callback {this->OnThresholdUpperChange(o->value());}
-        tooltip {Set the threshold above which the speed function will be negative} xywh {25 220 40 20} color 51 labelsize 12 align 5 maximum 100 step 0.01 textsize 10
-      }
-      Fl_Slider m_InUpperThreshold {
-        callback {o->take_focus();
-this->OnThresholdUpperChange(o->value());}
-        tooltip {Set the threshold above which the speed function will be negative} xywh {70 220 155 20} type Horizontal color 51 selection_color 197 value 0.01
-      }
-    }
-    Fl_Window m_WinEdge {
-      label {Image Edge Filter} open
-      xywh {732 549 400 351} type Double box PLASTIC_DOWN_BOX non_modal visible
-    } {
-      Fl_Value_Slider m_InEdgeScale {
-        label {Scale of Gaussian blurring (sigma)}
-        callback {o->take_focus();
-this->OnEdgeSettingsChange();}
-        tooltip {Set the scale of Gaussian blurring applied to the image before computing the gradient magnitude (and the speed function). Use smaller values to emphasize finer edges in the input image, and use larger values if you want the active contour evolution to be driven by the strongest edges.} xywh {25 175 225 20} type Horizontal color 51 selection_color 197 labelsize 12 align 5 minimum 0.1 maximum 3 step 0.1 value 1
-      }
-      Fl_Value_Slider m_InEdgeKappa {
-        label {Edge contrast (kappa)}
-        callback {o->take_focus();
-this->OnEdgeSettingsChange();}
-        tooltip {This parameter affects the shape of the mapping between gradient magnitude and the speed function} xywh {25 220 225 20} type Horizontal color 51 selection_color 197 labelsize 12 align 5 minimum 0.002 maximum 0.2 step 0.002 value 0.1
-      }
-      Fl_Value_Slider m_InEdgeExponent {
-        label {Edge mapping exponent}
-        callback {o->take_focus();
-this->OnEdgeSettingsChange();}
-        tooltip {This parameter affects the shape of the mapping between gradient magnitude and the speed function} xywh {25 265 225 20} type Horizontal color 51 selection_color 197 labelsize 12 align 5 minimum 1 maximum 3 step 0.05 value 2
-      }
-      Fl_Button m_BtnEdgeOK {
-        label Okay
-        callback {this->OnEdgeOk();}
-        tooltip {Accept the speed image and close the window} xywh {170 300 65 25} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0x1ff0d color 180 selection_color 134 labelfont 1 labelsize 12
-      }
-      Fl_Button m_BtnEdgeApply {
-        label {&Apply}
-        callback {this->OnEdgeApply();}
-        tooltip {Accept the speed image, but do not close the window} xywh {245 300 65 25} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0x80061 color 180 selection_color 134 labelsize 12
-      }
-      Fl_Button m_BtnEdgeClose {
-        label Close
-        callback {this->OnEdgeClose();}
-        xywh {320 300 65 25} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0xff1b color 180 selection_color 134 labelsize 12
-      }
-      Fl_Check_Button m_InEdgePreview {
-        label {Preview result}
-        callback {this->OnEdgePreviewChange();}
-        tooltip {Select this to have the main program windows update automatically as you change threshold parameters} xywh {270 170 105 25} down_box DOWN_BOX labelsize 12
-      }
-      Fl_Group {} {
-        label {The function g() applied to the gradient magnitude image} open
-        xywh {25 15 350 120} box BORDER_FRAME color 0 labelsize 11 align 2
-      } {
-        Fl_Box m_BoxEdgeFunctionPlot {
-          tooltip {This window displays a mapping between gradient magnitude of the input image and  the 'speed' function. The 'speed' function should be close to 0 near edges in the input image (where gradient magnitude is high), and it should be close to 1 at regions where image intensity is nearly constant (gradient magnitude close to 0). Gradient magnitude of the image is computed at a scale (sigma). At larger scales, small fine edges are smoothed out.} xywh {25 15 350 120} box BORDE [...]
-          class FunctionPlot2DBox
-        }
-      }
-      Fl_Slider m_OutEdgeProgress {
-        xywh {0 335 400 15} type {Horz Fill} selection_color 180 labelsize 12 align 0 value 1 deactivate
-      }
-    }
-  }
-} 
diff --git a/UserInterface/MainComponents/PreprocessingUIBase.h b/UserInterface/MainComponents/PreprocessingUIBase.h
deleted file mode 100644
index 0d7f544..0000000
--- a/UserInterface/MainComponents/PreprocessingUIBase.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PreprocessingUIBase.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:17 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __PreprocessingUIBase_h_
-#define __PreprocessingUIBase_h_
-
-#include "FunctionPlot2DBox.h"
-
-/**
- * \class PreprocessingUIBase
- * \brief Base class for preprocessing UI.
- */
-class PreprocessingUIBase
-{
-public:
-  virtual ~PreprocessingUIBase() {}
-  // Callbacks for the Edge snake preprocessing window
-  virtual void OnEdgeSettingsChange() = 0;
-  virtual void OnEdgePreviewChange() = 0;
-  virtual void OnEdgeOk() = 0;
-  virtual void OnEdgeClose() = 0;
-  virtual void OnEdgeApply() = 0;
-
-  // Callbacks for the InOut snake preprocessing window
-  virtual void OnThresholdDirectionChange() = 0;
-  virtual void OnThresholdLowerChange(double value) = 0;
-  virtual void OnThresholdUpperChange(double value) = 0;
-  virtual void OnThresholdSettingsChange() = 0;
-  virtual void OnThresholdOk() = 0;
-  virtual void OnThresholdClose() = 0;
-  virtual void OnThresholdApply() = 0;
-  virtual void OnThresholdPreviewChange() = 0;
-  virtual void OnThresholdOverlayChange() = 0;
-};
-
-#endif
diff --git a/UserInterface/MainComponents/PreprocessingUILogic.cxx b/UserInterface/MainComponents/PreprocessingUILogic.cxx
deleted file mode 100644
index dc200b2..0000000
--- a/UserInterface/MainComponents/PreprocessingUILogic.cxx
+++ /dev/null
@@ -1,778 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PreprocessingUILogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/19 19:16:30 $
-  Version:   $Revision: 1.7 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-// Borland compiler is very lazy so we need to instantiate the template
-//  by hand 
-#if defined(__BORLANDC__)
-#include "SNAPBorlandDummyTypes.h"
-#endif
-
-#include "PreprocessingUILogic.h"
-
-#include "GlobalState.h"
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-#include "SNAPImageData.h"
-#include "ThresholdSettings.h"
-#include "UserInterfaceBase.h"
-
-#include "itkOrientedImage.h"
-#include "itkEventObject.h" 
-
-
-void 
-PreprocessingUILogic
-::Register(UserInterfaceBase *parent)
-{
-  m_ParentUI = parent;
-  m_Driver = parent->GetDriver();
-  m_GlobalState = parent->GetDriver()->GetGlobalState();
-}
-
-void 
-PreprocessingUILogic
-::DisplayEdgeWindow()
-{
-  // Get the threshold parameters
-  EdgePreprocessingSettings settings = 
-    m_GlobalState->GetEdgePreprocessingSettings();
-
-  // Set the slider values
-  m_InEdgeScale->value(
-    m_InEdgeScale->clamp(settings.GetGaussianBlurScale()));
-
-  m_InEdgeKappa->value(
-    m_InEdgeKappa->clamp(settings.GetRemappingSteepness()));
-
-  m_InEdgeExponent->value(
-    m_InEdgeExponent->clamp(settings.GetRemappingExponent()));
-
-  // Position the window and show it
-  m_ParentUI->CenterChildWindowInMainWindow(m_WinEdge);
-
-  // Get a handle to the snap image data
-  SNAPImageData *snapData = m_Driver->GetSNAPImageData();
-
-  // Initialize the speed image if necessary, and assign it the correct
-  // color map preset
-  if(!snapData->IsSpeedLoaded())
-    {
-    snapData->InitializeSpeed();
-    snapData->GetSpeed()->SetColorMap(
-      SpeedColorMap::GetPresetColorMap(m_GlobalState->GetSpeedColorMap()));
-    }
-    
-  // Set the intensity mapping mode for the speed image
-  snapData->GetSpeed()->SetModeToEdgeSnake();
-
-  // Apply the automatic preview preference
-  m_InEdgePreview->value(
-    m_GlobalState->GetShowPreprocessedEdgePreview() ? 1 : 0);
-
-  OnEdgePreviewChange();
-
-  // Set up the plot range, etc
-  FunctionPlot2DSettings &plotSettings = 
-    m_BoxEdgeFunctionPlot->GetPlotter().GetSettings();
-  plotSettings.SetPlotRangeMin(Vector2f(0.0f));
-
-  // Compute the plot to be displayed
-  UpdateEdgePlot();
-
-  // Show the window
-  m_WinEdge->show();
-
-  // Explicitly show the plotting box  
-  m_BoxEdgeFunctionPlot->show();
-}
-
-void 
-PreprocessingUILogic
-::DisplayInOutWindow(void)
-{
-  // Get the threshold parameters
-  ThresholdSettings settings = m_GlobalState->GetThresholdSettings();
-
-  // Shorthands
-  GreyTypeToNativeFunctor g2n =
-    m_Driver->GetCurrentImageData()->GetGrey()->GetNativeMapping();
-  float lower = g2n((GreyType)settings.GetLowerThreshold());
-  float upper = g2n((GreyType)settings.GetUpperThreshold());
-
-  // Set the ranges for the two thresholds.  These ranges do not require the
-  // lower slider to be less than the upper slider, that will be corrected
-  // dynamically as the user moves the sliders
-  double iMin = m_Driver->GetCurrentImageData()->GetGrey()->GetImageMinNative();
-  double iMax = m_Driver->GetCurrentImageData()->GetGrey()->GetImageMaxNative();
-
-  m_InLowerThreshold->minimum(iMin);
-  m_InLowerThresholdText->minimum(iMin);
-  m_InLowerThreshold->maximum(iMax);
-  m_InLowerThresholdText->maximum(iMax);
-
-  m_InUpperThreshold->minimum(iMin);
-  m_InUpperThresholdText->minimum(iMin);
-  m_InUpperThreshold->maximum(iMax);
-  m_InUpperThresholdText->maximum(iMax);
-
-  //m_InThresholdSteepness->minimum(1);
-  //m_InThresholdSteepness->maximum(iMax-iMin);
-  m_InThresholdSteepness->minimum(1);
-  m_InThresholdSteepness->maximum(10);
-
-  // Make sure that the specified range is valid
-  if(lower > upper)
-    {
-    lower = 0.67 * iMin + 0.33 * iMax;
-    upper = 0.33 * iMin + 0.67 * iMax;
-    }
-
-  // Make sure the current values of the upper and lower threshold are 
-  // within the bounds (Nathan Moon)
-  SetLowerThresholdControlValue(m_InLowerThreshold->clamp(lower));
-  SetUpperThresholdControlValue(m_InUpperThreshold->clamp(upper));
-
-  m_InThresholdSteepness->value(
-    m_InThresholdSteepness->clamp(settings.GetSmoothness()));
-
-  // Set the radio buttons
-  if(settings.IsLowerThresholdEnabled() && 
-    settings.IsUpperThresholdEnabled())
-    {
-    m_RadioThresholdBoth->setonly();
-    }
-  else if(settings.IsLowerThresholdEnabled())
-    {
-    m_RadioThresholdBelow->setonly();
-    }
-  else
-    {
-    m_RadioThresholdAbove->setonly();
-    }
-
-  // Position the window and show it
-  m_ParentUI->CenterChildWindowInMainWindow(m_WinInOut);
-
-  // Get a handle to the snap image data
-  SNAPImageData *snapData = m_Driver->GetSNAPImageData();
-
-  // Initialize the speed image if necessary and assign it a color map
-  if(!snapData->IsSpeedLoaded())
-    {
-    snapData->InitializeSpeed();
-    snapData->GetSpeed()->SetColorMap(
-      SpeedColorMap::GetPresetColorMap(m_GlobalState->GetSpeedColorMap()));
-    }
-  // Set the speed image to In/Out mode
-  snapData->GetSpeed()->SetModeToInsideOutsideSnake();
-
-  // Apply the automatic preview preference
-  m_InThresholdPreview->value(
-    m_GlobalState->GetShowPreprocessedInOutPreview() ? 1 : 0);
-  OnThresholdPreviewChange();
-
-  // Use a callback method to enable / disable sliders
-  OnThresholdDirectionChange();
-
-  // Apply the overlay settings (this is a personal preference, but I like 
-  // to disable the color overlay when the window comes up initially)
-  m_InThresholdOverlay->value(0);
-  OnThresholdOverlayChange();
-
-  // Set up the plot range, etc
-  FunctionPlot2DSettings &plotSettings = 
-    m_BoxThresholdFunctionPlot->GetPlotter().GetSettings();
-  NativeToGreyTypeFunctor n2g(g2n);
-  plotSettings.SetPlotRangeMin(Vector2f(n2g(iMin),-1.0f));
-  plotSettings.SetPlotRangeMax(Vector2f(n2g(iMax),1.0f));
-
-  // Compute the plot to be displayed
-  UpdateThresholdPlot();
-
-  // Show the window
-  m_WinInOut->show();
-
-  // Explicitly show the plotting box  
-  m_BoxThresholdFunctionPlot->show();
-}
-
-void 
-PreprocessingUILogic
-::OnThresholdDirectionChange()
-{
-  // Enable and disable the state of the sliders based on the
-  // current button settings
-  if(m_RadioThresholdBoth->value())
-    {
-    m_InLowerThreshold->activate();
-    m_InLowerThresholdText->activate();
-    m_InUpperThreshold->activate();
-    m_InUpperThresholdText->activate();
-    }
-  else if(m_RadioThresholdAbove->value())
-    {
-    m_InLowerThreshold->deactivate();
-    m_InLowerThresholdText->deactivate();
-
-    SetLowerThresholdControlValue(
-      m_Driver->GetCurrentImageData()->GetGrey()->GetImageMinNative());
-    
-    m_InUpperThreshold->activate();
-    m_InUpperThresholdText->activate();
-    }
-  else
-    {
-    m_InLowerThreshold->activate();
-    m_InLowerThresholdText->activate();
-
-    SetUpperThresholdControlValue(
-      m_Driver->GetCurrentImageData()->GetGrey()->GetImageMaxNative());
-
-    m_InUpperThreshold->deactivate();
-    m_InUpperThresholdText->deactivate();
-    }
-
-  // The settings have changed, so call that method
-  OnThresholdSettingsChange();
-}
-
-void PreprocessingUILogic
-::SetUpperThresholdControlValue(double val)
-{
-  m_InUpperThreshold->value(val);
-  m_InUpperThresholdText->value(val);
-}
-
-void PreprocessingUILogic
-::SetLowerThresholdControlValue(double val)
-{
-  m_InLowerThreshold->value(val);
-  m_InLowerThresholdText->value(val);
-}
-
-void 
-PreprocessingUILogic
-::OnThresholdLowerChange(double value)
-{
-  // Propagate the value to all controls
-  SetLowerThresholdControlValue( value );
-
-  // There may be a need to shift the upper bound
-  if(m_InUpperThreshold->value() < m_InLowerThreshold->value())
-    {
-    SetUpperThresholdControlValue( m_InLowerThreshold->value() );
-    }
-
-  // Call the generic callback
-  OnThresholdSettingsChange();
-}
-
-void 
-PreprocessingUILogic
-::OnThresholdUpperChange(double value)
-{
-  // Propagate the value to all controls
-  SetUpperThresholdControlValue( value );
-
-  // There may be a need to shift the lower bound
-  if( m_InUpperThreshold->value() < m_InLowerThreshold->value())
-    {
-    SetLowerThresholdControlValue( m_InUpperThreshold->value() );
-    }
-
-  // Call the generic callback
-  OnThresholdSettingsChange();
-}
-
-void 
-PreprocessingUILogic
-::OnEdgeSettingsChange()
-{
-  // Pass the current GUI settings to the filter
-  EdgePreprocessingSettings settings;
-  settings.SetGaussianBlurScale(m_InEdgeScale->value());
-  settings.SetRemappingSteepness(m_InEdgeKappa->value());
-  settings.SetRemappingExponent(m_InEdgeExponent->value());
-
-  // Store the settings globally
-  m_GlobalState->SetEdgePreprocessingSettings(settings);
-
-  // Update the plotter
-  UpdateEdgePlot();
-  
-  // Update display if in preview mode
-  if(m_GlobalState->GetShowPreprocessedEdgePreview())
-    {
-    // Apply the settings to the preview filters
-    m_EdgePreviewFilter[0]->SetEdgePreprocessingSettings(settings);
-    m_EdgePreviewFilter[1]->SetEdgePreprocessingSettings(settings);
-    m_EdgePreviewFilter[2]->SetEdgePreprocessingSettings(settings);
-
-    // Repaint the slice windows
-    m_ParentUI->RedrawWindows();
-    }
-}
-
-void 
-PreprocessingUILogic
-::OnThresholdSettingsChange()
-{
-  // Pass the current GUI settings to the filter
-  ThresholdSettings settings;
-  GreyTypeToNativeFunctor g2n =
-    m_Driver->GetCurrentImageData()->GetGrey()->GetNativeMapping();
-  NativeToGreyTypeFunctor n2g(g2n);
-  settings.SetLowerThreshold(n2g(m_InLowerThreshold->value()));
-  settings.SetUpperThreshold(n2g(m_InUpperThreshold->value()));
-  settings.SetSmoothness(m_InThresholdSteepness->value());
-  settings.SetLowerThresholdEnabled(m_InLowerThreshold->active());
-  settings.SetUpperThresholdEnabled(m_InUpperThreshold->active());  
-
-  // Store the settings globally
-  m_GlobalState->SetThresholdSettings(settings);
-
-  // Compute the plot to be displayed
-  UpdateThresholdPlot();
-  
-  // Apply the settings to the filter but only if we are in preview mode
-  if(m_GlobalState->GetShowPreprocessedInOutPreview())
-    {    
-    m_InOutPreviewFilter[0]->SetThresholdSettings(settings);
-    m_InOutPreviewFilter[1]->SetThresholdSettings(settings);
-    m_InOutPreviewFilter[2]->SetThresholdSettings(settings);
-
-    // Repaint the slice windows
-    m_ParentUI->RedrawWindows();
-    }  
-}
-
-void 
-PreprocessingUILogic
-::OnEdgePreviewChange(void)
-{  
-  bool preview = (m_InEdgePreview->value() == 1);
-
-  // Store the value of the flag globally
-  m_GlobalState->SetShowPreprocessedEdgePreview(preview);
-
-  // Entering preview mode means that we can draw the speed image
-  m_GlobalState->SetShowSpeed(preview);
-
-  if(preview)
-    {
-    // Initialize each preview filter
-    for(unsigned int i=0;i<3;i++)
-      {
-      // Make sure the preview filter is deallocated
-      assert(!m_EdgePreviewFilter[i]);
-  
-      // Create the filter
-      m_EdgePreviewFilter[i] = EdgeFilterType::New();
-
-      // Give it an input
-      m_EdgePreviewFilter[i]->SetInput(
-        m_Driver->GetSNAPImageData()->GetGrey()->GetImage());
-  
-      // Pass the current settings to the filter
-      m_EdgePreviewFilter[i]->SetEdgePreprocessingSettings(
-        m_GlobalState->GetEdgePreprocessingSettings());
-      }
-        
-    // Attach the preview filters to the corresponding slicers
-    for(unsigned int j=0;j<3;j++)
-      {
-      // What is the image axis corresponding to the j-th slicer?
-      unsigned int iSliceAxis = 
-        m_Driver->GetSNAPImageData()->GetSpeed()->GetDisplaySliceImageAxis(j);
-
-      // Connect the previewer to that slicer
-      m_Driver->GetSNAPImageData()->GetSpeed()->SetSliceSourceForPreview(
-        j,m_EdgePreviewFilter[iSliceAxis]->GetOutput());
-      }
-
-    // The speed preview is now valid
-    m_GlobalState->SetSpeedPreviewValid(true);
-
-    }
-  else
-    {
-    // Clear the preview filters
-    m_EdgePreviewFilter[0] = NULL;
-    m_EdgePreviewFilter[1] = NULL;
-    m_EdgePreviewFilter[2] = NULL;
-
-    // Revert to the old speed image
-    // TODO: We're reverting to the last APPLY.  The user may get confused.
-    m_Driver->GetSNAPImageData()->GetSpeed()->RemoveSliceSourcesForPreview();
-
-    // The speed preview is now invalid
-    m_GlobalState->SetSpeedPreviewValid(false);
-    }
-
-  // Notify parent of the update
-  m_ParentUI->OnPreprocessingPreviewStatusUpdate(preview);
-}
-
-void 
-PreprocessingUILogic
-::OnThresholdPreviewChange(void)
-{
-  bool preview = (m_InThresholdPreview->value() == 1);
-
-  // Store the value of the flag globally
-  m_GlobalState->SetShowPreprocessedInOutPreview(preview);
-
-  // Entering preview mode means that we can draw the speed image
-  m_GlobalState->SetShowSpeed(preview);
-
-  if(preview)
-    {
-    // Initialize each preview filter
-    for(unsigned int i=0;i<3;i++)
-      {
-      // Make sure the preview filter is deallocated
-      assert(!m_InOutPreviewFilter[i]);
-  
-      // Create the filter
-      m_InOutPreviewFilter[i] = InOutFilterType::New();
-
-      // Give it an input
-      m_InOutPreviewFilter[i]->SetInput(
-        m_Driver->GetSNAPImageData()->GetGrey()->GetImage());
-  
-      // Pass the current settings to the filter
-      m_InOutPreviewFilter[i]->SetThresholdSettings(
-        m_GlobalState->GetThresholdSettings());
-      }
-
-    // Attach the preview filters to the corresponding slicers
-    for(unsigned int j=0;j<3;j++)
-      {
-      // What is the image axis corresponding to the j-th slicer?
-      unsigned int iSliceAxis = 
-        m_Driver->GetSNAPImageData()->GetSpeed()->GetDisplaySliceImageAxis(j);
-
-      // Connect the previewer to that slicer
-      m_Driver->GetSNAPImageData()->GetSpeed()->SetSliceSourceForPreview(
-        j,m_InOutPreviewFilter[iSliceAxis]->GetOutput());
-      }
-
-    // The speed preview is now valid
-    m_GlobalState->SetSpeedPreviewValid(true);
-    }
-  else
-    {
-    // Clear the preview filters
-    m_InOutPreviewFilter[0] = NULL;
-    m_InOutPreviewFilter[1] = NULL;
-    m_InOutPreviewFilter[2] = NULL;
-
-    // Revert to the old speed image
-    // TODO: We're reverting to the last APPLY.  The user may get confused.
-    m_Driver->GetSNAPImageData()->GetSpeed()->RemoveSliceSourcesForPreview();
-
-    // The speed preview is now invalid
-    m_GlobalState->SetSpeedPreviewValid(false);
-    }
-
-  // Notify parent of the update
-  m_ParentUI->OnPreprocessingPreviewStatusUpdate(preview);
-}
-
-void 
-PreprocessingUILogic
-::OnEdgeOk()
-{
-  // Apply the preprocessing on the whole image
-  OnEdgeApply();
-
-  // Run the same code as when the window is closed
-  OnEdgeClose();
-}
-
-void 
-PreprocessingUILogic
-::OnThresholdOk(void)
-{
-  // Apply the preprocessing on the whole image
-  OnThresholdApply();
-
-  // Run the same code as when the window is closed
-  OnThresholdClose();
-}
-
-void 
-PreprocessingUILogic
-::OnEdgeApply()
-{
-  // Create a callback object
-  CommandPointer callback = CommandType::New();
-  callback->SetCallbackFunction(this,&PreprocessingUILogic::OnEdgeProgress);
-  
-  // Use the SNAPImageData to perform preprocessing
-  m_OutEdgeProgress->value(0);
-  m_Driver->GetSNAPImageData()->DoEdgePreprocessing(
-    m_GlobalState->GetEdgePreprocessingSettings(),callback);
-  m_OutEdgeProgress->value(1);
-
-  // The preprocessing image is valid
-  m_GlobalState->SetSpeedValid(true);
-
-  // Update the parent UI
-  m_ParentUI->OnSpeedImageUpdate();
-}
-
-void 
-PreprocessingUILogic
-::OnThresholdApply()
-{
-  // Create a callback object
-  CommandPointer callback = CommandType::New();
-  callback->SetCallbackFunction(this,&PreprocessingUILogic::OnThresholdProgress);
-  
-  // Use the SNAPImageData to perform preprocessing
-  m_Driver->GetSNAPImageData()->DoInOutPreprocessing(
-    m_GlobalState->GetThresholdSettings(),callback);
-
-  // The preprocessing image is valid
-  m_GlobalState->SetSpeedValid(true);
-
-  // Update the parent UI
-  m_ParentUI->OnSpeedImageUpdate();
-}
-
-void 
-PreprocessingUILogic
-::OnThresholdOverlayChange(void)
-{  
-  if(m_InThresholdOverlay->value())
-    {
-    // These five lines of code pass the current drawing color to the overlay
-    // system in the SpeedImageWrapper
-    unsigned char rgbaOverlay[4];
-    unsigned int label = m_GlobalState->GetDrawingColorLabel();
-    m_Driver->GetColorLabelTable()->GetColorLabel(label).GetRGBAVector(rgbaOverlay);
-    SpeedImageWrapper::OverlayPixelType colorOverlay(rgbaOverlay);
-    m_Driver->GetSNAPImageData()->GetSpeed()->SetOverlayColor(colorOverlay);
-
-    // Set the cutoff threshold to zero, i.e., positive speed values will be 
-    // painted 
-    m_Driver->GetSNAPImageData()->GetSpeed()->SetOverlayCutoff(0);
-
-    // Set the appropriate flag
-    m_GlobalState->SetSpeedViewZero(true);
-
-    // Repaint
-    m_ParentUI->RedrawWindows();
-    }
-  else 
-    {
-    // Clear the appropriate flag
-    m_GlobalState->SetSpeedViewZero(false);
-    }
-
-  // Repaint the slice windows
-  m_ParentUI->RedrawWindows();
-}
-
-void 
-PreprocessingUILogic
-::OnCloseCommon()
-{
-  // Revert to the old speed image
-  // TODO: We're reverting to the last APPLY.  The user may get confused.
-  m_Driver->GetSNAPImageData()->GetSpeed()->RemoveSliceSourcesForPreview();
-
-  // The speed preview is now invalid
-  m_GlobalState->SetSpeedPreviewValid(false);
-  
-  // Make sure that if the speed is not valid, then it is not visible
-  if(!m_GlobalState->GetSpeedValid())
-    {
-    m_GlobalState->SetShowSpeed(false);
-    m_ParentUI->RedrawWindows();
-    }
-    
-  // Notify that we have been closed
-  m_ParentUI->OnPreprocessClose();
-}
-
-void 
-PreprocessingUILogic
-::OnEdgeClose()
-{
-  // If in preview mode, disconnect and destroy the preview filters
-  m_EdgePreviewFilter[0] = NULL;
-  m_EdgePreviewFilter[1] = NULL;
-  m_EdgePreviewFilter[2] = NULL;
-
-  // Close the window
-  m_WinEdge->hide();
-
-  // Common closing tasks
-  OnCloseCommon();
-}
-
-void 
-PreprocessingUILogic
-::OnThresholdClose(void)
-{
-  // Make sure we are no longer looking in grey/speed overlay mode
-  m_GlobalState->SetSpeedViewZero(false);
-
-  // If in preview mode, disconnect and destroy the preview filters
-  m_InOutPreviewFilter[0] = NULL;
-  m_InOutPreviewFilter[1] = NULL;
-  m_InOutPreviewFilter[2] = NULL;
-
-  // Close the window
-  m_WinInOut->hide();
-  
-  // Common closing tasks
-  OnCloseCommon();
-}
-
-void 
-PreprocessingUILogic
-::HidePreprocessingWindows()
-{
-  m_WinInOut->hide();
-  m_WinEdge->hide();
-}
-
-void 
-PreprocessingUILogic
-::UpdateEdgePlot()
-{
-  // Create a functor object used in the filter
-  EdgeFilterType::FunctorType functor;
-
-  // Get the global settings
-  EdgePreprocessingSettings settings = 
-    m_GlobalState->GetEdgePreprocessingSettings();
-
-  // Pass the settings to the functor
-  functor.SetParameters(0.0f,1.0f,
-    settings.GetRemappingExponent(),
-    settings.GetRemappingSteepness());
-
-  // Compute the function for a range of values
-  const unsigned int nSamples = 200;
-  float x[nSamples];
-  float y[nSamples];
-
-  for(unsigned int i=0;i<nSamples;i++) 
-    {
-    x[i] = i * 1.0f / (nSamples-1);
-    y[i] = functor(x[i]);
-    }
-
-  // Pass the results to the plotter
-  m_BoxEdgeFunctionPlot->GetPlotter().SetDataPoints(x,y,nSamples);
-
-  // Redraw the box
-  m_BoxEdgeFunctionPlot->redraw();
-}
-
-void 
-PreprocessingUILogic
-::UpdateThresholdPlot()
-{
-  // Create a functor object used in the filter
-  SmoothBinaryThresholdFunctor<float,float> functor;
-
-  // Get the global settings
-  ThresholdSettings settings = 
-    m_GlobalState->GetThresholdSettings();
-
-  // We need to know the min/max of the image
-  GreyTypeToNativeFunctor g2n =
-    m_Driver->GetCurrentImageData()->GetGrey()->GetNativeMapping();
-  NativeToGreyTypeFunctor n2g(g2n);
-  float iMin = n2g(m_InLowerThreshold->minimum());
-  float iMax = n2g(m_InUpperThreshold->maximum());
-
-  // Pass the settings to the functor
-  functor.SetParameters(iMin,iMax,settings);
-
-  // Compute the function for a range of values
-  const unsigned int nSamples = 200;
-  float x[nSamples];
-  float y[nSamples];
-
-  for(unsigned int i=0;i<nSamples;i++) 
-    {
-    x[i] = iMin + i * (iMax-iMin) / (nSamples-1.0f);
-    y[i] = functor(x[i]);
-    }
-
-  // Pass the results to the plotter
-  m_BoxThresholdFunctionPlot->GetPlotter().SetDataPoints(x,y,nSamples);
-
-  // Redraw the box
-  m_BoxThresholdFunctionPlot->redraw();
-}
-
-#include <EdgePreprocessingImageFilter.h>
-
-void 
-PreprocessingUILogic
-::OnEdgeProgress(itk::Object *object, const itk::EventObject &irisNotUsed(event))
-{
-  // Last progress value
-  static double last_refresh = clock();
-  static const double delta = CLOCKS_PER_SEC * 0.25;
-
-  // Ignore event if nothing has happened
-  if(last_refresh + delta < clock())
-    {
-    // Get the value of the progress
-    float progress = dynamic_cast<itk::ProcessObject *>(object)->GetProgress();
-
-    // Display the filter's progress
-    m_OutEdgeProgress->value(progress);
-
-    // Let the UI refresh
-    Fl::check();
-
-    // Reset the refresh counter
-    last_refresh = clock();
-    }
-}
-
-void 
-PreprocessingUILogic
-::OnThresholdProgress(itk::Object *object, const itk::EventObject &irisNotUsed(event))
-{
-  // Last progress value
-  static double last_refresh = clock();
-  static const double delta = CLOCKS_PER_SEC * 0.25;
-
-  // Ignore event if nothing has happened
-  if(last_refresh + delta < clock())
-    {
-    // Get the value of the progress
-    float progress = dynamic_cast<itk::ProcessObject *>(object)->GetProgress();
-    
-    // Display the filter's progress
-    m_OutThresholdProgress->value(progress);
-
-    // Let the UI refresh
-    Fl::check();
-
-    // Reset the refresh counter
-    last_refresh = clock();
-    }
-}
-
diff --git a/UserInterface/MainComponents/PreprocessingUILogic.h b/UserInterface/MainComponents/PreprocessingUILogic.h
deleted file mode 100644
index 8a603d8..0000000
--- a/UserInterface/MainComponents/PreprocessingUILogic.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PreprocessingUILogic.h,v $
-  Language:  C++
-  Date:      $Date: 2009/01/23 20:09:38 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __PreprocessingUILogic_h_
-#define __PreprocessingUILogic_h_
-
-#include "PreprocessingUI.h"
-#include "SNAPCommonUI.h"
-#include "EdgePreprocessingImageFilter.h"
-#include "SmoothBinaryThresholdImageFilter.h"
-
-// Forward references to application classes
-class GlobalState;
-class IRISApplication;
-class UserInterfaceBase;
-
-// ITK forward references
-namespace itk {
-  template<class TPixel, unsigned int VDimension> class Image;
-  template<class TObject> class MemberCommand;
-  class EventObject;
-}
-
-/**
- * \class PreprocessingUILogic
- * \brief Logic for the preprocessing UI.
- */
-class PreprocessingUILogic : public PreprocessingUI
-{
-public:
-
-  // A virtual destructor to make gcc happy
-  virtual ~PreprocessingUILogic() {}
-  
-  // Callbacks for the Edge snake preprocessing window
-  void OnEdgeSettingsChange();
-  void OnEdgePreviewChange();  
-  void OnEdgeOk();
-  void OnEdgeClose();
-  void OnEdgeApply();
-
-  // Callbacks for the InOut snake preprocessing window
-  void OnThresholdDirectionChange();
-  void OnThresholdLowerChange(double value);
-  void OnThresholdUpperChange(double value);
-  void OnThresholdSettingsChange();
-  void OnThresholdOk();
-  void OnThresholdClose();
-  void OnThresholdApply();
-  void OnThresholdPreviewChange();
-  void OnThresholdOverlayChange();
-  
-  // Register this class with the parent user interface
-  void Register(UserInterfaceBase *parent);
-
-  // Display the Edge preprocessing window
-  void DisplayEdgeWindow();
-
-  // Display the In/Out preprocessing window
-  void DisplayInOutWindow();
-
-  // Programmatically hide the preprocessing windows
-  void HidePreprocessingWindows();
-
-private:
-  GlobalState *m_GlobalState;
-  IRISApplication *m_Driver;
-  UserInterfaceBase *m_ParentUI;
-
-  /** The image types used for preprocessing */
-  typedef itk::OrientedImage<GreyType,3> GreyImageType;
-  typedef itk::OrientedImage<float,3> SpeedImageType;
-  
-  /** The filter type for in/out processing */
-  typedef SmoothBinaryThresholdImageFilter<
-    GreyImageType,SpeedImageType> InOutFilterType;
-  typedef itk::SmartPointer<InOutFilterType> InOutFilterPointer;
-
-  /** The filter type for edge preprocessing */
-  typedef EdgePreprocessingImageFilter<
-    GreyImageType,SpeedImageType> EdgeFilterType;
-  typedef itk::SmartPointer<EdgeFilterType> EdgeFilterPointer;
-
-  /** A command type for progress reporting */
-  typedef itk::MemberCommand<PreprocessingUILogic> CommandType;
-  typedef itk::SmartPointer<CommandType> CommandPointer;
-
-  /** The filter used for in-out thresholding */
-  InOutFilterPointer m_InOutPreviewFilter[3];
-  InOutFilterPointer m_InOutFilterWhole;
-
-  /** The filters used for edge preprocessing */
-  EdgeFilterPointer m_EdgePreviewFilter[3];
-  EdgeFilterPointer m_EdgeFilterWhole;
-
-  /** Update the plot shown in the edge plot box */
-  void UpdateEdgePlot();
-
-  /** Update the plot shown in the in-out plot box */
-  void UpdateThresholdPlot();
-
-  /** Progress callback for edge preprocessing */
-  void OnEdgeProgress(itk::Object *object, const itk::EventObject &event);
-
-  /** Progress callback for thresholding preprocessing */
-  void OnThresholdProgress(itk::Object *object, const itk::EventObject &event);
-
-  /** Common closing code for both preprocessors */
-  void OnCloseCommon();
-
-  /** Code to set values in both controls used to show the upper threshold */
-  void SetUpperThresholdControlValue(double val);
-
-  /** Code to set values in both controls used to show the upper threshold */
-  void SetLowerThresholdControlValue(double val);
-};
-
-#endif // __PreprocessingUILogic_h_
diff --git a/UserInterface/MainComponents/ReorientImageUI.fl b/UserInterface/MainComponents/ReorientImageUI.fl
deleted file mode 100644
index 2e5222c..0000000
--- a/UserInterface/MainComponents/ReorientImageUI.fl
+++ /dev/null
@@ -1,219 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0108 
-header_name {.h} 
-code_name {.cxx}
-class ReorientImageUI {open : ReorientImageUIBase
-} {
-  Function {MakeWindow()} {open
-  } {
-    Fl_Window m_WinReorient {
-      label {Change Image Orientation} open selected
-      xywh {712 314 580 429} type Double box PLASTIC_DOWN_BOX resizable
-      code0 {\#include "ReorientImageUIBase.h"} visible
-    } {
-      Fl_Group {} {
-        label Desired open
-        xywh {345 30 225 390} box PLASTIC_DOWN_BOX labeltype EMBOSSED_LABEL align 5
-      } {
-        Fl_Input m_InDesiredRAI {
-          callback {this->OnDesiredRAIUpdate();}
-          xywh {355 40 70 25} labelsize 12 when 1 textsize 12
-        }
-        Fl_Output m_OutDesiredRAIError {
-          xywh {355 65 95 15} box FLAT_BOX color 52 labeltype NO_LABEL labelsize 10 align 0 textfont 1 textsize 10 textcolor 72
-        }
-        Fl_Output {m_OutDesiredAxisDirection[0]} {
-          xywh {355 85 205 25} color 49 labelsize 12 textsize 12
-        }
-        Fl_Output {m_OutDesiredAxisDirection[1]} {
-          xywh {355 115 205 25} color 49 labelsize 12 textsize 12
-        }
-        Fl_Output {m_OutDesiredAxisDirection[2]} {
-          xywh {355 145 205 25} color 49 labelsize 12 textsize 12
-        }
-        Fl_Output m_OutDesiredSForm {
-          label {output:}
-          xywh {355 185 205 55} type Multiline color 49 labeltype NO_LABEL align 20 textfont 4 textsize 9
-        }
-        Fl_Group {} {open
-          xywh {355 255 205 155} box ROUNDED_BOX color 7 align 16
-        } {
-          Fl_Wizard m_GrpDesiredDoll {open
-            xywh {395 270 130 120} box NO_BOX
-          } {
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollRAI.gif} xywh {395 270 130 120} align 16
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollRIA.gif} xywh {395 270 130 120} align 16 hide
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollARI.gif} xywh {395 270 130 120} align 16 hide
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollAIR.gif} xywh {395 270 130 120} align 16 hide
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollIRA.gif} xywh {395 270 130 120} align 16 hide
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollIAR.gif} xywh {395 270 130 120} align 16 hide
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollInvalid.gif} xywh {395 270 130 120} align 16 hide
-            } {}
-          }
-          Fl_Wizard {m_GrpDesiredDollAxis[0]} {open
-            xywh {435 380 75 30} box NO_BOX
-          } {
-            Fl_Group {} {
-              image {../ImageIOWizard/Artwork/x02.png} xywh {435 380 75 30} align 0 hide
-            } {}
-            Fl_Group {} {
-              image {../ImageIOWizard/Artwork/x01.png} xywh {435 380 75 30} align 0
-            } {}
-          }
-          Fl_Wizard {m_GrpDesiredDollAxis[1]} {open
-            xywh {520 285 30 95} box NO_BOX
-          } {
-            Fl_Group {} {
-              image {../ImageIOWizard/Artwork/y02.png} xywh {520 285 20 85} align 0 hide
-            } {}
-            Fl_Group {} {
-              image {../ImageIOWizard/Artwork/y01.png} xywh {520 285 20 85} align 0
-            } {}
-          }
-          Fl_Wizard {m_GrpDesiredDollAxis[2]} {open
-            xywh {380 345 50 65} box NO_BOX
-          } {
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/z01.png} xywh {380 345 40 55} align 0
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/z02.png} xywh {380 345 40 55} align 0 hide
-            } {}
-          }
-        }
-      }
-      Fl_Group {} {
-        label Current open
-        xywh {105 30 225 390} box PLASTIC_DOWN_BOX labeltype EMBOSSED_LABEL align 5
-      } {
-        Fl_Output m_OutCurrentRAI {
-          xywh {115 40 70 25} color 49 labelsize 12 textsize 12
-        }
-        Fl_Output {m_OutCurrentAxisDirection[0]} {
-          xywh {115 85 205 25} color 49 labelsize 12 textsize 12
-        }
-        Fl_Output {m_OutCurrentAxisDirection[1]} {
-          xywh {115 115 205 25} color 49 labelsize 12 textsize 12
-        }
-        Fl_Output {m_OutCurrentAxisDirection[2]} {
-          xywh {115 145 205 25} color 49 labelsize 12 textsize 12
-        }
-        Fl_Group {} {open
-          xywh {115 255 205 155} box ROUNDED_BOX color 7 align 16
-        } {
-          Fl_Wizard m_GrpCurrentDoll {open
-            xywh {155 270 130 120} box NO_BOX
-          } {
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollRAI.gif} xywh {155 270 130 120} align 16
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollRIA.gif} xywh {155 270 130 120} align 16 hide
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollARI.gif} xywh {155 270 130 120} align 16 hide
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollAIR.gif} xywh {155 270 130 120} align 16 hide
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollIRA.gif} xywh {155 270 130 120} align 16 hide
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollIAR.gif} xywh {155 270 130 120} align 16 hide
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/dollInvalid.gif} xywh {155 270 130 120} align 16 hide
-            } {}
-          }
-          Fl_Wizard {m_GrpCurrentDollAxis[0]} {open
-            xywh {195 380 75 30} box NO_BOX
-          } {
-            Fl_Group {} {
-              image {../ImageIOWizard/Artwork/x02.png} xywh {195 380 75 30} align 0 hide
-            } {}
-            Fl_Group {} {
-              image {../ImageIOWizard/Artwork/x01.png} xywh {195 380 75 30} align 0
-            } {}
-          }
-          Fl_Wizard {m_GrpCurrentDollAxis[1]} {open
-            xywh {280 285 30 95} box NO_BOX
-          } {
-            Fl_Group {} {
-              image {../ImageIOWizard/Artwork/y02.png} xywh {280 285 20 85} align 0 hide
-            } {}
-            Fl_Group {} {
-              image {../ImageIOWizard/Artwork/y01.png} xywh {280 285 20 85} align 0
-            } {}
-          }
-          Fl_Wizard {m_GrpCurrentDollAxis[2]} {open
-            xywh {140 345 50 65} box NO_BOX
-          } {
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/z01.png} xywh {140 345 40 55} align 0
-            } {}
-            Fl_Group {} {open
-              image {../ImageIOWizard/Artwork/z02.png} xywh {140 345 40 55} align 0 hide
-            } {}
-          }
-        }
-        Fl_Output m_OutCurrentSForm {
-          label {output:}
-          xywh {115 185 205 55} type Multiline color 49 labeltype NO_LABEL align 20 textfont 4 textsize 9
-        }
-        Fl_Output m_OutCurrentRAIClosest {
-          xywh {115 65 130 15} box FLAT_BOX color 52 labeltype NO_LABEL labelsize 10 align 0 textfont 1 textsize 10 textcolor 60
-        }
-      }
-      Fl_Group {} {
-        label {RAI Code:} open
-        xywh {10 40 85 25} labelsize 12 align 24
-      } {}
-      Fl_Group {} {
-        label {Voxel X Axis:} open
-        xywh {10 85 85 25} labelsize 12 align 24
-      } {}
-      Fl_Group {} {
-        label {Voxel Y Axis:} open
-        xywh {10 115 85 25} labelsize 12 align 24
-      } {}
-      Fl_Group {} {
-        label {Voxel Z Axis:} open
-        xywh {10 145 85 25} labelsize 12 align 24
-      } {}
-      Fl_Group {} {
-        label {Voxel to World
-Matrix (NIFTI):} open
-        xywh {10 185 85 25} labelsize 12 align 24
-      } {}
-      Fl_Button {} {
-        label {&Apply}
-        callback {this->OnApplyAction();}
-        xywh {10 360 80 25} box PLASTIC_UP_BOX shortcut 0x80061 color 180 labelfont 1 labelsize 12
-      }
-      Fl_Button {} {
-        label Close
-        callback {this->OnCloseAction();}
-        xywh {10 390 80 25} box PLASTIC_UP_BOX shortcut 0xff1b color 180 labelsize 12
-      }
-      Fl_Button {} {
-        label {&Ok}
-        callback {this->OnOkAction();}
-        xywh {10 330 80 25} box PLASTIC_UP_BOX shortcut 0x8006f color 180 labelfont 1 labelsize 12
-      }
-    }
-  }
-} 
diff --git a/UserInterface/MainComponents/ReorientImageUIBase.h b/UserInterface/MainComponents/ReorientImageUIBase.h
deleted file mode 100644
index 8b5fe10..0000000
--- a/UserInterface/MainComponents/ReorientImageUIBase.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ReorientImageUIBase.h,v $
-  Language:  C++
-  Date:      $Date: 2008/11/17 19:47:41 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-
-#ifndef __ReorientImageUIBase_h_
-#define __ReorientImageUIBase_h_
-
-class ReorientImageUIBase 
-{
-public:
-  virtual ~ReorientImageUIBase() {}
-  virtual void OnDesiredRAIUpdate() = 0;
-  virtual void OnOkAction() = 0;
-  virtual void OnApplyAction() = 0;
-  virtual void OnCloseAction() = 0;
-};
-
-
-#endif
-
-
diff --git a/UserInterface/MainComponents/ReorientImageUILogic.cxx b/UserInterface/MainComponents/ReorientImageUILogic.cxx
deleted file mode 100644
index f497da5..0000000
--- a/UserInterface/MainComponents/ReorientImageUILogic.cxx
+++ /dev/null
@@ -1,320 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ReorientImageUILogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2009/10/30 16:48:22 $
-  Version:   $Revision: 1.5 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-
-#include "SNAPCommonUI.h"
-#include "ReorientImageUILogic.h"
-#include "UserInterfaceLogic.h"
-#include "IRISApplication.h"
-#include "GenericImageData.h"
-#include "itkOrientedImage.h"
-#include <cassert>
-#include <string>
-#include <iomanip>
-#include <sstream>
-
-std::string
-PrintMatrixFormatted(
-  vnl_matrix<double> mat, 
-  size_t width, 
-  size_t precision, 
-  const char *prefix = "")
-{
-  // Create output stream
-  std::ostringstream sout;
-
-  // Print each row and column of the matrix
-  for(size_t i = 0; i < mat.rows(); i++)
-    {
-    sout << prefix;
-    for(size_t j = 0; j < mat.columns(); j++)
-      {
-      sout 
-        << std::setw(width) 
-        << std::setprecision(precision) 
-        << mat(i,j);
-      if(j == mat.columns() - 1)
-        sout << std::endl;
-      else 
-        sout << " ";
-      }
-    }
-
-  // Return result
-  return sout.str();
-}
-
-const char ReorientImageUILogic::m_RAICodes[3][2] = {
-  {'R', 'L'},
-  {'A', 'P'},
-  {'I', 'S'}};
-
-const char *ReorientImageUILogic::m_AxisLabels[3][2] = {
-  {"Right to Left", "Left to Right"},
-  {"Anterior to Posterior", "Posterior to Anterior"},
-  {"Inferior to Superior", "Superior to Inferior"}};
-
-ReorientImageUILogic
-::ReorientImageUILogic()
-{
-
-}
-
-void
-ReorientImageUILogic
-::ShowDialog()
-{
-  assert(m_ParentUI);
-
-  // Get the current image data  
-  m_ImageData = m_ParentUI->GetDriver()->GetCurrentImageData();
-
-  // Get the direction matrix
-  vnl_matrix_fixed<double, 3, 3> dir = 
-    m_ImageData->GetMain()->GetImageBase()->GetDirection().GetVnlMatrix();
-
-  // Compute the RAI code from the direction matrix
-  char rai[4]; rai[3] = 0;
-  bool oblique = false;
-
-  for(size_t i = 0; i < 3; i++)
-    {
-    // Get the direction cosine for voxel direction i
-    Vector3d dcos = dir.get_column(i);
-    double dabsmax = dcos.inf_norm();
-
-    for(size_t j = 0; j < 3; j++)
-      {
-      double dabs = fabs(dcos[j]);
-      size_t dsgn = dcos[j] > 0 ? 0 : 1;
-
-      if(dabs == 1.0)
-        {
-        rai[i] = m_RAICodes[j][dsgn];
-        m_OutCurrentAxisDirection[i]->value(m_AxisLabels[j][dsgn]);
-        }
-      else if(dabs == dabsmax)
-        {
-        oblique = true;
-        rai[i] = m_RAICodes[j][dsgn];
-        m_OutCurrentAxisDirection[i]->value("Oblique");
-        }
-      }
-    }
-      
-  // If RAI code is valid, set all the other components
-  if(oblique)
-    {
-    m_OutCurrentRAI->value("OBLIQUE");
-    std::ostringstream sout;
-    sout << "Closest to " << rai;
-    m_OutCurrentRAIClosest->value(sout.str().c_str());
-    m_InDesiredRAI->value(rai);
-    }
-  else
-    {
-    m_OutCurrentRAI->value(rai);
-    m_OutCurrentRAIClosest->value("");
-    m_InDesiredRAI->value(rai);
-    }
-
-  // Print the matrix
-  string smat_current = 
-    PrintMatrixFormatted(m_ImageData->GetMain()->GetNiftiSform(), 9, 3);
-  m_OutCurrentSForm->value(smat_current.c_str());
-
-  // Update the 'current' graphic
-  this->UpdateOrientationGraphic(rai, oblique, m_GrpCurrentDoll, m_GrpCurrentDollAxis);
-
-  // Update the other fields in the desired column
-  this->UpdateDesiredDerivedFields();
-
-  // Show the window
-  m_WinReorient->show();
-  m_ParentUI->CenterChildWindowInMainWindow(m_WinReorient);
-}
-
-void
-ReorientImageUILogic
-::UpdateDesiredDerivedFields()
-{
-  // An identity matrix, for pulling out rows
-  vnl_matrix_fixed<double, 3, 3> eye;
-  eye.set_identity();
-
-  // Apply the RAI code
-  const char *rai = m_InDesiredRAI->value();
-  for(size_t i = 0; i < 3; i++)
-    {
-    for(size_t j = 0; j < 3; j++)
-      {
-      for(size_t k = 0; k < 2; k++)
-        {
-        if(toupper(rai[i]) == m_RAICodes[j][k])
-          {
-          m_OutDesiredAxisDirection[i]->value(m_AxisLabels[j][k]);
-          m_DesiredDirection.set_column(i, (k==0 ? 1.0 : -1.0) * eye.get_row(j));
-          }
-        }
-      }
-    }
-
-  // Compute the new NIFTI matrix given these directions
-  vnl_matrix_fixed<double, 4, 4> m_sform = 
-    GreyImageWrapper::ConstructNiftiSform(
-      m_DesiredDirection,
-      m_ImageData->GetMain()->GetImageBase()->GetOrigin().GetVnlVector(),
-      m_ImageData->GetMain()->GetImageBase()->GetSpacing().GetVnlVector());
-
-  // Print the matrix
-  string smat_desired = 
-    PrintMatrixFormatted(m_sform, 9, 3);
-  m_OutDesiredSForm->value(smat_desired.c_str());  
-
-  // Update the graphic
-  this->UpdateOrientationGraphic(rai, false, m_GrpDesiredDoll, m_GrpDesiredDollAxis);
-}
-
-void
-ReorientImageUILogic
-::UpdateOrientationGraphic(
-  const char *rai, bool oblique, Fl_Wizard *grpDoll, Fl_Wizard *grpDollAxis[])
-{
-  // Handle oblique/invalid cases (show question mark)
-  if(oblique || !ImageCoordinateGeometry::IsRAICodeValid(rai))
-    {
-    grpDoll->value(grpDoll->child(6));
-    return;
-    }
-
-  // Initialize the mappings for the doll display
-  size_t xCodeToGraphicMap[3][3][3];
-  xCodeToGraphicMap[0][1][2] = 0; // RAI
-  xCodeToGraphicMap[0][2][1] = 1; // RIA
-  xCodeToGraphicMap[1][0][2] = 2; // ARI
-  xCodeToGraphicMap[1][2][0] = 3; // AIR
-  xCodeToGraphicMap[2][0][1] = 4; // IRA
-  xCodeToGraphicMap[2][1][0] = 5; // IAR
-
-  // Convert RAI to a numeric mapping
-  Vector3i rn = ImageCoordinateGeometry::ConvertRAIToCoordinateMapping(rai);
-  Vector3i ra = rn.apply(abs);
-  
-  // Get the appropriate doll
-  size_t idoll = xCodeToGraphicMap[ra[0]-1][ra[1]-1][ra[2]-1];
-
-  // Select the doll
-  grpDoll->value(grpDoll->child(idoll));
-
-  // Geez, this is getting complicated!
-  int xDollAxisFlips[6][3] = {
-    { 0, 0, 0 },
-    { 1, 1, 1 },
-    { 1, 0, 0 }, 
-    { 1, 1, 0 },
-    { 0, 1, 1 },
-    { 0, 0, 1 }}; 
-
-  // Flip the arrows too
-  for(size_t i = 0; i < 3; i++)
-    {
-    int axdir = (rn[i] > 0) 
-      ? xDollAxisFlips[idoll][i] 
-      : 1 - xDollAxisFlips[idoll][i];
-    grpDollAxis[i]->value(grpDollAxis[i]->child(axdir));
-    }
-}
-
-void
-ReorientImageUILogic
-::Register(UserInterfaceLogic *parent_ui)
-{ 
-  m_ParentUI = parent_ui; 
-}
-
-void 
-ReorientImageUILogic
-::OnDesiredRAIUpdate()
-{
-  // If the code is valid, update the UI  
-  if(ImageCoordinateGeometry::IsRAICodeValid(m_InDesiredRAI->value()))
-    {
-    m_OutDesiredRAIError->value("");
-    this->UpdateDesiredDerivedFields();
-    }
-  else
-    {
-    m_OutDesiredRAIError->value("Invalid RAI Code");
-    m_OutDesiredRAIError->show();
-    m_OutDesiredAxisDirection[0]->value("");
-    m_OutDesiredAxisDirection[1]->value("");
-    m_OutDesiredAxisDirection[2]->value("");
-    m_OutDesiredSForm->value("");
-    this->UpdateOrientationGraphic("", false, m_GrpDesiredDoll, m_GrpDesiredDollAxis);
-    }
-}
-
-void 
-ReorientImageUILogic
-::OnOkAction()
-{
-  this->OnApplyAction();
-  this->OnCloseAction();
-}
-
-void 
-ReorientImageUILogic
-::OnApplyAction()
-{
-  // Reorient the image
-  m_ParentUI->GetDriver()->ReorientImage(m_DesiredDirection);
-
-  // GUI has to refresh
-  m_ParentUI->OnImageGeometryUpdate();
-}
-
-void 
-ReorientImageUILogic
-::OnCloseAction()
-{
-  m_WinReorient->hide();
-}
-
-bool
-ReorientImageUILogic
-::Shown()
-{
-  return m_WinReorient->shown();
-}
-
diff --git a/UserInterface/MainComponents/ReorientImageUILogic.h b/UserInterface/MainComponents/ReorientImageUILogic.h
deleted file mode 100644
index c541a81..0000000
--- a/UserInterface/MainComponents/ReorientImageUILogic.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ReorientImageUILogic.h,v $
-  Language:  C++
-  Date:      $Date: 2009/10/30 16:48:24 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-
-#ifndef __ReorientImageUILogic_h_
-#define __ReorientImageUILogic_h_
-
-#include "ReorientImageUI.h"
-#include <vnl/vnl_matrix_fixed.h>
-
-class UserInterfaceLogic;
-class GenericImageData;
-
-class ReorientImageUILogic : public ReorientImageUI
-{
-public:
-  // Constructor
-  ReorientImageUILogic();
-  virtual ~ReorientImageUILogic() {}
-  
-  // Callbacks
-  void OnDesiredRAIUpdate();
-  void OnOkAction();
-  void OnApplyAction();
-  void OnCloseAction();
-
-  void ShowDialog();
-  void Register(UserInterfaceLogic *parent_ui);
-
-  bool Shown();
-
-private:
-
-  void UpdateDesiredDerivedFields();
-
-  // This code matches the orientation graphic to a RAI
-  void UpdateOrientationGraphic(
-    const char *rai, bool oblique, Fl_Wizard *grpDoll, Fl_Wizard *grpDollAxis[]);
-
-  UserInterfaceLogic *m_ParentUI;
-  GenericImageData *m_ImageData;
-
-  // Direction matrix for the desired RAI code
-  vnl_matrix_fixed<double, 3, 3> m_DesiredDirection;
-
-  static const char m_RAICodes[3][2];
-  static const char *m_AxisLabels[3][2];
-};
-
-
-#endif
-
diff --git a/UserInterface/MainComponents/ResizeRegionDialog.fl b/UserInterface/MainComponents/ResizeRegionDialog.fl
deleted file mode 100644
index ed3cf44..0000000
--- a/UserInterface/MainComponents/ResizeRegionDialog.fl
+++ /dev/null
@@ -1,251 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0102 
-header_name {.h} 
-code_name {.cxx}
-class ResizeRegionDialog {open : { private ResizeRegionDialogBase }
-} {
-  Function {MakeWindow()} {open return_type {virtual void}
-  } {
-    Fl_Window m_WinResample {
-      label {Region Resampling} open
-      xywh {766 513 440 349} type Double box PLASTIC_DOWN_BOX
-      code0 {\#include "ResizeRegionDialogBase.h"} modal visible
-    } {
-      Fl_Group {} {
-        label {Segmentation Region Resampling} open
-        xywh {5 5 435 35} labeltype EMBOSSED_LABEL align 16
-      } {}
-      Fl_Group {} {
-        label {Input image voxel size:} open
-        xywh {10 60 420 55} box PLASTIC_UP_BOX labelsize 12 align 5
-      } {
-        Fl_Value_Output {m_OutSize[0]} {
-          label {X:}
-          xywh {45 75 55 25} box DOWN_BOX color 51 labelsize 12 textsize 12
-        }
-        Fl_Value_Output {m_OutSize[1]} {
-          label {Y:}
-          xywh {180 75 55 25} box DOWN_BOX color 51 labelsize 12 textsize 12
-        }
-        Fl_Value_Output {m_OutSize[2]} {
-          label {Z:}
-          xywh {315 75 55 25} box DOWN_BOX color 51 labelsize 12 textsize 12
-        }
-        Fl_Group {} {
-          label {mm.} open
-          xywh {100 75 35 25} labelsize 12 align 16
-        } {}
-        Fl_Group {} {
-          label {mm.} open
-          xywh {235 75 35 25} labelsize 12 align 16
-        } {}
-        Fl_Group {} {
-          label {mm.} open
-          xywh {370 75 35 25} labelsize 12 align 16
-        } {}
-      }
-      Fl_Group {} {
-        label {Region of interest voxel size:} open
-        xywh {10 140 420 75} box PLASTIC_UP_BOX labelsize 12 align 5
-      } {
-        Fl_Value_Input {m_InSize[0]} {
-          label {X:}
-          callback {this->OnVoxelSizeChange();}
-          xywh {45 155 55 25} labelsize 12 textsize 12
-        }
-        Fl_Value_Input {m_InSize[1]} {
-          label {Y:}
-          callback {this->OnVoxelSizeChange();}
-          xywh {180 155 55 25} labelsize 12 textsize 12
-        }
-        Fl_Value_Input {m_InSize[2]} {
-          label {Z:}
-          callback {this->OnVoxelSizeChange();}
-          xywh {315 155 55 25} labelsize 12 textsize 12
-        }
-        Fl_Choice {m_InScale[0]} {
-          callback {this->OnVoxelScaleChange();} open
-          xywh {45 185 75 20} down_box BORDER_BOX labelsize 11 textsize 11
-        } {
-          menuitem {} {
-            label custom
-            xywh {90 90 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {5 : 1}
-            xywh {0 0 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {4 : 1}
-            xywh {10 10 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {3 : 1}
-            xywh {20 20 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {2 : 1}
-            xywh {30 30 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 1}
-            xywh {40 40 100 20} value 1 labelsize 11
-          }
-          menuitem {} {
-            label {1 : 2}
-            xywh {50 50 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 3}
-            xywh {60 60 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 4}
-            xywh {70 70 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 5}
-            xywh {80 80 100 20} labelsize 11
-          }
-        }
-        Fl_Choice {m_InScale[1]} {
-          callback {this->OnVoxelScaleChange();} open
-          xywh {180 185 75 20} down_box BORDER_BOX labelsize 11 textsize 11
-        } {
-          menuitem {} {
-            label custom
-            xywh {100 100 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {5 : 1}
-            xywh {10 10 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {4 : 1}
-            xywh {20 20 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {3 : 1}
-            xywh {30 30 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {2 : 1}
-            xywh {40 40 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 1}
-            xywh {50 50 100 20} value 1 labelsize 11
-          }
-          menuitem {} {
-            label {1 : 2}
-            xywh {60 60 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 3}
-            xywh {70 70 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 4}
-            xywh {80 80 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 5}
-            xywh {90 90 100 20} labelsize 11
-          }
-        }
-        Fl_Choice {m_InScale[2]} {
-          callback {this->OnVoxelScaleChange();} open
-          xywh {315 185 75 20} down_box BORDER_BOX labelsize 11 textsize 11
-        } {
-          menuitem {} {
-            label custom
-            xywh {110 110 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {5 : 1}
-            xywh {20 20 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {4 : 1}
-            xywh {30 30 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {3 : 1}
-            xywh {40 40 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {2 : 1}
-            xywh {50 50 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 1}
-            xywh {60 60 100 20} value 1 labelsize 11
-          }
-          menuitem {} {
-            label {1 : 2}
-            xywh {70 70 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 3}
-            xywh {80 80 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 4}
-            xywh {90 90 100 20} labelsize 11
-          }
-          menuitem {} {
-            label {1 : 5}
-            xywh {100 100 100 20} labelsize 11
-          }
-        }
-        Fl_Group {} {
-          label {mm.}
-          xywh {235 155 35 25} labelsize 12 align 16
-        } {}
-        Fl_Group {} {
-          label {mm.} open
-          xywh {100 155 35 25} labelsize 12 align 16
-        } {}
-        Fl_Group {} {
-          label {mm.} open
-          xywh {370 155 35 25} labelsize 12 align 16
-        } {}
-      }
-      Fl_Group {} {
-        label {Resampling method:} open
-        xywh {10 240 420 55} box PLASTIC_UP_BOX labelsize 12 align 5
-      } {
-        Fl_Choice m_InInterpolation {open
-          xywh {85 255 265 25} down_box BORDER_BOX labelsize 12 textsize 12
-        } {
-          menuitem {} {
-            label {Nearest Neighbor (fastest) } selected
-            xywh {0 0 100 20} labelsize 12
-          }
-          menuitem {} {
-            label {Linear Interpolation (fast)}
-            xywh {10 10 100 20} labelsize 12
-          }
-          menuitem {} {
-            label {Cubic Interpolation (high quality)}
-            xywh {20 20 100 20} value 1 labelsize 12
-          }
-          menuitem {} {
-            label {Windowed Sinc Interpolation (best quality)}
-            xywh {30 30 100 20} labelsize 12
-          }
-        }
-      }
-      Fl_Button {} {
-        label Ok
-        callback {OnOkAction();}
-        xywh {125 310 90 25} box PLASTIC_UP_BOX color 180 labelfont 1 labelsize 12
-      }
-      Fl_Button {} {
-        label Cancel
-        callback {OnCancelAction();}
-        xywh {225 310 90 25} box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-    }
-  }
-} 
diff --git a/UserInterface/MainComponents/ResizeRegionDialogBase.h b/UserInterface/MainComponents/ResizeRegionDialogBase.h
deleted file mode 100644
index 11e88b3..0000000
--- a/UserInterface/MainComponents/ResizeRegionDialogBase.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ResizeRegionDialogBase.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:17 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __ResizeRegionDialogBase_h_
-#define __ResizeRegionDialogBase_h_
-
-class ResizeRegionDialogBase {
-public:
-    virtual ~ResizeRegionDialogBase() {}
-  virtual void OnVoxelSizeChange() = 0;
-  virtual void OnVoxelScaleChange() = 0;
-  virtual void OnOkAction() = 0;
-  virtual void OnCancelAction() = 0;
-};
-
-#endif // __ResizeRegionDialogBase_h_
diff --git a/UserInterface/MainComponents/ResizeRegionDialogLogic.cxx b/UserInterface/MainComponents/ResizeRegionDialogLogic.cxx
deleted file mode 100644
index eccf426..0000000
--- a/UserInterface/MainComponents/ResizeRegionDialogLogic.cxx
+++ /dev/null
@@ -1,182 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ResizeRegionDialogLogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:17 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "ResizeRegionDialogLogic.h"
-
-const int 
-ResizeRegionDialogLogic::NumberOfScaleChoices = 10;
-
-const int 
-ResizeRegionDialogLogic::ScaleChoices[10][2] = 
-  {{0,0},{5,1},{4,1},{3,1},{2,1},{1,1},{1,2},{1,3},{1,4},{1,5}};
-
-void 
-ResizeRegionDialogLogic
-::MakeWindow()
-{
-  // Call parent method
-  ResizeRegionDialog::MakeWindow();
-
-  // Update the UI choices to defaults
-  m_InScale[0]->value(5);
-  m_InScale[1]->value(5);
-  m_InScale[2]->value(5);
-  m_InInterpolation->value(2);
-}
-
-bool 
-ResizeRegionDialogLogic
-::DisplayDialog(const double *voxelSpacing, 
-                SNAPSegmentationROISettings &targetROI)
-{
-  // Set the input spacing values
-  for(unsigned int i=0;i<3;i++)
-    m_OutSize[i]->value(voxelSpacing[i]);
-
-  // Compute the output voxel sizes based on the current scaling settings
-  OnVoxelScaleChange();
-
-  // Show the dialog
-  m_WinResample->show();
-
-  // Run until closed
-  m_Accept = false;
-  while(m_WinResample->shown())
-    Fl::wait();
-
-  // Compute the voxel scaling
-  Vector3d voxelScaling(1.0);
-  if(m_Accept)
-    {
-    voxelScaling[0] = GetSpacing(0) / voxelSpacing[0];
-    voxelScaling[1] = GetSpacing(1) / voxelSpacing[1];
-    voxelScaling[2] = GetSpacing(2) / voxelSpacing[2];
-    }
-  
-  // Update the settings object
-  targetROI.SetVoxelScale(voxelScaling);
-  targetROI.SetResampleFlag(m_Accept);
-
-  // Update the interpolation mode
-  switch(m_InInterpolation->value()) 
-    {
-    case 0 : 
-      targetROI.SetInterpolationMethod(
-        SNAPSegmentationROISettings::NEAREST_NEIGHBOR);
-      break;
-    case 1 : 
-      targetROI.SetInterpolationMethod(
-        SNAPSegmentationROISettings::TRILINEAR);
-      break;
-    case 2 : 
-      targetROI.SetInterpolationMethod(
-        SNAPSegmentationROISettings::TRICUBIC);
-      break;
-    case 3 : 
-      targetROI.SetInterpolationMethod(
-        SNAPSegmentationROISettings::SINC_WINDOW_05);
-      break;
-    };
-
-  // Return the accept flag
-  return m_Accept;
-}
-
-void 
-ResizeRegionDialogLogic
-::OnVoxelScaleChange()
-{
-  // Set the output spacing values
-  for(unsigned int i=0;i<3;i++)
-    {
-    // Get the numerator and denominator
-    int choice = m_InScale[i]->value();
-    int scaleFrom = ScaleChoices[choice][0];
-    int scaleTo = ScaleChoices[choice][1];
-
-    // If both scale choices are 0 and 0, i.e, custom mode, leave the values
-    // unchanged
-    if(scaleFrom == 0 && scaleTo == 0)
-      continue;
-
-    if(scaleFrom == 1)
-      m_InSize[i]->value(scaleTo * m_OutSize[i]->value());
-    else
-      m_InSize[i]->value(m_OutSize[i]->value() / scaleFrom);
-    }
-}
-
-void 
-ResizeRegionDialogLogic
-::OnVoxelSizeChange()
-{
-  // Set the output spacing values
-  for(unsigned int i=0;i<3;i++)
-    {
-    int choice = 0; // Custom choice
-    for(int j = 1;j < NumberOfScaleChoices;j++)
-      {
-      // Get the numerator and denominator
-      int scaleFrom = ScaleChoices[j][0];
-      int scaleTo = ScaleChoices[j][1];
-
-      // See if the choice fits
-      if(m_InSize[i]->value() * scaleFrom == m_OutSize[i]->value() * scaleTo)
-        {
-        choice = j;
-        break;
-        }
-      }
-
-    m_InScale[i]->value(choice);
-    }
-}
-
-void
-ResizeRegionDialogLogic
-::OnOkAction()
-{
-  m_WinResample->hide();
-  m_Accept = true;
-}
-
-void
-ResizeRegionDialogLogic
-::OnCancelAction()
-{
-  m_WinResample->hide();
-  m_Accept = false;
-}
-
-
diff --git a/UserInterface/MainComponents/ResizeRegionDialogLogic.h b/UserInterface/MainComponents/ResizeRegionDialogLogic.h
deleted file mode 100644
index 61c52ae..0000000
--- a/UserInterface/MainComponents/ResizeRegionDialogLogic.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ResizeRegionDialogLogic.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:17 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __ResizeRegionDialogLogic_h_
-#define __ResizeRegionDialogLogic_h_
-
-#include "ResizeRegionDialog.h"
-#include "SNAPSegmentationROISettings.h"
-
-class ResizeRegionDialogLogic : public ResizeRegionDialog {
-public:
-    virtual ~ResizeRegionDialogLogic() {}
-  // A list of scaling choices
-  static const int NumberOfScaleChoices;
-  static const int ScaleChoices[10][2];
-
-  // Resampling method
-  enum ResamplingMethod {
-    NearestNeighbor, Linear
-  };
-  
-  // Get the new spacing
-  double GetSpacing(unsigned int dim) {
-    return m_InSize[dim]->value();
-  }
-
-  // Get the selected resampling method
-  ResamplingMethod GetResamplingMethod() {
-    return (ResamplingMethod)(NearestNeighbor + m_InInterpolation->value());
-  }
-
-  // Callback functions
-  void MakeWindow();
-  bool DisplayDialog(const double *voxelSpacing,
-                     SNAPSegmentationROISettings &targetROI);
-  void OnVoxelSizeChange();
-  void OnVoxelScaleChange();
-  void OnOkAction();
-  void OnCancelAction();
-
-private:
-  bool m_Accept;
-};
-
-#endif // __ResizeRegionDialogLogic_h_
diff --git a/UserInterface/MainComponents/RestoreSettingsDialog.fl b/UserInterface/MainComponents/RestoreSettingsDialog.fl
deleted file mode 100644
index ff7bfe7..0000000
--- a/UserInterface/MainComponents/RestoreSettingsDialog.fl
+++ /dev/null
@@ -1,70 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0300 
-header_name {.h} 
-code_name {.cxx}
-class RestoreSettingsDialog {open : {private RestoreSettingsDialogBase}
-} {
-  Function {MakeWindow()} {open
-  } {
-    Fl_Window m_WinMain {
-      label {Restore Settings?}
-      callback {OnCancelAction();} open
-      xywh {123 300 400 255} type Double box PLASTIC_DOWN_BOX
-      code0 {\#include "RestoreSettingsDialogBase.h"} visible
-    } {
-      Fl_Group {} {
-        label {Would you like ITK-SNAP to restore the settings that were used the last time you worked with this image?  
-
-The following settings can be restored:} open selected
-        xywh {10 10 385 65} labelsize 12 align 149
-      } {}
-      Fl_Group {} {open
-        xywh {20 70 360 115}
-      } {
-        Fl_Check_Button m_ChkLabels {
-          label {Labels for segmentation}
-          xywh {55 80 320 20} down_box DOWN_BOX value 1 labelsize 12
-        }
-        Fl_Check_Button m_ChkPreprocessing {
-          label {Image preprocessing parameters}
-          xywh {55 100 320 20} down_box DOWN_BOX value 1 labelsize 12
-        }
-        Fl_Check_Button m_ChkParameters {
-          label {Automatic segmentation parameters}
-          xywh {55 120 320 20} down_box DOWN_BOX value 1 labelsize 12
-        }
-        Fl_Check_Button m_ChkDisplayOptions {
-          label {Display options}
-          xywh {55 140 320 20} down_box DOWN_BOX value 1 labelsize 12
-        }
-      }
-      Fl_Button {} {
-        label {&Restore Settings}
-        callback {OnRestoreSettingsAction();}
-        xywh {85 220 120 25} box PLASTIC_UP_BOX shortcut 0x80072 color 180 labelfont 1 labelsize 12
-      }
-      Fl_Button {} {
-        label {Don't Restore}
-        callback {OnDoNotRestoreSettingsAction();}
-        xywh {220 220 105 25} box PLASTIC_UP_BOX shortcut 0xff1b color 180 labelsize 12
-      }
-      Fl_Choice m_InFutureApproach {
-        label {In the future, } open
-        xywh {100 185 230 20} down_box BORDER_BOX labelsize 12 textsize 12
-      } {
-        MenuItem {} {
-          label {continue asking this question}
-          xywh {0 0 100 20} labelsize 12
-        }
-        MenuItem {} {
-          label {don't ask again about this image}
-          xywh {20 20 100 20} labelsize 12
-        }
-        MenuItem {} {
-          label {never ask me this question}
-          xywh {30 30 100 20} labelsize 12
-        }
-      }
-    }
-  }
-} 
diff --git a/UserInterface/MainComponents/RestoreSettingsDialogBase.h b/UserInterface/MainComponents/RestoreSettingsDialogBase.h
deleted file mode 100644
index d9ea6b2..0000000
--- a/UserInterface/MainComponents/RestoreSettingsDialogBase.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: RestoreSettingsDialogBase.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:17 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __RestoreSettingsDialogBase_h_
-#define __RestoreSettingsDialogBase_h_
-
-class RestoreSettingsDialogBase {
-public:
-    virtual ~RestoreSettingsDialogBase() {}
-  virtual void OnRestoreSettingsAction() = 0;
-  virtual void OnDoNotRestoreSettingsAction() = 0;
-  virtual void OnCancelAction() = 0;
-};
-
-#endif // __RestoreSettingsDialogBase_h_
diff --git a/UserInterface/MainComponents/RestoreSettingsDialogLogic.cxx b/UserInterface/MainComponents/RestoreSettingsDialogLogic.cxx
deleted file mode 100644
index efb2a14..0000000
--- a/UserInterface/MainComponents/RestoreSettingsDialogLogic.cxx
+++ /dev/null
@@ -1,159 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: RestoreSettingsDialogLogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:17 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "RestoreSettingsDialogLogic.h"
-#include "UserInterfaceBase.h"
-#include "SystemInterface.h"
-
-#include <vector>
-
-// Disable some windows debug length messages
-#if defined(_MSC_VER)
-#pragma warning ( disable : 4786 )
-#pragma warning ( disable : 4503 )
-#endif
-
-using namespace std;
-
-void 
-RestoreSettingsDialogLogic
-::DisplayDialog(UserInterfaceBase *parent, Registry *associatedSettings)
-{
-  // Remember the code and the system interface
-  m_SystemInterface = parent->GetSystemInterface();
-  m_AssociatedSettings = associatedSettings;
-
-  // Clear this flag
-  m_AssociatedSettingsHaveChanged = false;
-  
-  // Determine whether the options should be displayed at all
-  Registry *folder =  
-    &m_SystemInterface->Folder("ImageAssociation.RestoreOptions.Generic");
-  bool noprompt = folder->Entry("DoNotPrompt")[false];
-
-  // If the generic setting is to prompt, check for a specific setting
-  if(!noprompt) 
-    {
-    folder = &m_AssociatedSettings->Folder("RestoreOptions");
-    noprompt = folder->Entry("DoNotPrompt")[false]; 
-    }
-  
-  // Now the noprompt and key combination should reflect either the generic or 
-  // the specific state
-  if(noprompt)
-    {
-    // The user doesn't want to be prompted.  Load the settings
-    m_RestoreSettings = folder->Entry("RestoreAny")[true];
-    m_RestoreLabels = folder->Entry("RestoreLabels")[true];
-    m_RestoreParameters = folder->Entry("RestoreParameters")[true];
-    m_RestorePreprocessing = folder->Entry("RestorePreprocessing")[true];
-    m_RestoreDisplayOptions = folder->Entry("RestoreDisplayOptions")[true];
-    }
-  else
-    {
-    // Show the dialog and let the user specify what features to restore
-    parent->CenterChildWindowInMainWindow(m_WinMain);
-    m_WinMain->show(); 
-    while(m_WinMain->shown()) Fl::wait();
-    }
-}
-
-void 
-RestoreSettingsDialogLogic
-::OnRestoreSettingsAction()
-{
-  // Set the current state
-  m_RestoreSettings = true;
-  m_RestoreLabels = m_ChkLabels->value() != 0;
-  m_RestorePreprocessing = m_ChkPreprocessing->value() != 0;
-  m_RestoreParameters = m_ChkParameters->value() != 0;
-  m_RestoreDisplayOptions = m_ChkDisplayOptions->value() != 0;
-  
-  // Save for the future
-  SaveDefaultSettingsForFutureIfRequested();
-  
-  // Hide the window
-  m_WinMain->hide();
-}
-
-void 
-RestoreSettingsDialogLogic
-::OnDoNotRestoreSettingsAction()
-{
-  // Set the current state
-  m_RestoreSettings = false;
-  
-  // Save for the future
-  SaveDefaultSettingsForFutureIfRequested();
-  
-  // Hide the window
-  m_WinMain->hide();
-}
-
-void 
-RestoreSettingsDialogLogic
-::OnCancelAction()
-{
-  // Hide the window
-  m_WinMain->hide();
-}
-
-void 
-RestoreSettingsDialogLogic
-::SaveDefaultSettingsForFutureIfRequested()
-{
-  // If the user specified a future action, record that he/she does not
-  // want to be bothered with this question again
-  unsigned int future = m_InFutureApproach->value();
-  if(!future) return;
-
-  // Get a folder into which the settings should be dumped
-  Registry *folder = (future == 2) ?
-    &m_SystemInterface->Folder("ImageAssociation.RestoreOptions.Generic") : 
-    &m_AssociatedSettings->Folder("RestoreOptions");
-
-  // Store the current settings as associated with the key
-  folder->Entry("DoNotPrompt") << true;
-  folder->Entry("RestoreAny") << m_RestoreSettings;
-
-  // Store the individual settings 
-  folder->Entry("RestoreLabels") << m_RestoreLabels;
-  folder->Entry("RestoreParameters") << m_RestoreParameters;
-  folder->Entry("RestorePreprocessing") << m_RestorePreprocessing;
-  folder->Entry("RestoreDisplayOptions") << m_RestoreDisplayOptions;
-
-  // Set this flag
-  if(future == 1)
-    m_AssociatedSettingsHaveChanged = true;
-}
diff --git a/UserInterface/MainComponents/RestoreSettingsDialogLogic.h b/UserInterface/MainComponents/RestoreSettingsDialogLogic.h
deleted file mode 100644
index d7802a7..0000000
--- a/UserInterface/MainComponents/RestoreSettingsDialogLogic.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: RestoreSettingsDialogLogic.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:17 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __RestoreSettingsDialogLogic_h_
-#define __RestoreSettingsDialogLogic_h_
-
-#include "Registry.h"
-#include "SNAPCommonUI.h"
-#include "RestoreSettingsDialog.h"
-
-class SystemInterface;
-class UserInterfaceBase;
-
-/**
- * \class RestoreSettingsDialogLogic
- * \brief A dialog used to prompt the user whether to restore settings associated
- * with an image or not.
- */
-class RestoreSettingsDialogLogic : public RestoreSettingsDialog {
-public: 
-  RestoreSettingsDialogLogic() {};
-  virtual ~RestoreSettingsDialogLogic() {};
-
-  /** Optionally display this dialog based on the options specified in
-   * the system settings.  The caller can prompt whether the user wanted
-   * to restore settings, and which settings the user wanted to restore
-   * using the GetXXX methods in this class.
-   *
-   * The first parameter is the pointer to the \see SystemInterface object.
-   * The second parameter is the 16 digit code used to refer to the image
-   * in the system interface registry */
-  void DisplayDialog(UserInterfaceBase *parent, Registry *associatedSettings);    
-
-  /** Did the user want to restore settings */
-  irisGetMacro(RestoreSettings,bool);
-  
-  /** Did the user want to restore segmentation labels */
-  irisGetMacro(RestoreLabels,bool);
-  
-  /** Did the user want to restore preprocessing settings */
-  irisGetMacro(RestorePreprocessing,bool);
-  
-  /** Did the user want to restore segmentation parameters */
-  irisGetMacro(RestoreParameters,bool);
-  
-  /** Did the user want to restore display options */
-  irisGetMacro(RestoreDisplayOptions,bool);
-
-  /** Has the dialog changed the AssociatedSettings ? */
-  irisGetMacro(AssociatedSettingsHaveChanged,bool);
-  
-  // User interface callbacks
-  void OnRestoreSettingsAction();
-  void OnDoNotRestoreSettingsAction();
-  void OnCancelAction();
- 
-private:
-  // The system interface pointer
-  SystemInterface *m_SystemInterface;
-
-  // Settings associated with the current image
-  Registry *m_AssociatedSettings;
-
-  // Settings from the restore state
-  bool m_RestoreSettings;
-  bool m_RestoreLabels;
-  bool m_RestorePreprocessing;
-  bool m_RestoreParameters;
-  bool m_RestoreDisplayOptions;
-
-  // Whether or not we updated the AssociatedSettings
-  bool m_AssociatedSettingsHaveChanged;
-
-  // Method that saves the settings for the future on user request
-  void SaveDefaultSettingsForFutureIfRequested();
-};
-
-#endif // __RestoreSettingsDialogLogic_h_
diff --git a/UserInterface/MainComponents/SimpleFileDialog.fl b/UserInterface/MainComponents/SimpleFileDialog.fl
deleted file mode 100644
index 96e9281..0000000
--- a/UserInterface/MainComponents/SimpleFileDialog.fl
+++ /dev/null
@@ -1,41 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0104 
-header_name {.h} 
-code_name {.cxx}
-class SimpleFileDialog {open : { private SimpleFileDialogBase }
-} {
-  Function {MakeWindow()} {open
-  } {
-    Fl_Window m_Window {
-      label {Load File} open
-      xywh {551 370 373 152} type Double box PLASTIC_DOWN_BOX
-      code0 {\#include "SimpleFileDialogBase.h"} modal visible
-    } {
-      Fl_Input m_InFile {
-        label {File:}
-        callback {OnFileChange();}
-        xywh {15 35 340 25} labelsize 12 align 5 textsize 12
-      }
-      Fl_Button {} {
-        label {&Browse...}
-        callback {this->OnBrowseAction();}
-        xywh {185 65 80 25} box PLASTIC_UP_BOX down_box UP_BOX shortcut 0x80062 labelsize 12
-      }
-      Fl_Menu_Button m_InHistory {
-        label History
-        callback {OnHistoryChange();} open
-        xywh {275 65 80 25} box PLASTIC_UP_BOX selection_color 181 labelsize 12 align 20 textsize 12
-      } {}
-      Fl_Button m_BtnOk {
-        label Ok
-        callback {this->OnOkAction();} selected
-        xywh {100 120 80 25} box PLASTIC_UP_BOX down_box DOWN_BOX shortcut 0x1ff0d color 180 labelfont 1 labelsize 12
-      }
-      Fl_Button {} {
-        label Cancel
-        callback {this->OnCancelAction();}
-        xywh {190 120 80 25} box PLASTIC_UP_BOX down_box DOWN_BOX shortcut 0xff1b color 180 labelsize 12
-      }
-    }
-  }
-} 
diff --git a/UserInterface/MainComponents/SimpleFileDialogBase.h b/UserInterface/MainComponents/SimpleFileDialogBase.h
deleted file mode 100644
index 2a83c09..0000000
--- a/UserInterface/MainComponents/SimpleFileDialogBase.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SimpleFileDialogBase.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:17 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SimpleFileDialogBase_h_
-#define __SimpleFileDialogBase_h_
-
-class SimpleFileDialogBase {
-public:
-    virtual ~SimpleFileDialogBase() {}
-  virtual void OnFileChange() = 0;
-  virtual void OnHistoryChange() = 0;
-  virtual void OnBrowseAction() = 0;
-  virtual void OnOkAction() = 0;
-  virtual void OnCancelAction() = 0;
-};
-
-#endif // __SimpleFileDialogBase_h_
diff --git a/UserInterface/MainComponents/SimpleFileDialogLogic.cxx b/UserInterface/MainComponents/SimpleFileDialogLogic.cxx
deleted file mode 100644
index 7079128..0000000
--- a/UserInterface/MainComponents/SimpleFileDialogLogic.cxx
+++ /dev/null
@@ -1,203 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SimpleFileDialogLogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/05/31 19:52:37 $
-  Version:   $Revision: 1.5 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "SimpleFileDialogLogic.h"
-#include "itkCommand.h"
-#include "FL/Fl_Native_File_Chooser.H"
-
-#include <algorithm>
-
-using namespace std;
-
-SimpleFileDialogLogic
-::SimpleFileDialogLogic()
-{
-  m_FileChooser = NULL;
-}
-
-SimpleFileDialogLogic
-::~SimpleFileDialogLogic()
-{
-  if(m_FileChooser)
-    delete m_FileChooser;
-}
-
-void
-SimpleFileDialogLogic
-::MakeWindow()
-{
-  SimpleFileDialog::MakeWindow();
-  m_FileChooser = new Fl_Native_File_Chooser;
-}
-
-void
-SimpleFileDialogLogic
-::DisplayLoadDialog(const HistoryListType &history,const char *file)
-{
-  m_SaveMode = false;
-  this->DisplayDialog(history,file);
-}
-  
-void
-SimpleFileDialogLogic
-::DisplaySaveDialog(const HistoryListType &history,const char *file)
-{
-  m_SaveMode = true;
-  this->DisplayDialog(history,file);
-}
-
-void 
-SimpleFileDialogLogic
-::DisplayDialog(const HistoryListType &history, const char *file)
-{
-  // If the filename was supplied, update it in the UI
-  if(file)
-    {
-    m_InFile->value(file);
-    }
-
-  // Clear the history drop box
-  m_InHistory->clear();
-
-  // Add elements in the history list
-  if(history.size() > 0)
-    {  
-    // Add each item to the history menu (history is traversed backwards)
-    HistoryListType::const_reverse_iterator it;
-    for(it=history.rbegin();it!=history.rend();it++)
-      {
-      // FLTK's add() treats slashes as submenu separators, hence this code
-      m_InHistory->replace(m_InHistory->add("dummy"),it->c_str());
-      }
-
-    // Activate the history menu    
-    m_InHistory->activate();
-    }
-  else
-    {
-    // Deactivate history
-    m_InHistory->deactivate();
-    }
-
-  // Deactivate / activate the OK button
-  this->OnFileChange();
-
-  // Show the dialog and wait until it closes
-  m_Window->show();
-  while(m_Window->shown())
-    Fl::wait();  
-}
-
-void 
-SimpleFileDialogLogic
-::OnFileChange()
-{
-  // Disable the OK button if the file box is empty
-  if(!m_InFile->value() || strlen(m_InFile->value()) == 0)
-    m_BtnOk->deactivate();
-  else
-    m_BtnOk->activate();
-}
-
-void 
-SimpleFileDialogLogic
-::OnHistoryChange()
-{
-  // Put the seleted history into the file box
-  m_InFile->value(m_InHistory->mvalue()->text);
-
-  // Act as if the user changed the file
-  OnFileChange();
-}
-
-void 
-SimpleFileDialogLogic
-::OnBrowseAction()
-{
-  if (m_SaveMode)
-    {
-    m_FileChooser->type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
-    m_FileChooser->title("Save a file");
-    }
-  else
-    {
-    m_FileChooser->type(Fl_Native_File_Chooser::BROWSE_FILE);
-    m_FileChooser->title("Load a file");
-    }
-  
-  // If there is something in the file box, pass it to the chooser
-  if(m_InFile->value() && strlen(m_InFile->value()))
-    m_FileChooser->preset_file(m_InFile->value());
-
-  // Set the pattern
-  m_FileChooser->filter(m_Pattern.c_str());
-
-  // Show the dialog
-  if (m_FileChooser->show() == 0)
-    {
-    const char *fName = NULL;
-    fName = m_FileChooser->filename();
-    if (fName && strlen(fName))
-      {
-      m_InFile->value(fName);
-      m_BtnOk->activate();
-      }
-    }
-}
-
-void 
-SimpleFileDialogLogic
-::OnOkAction()
-{
-  try 
-    {
-    // Fire the appropriate event
-    if(m_SaveMode)
-      m_SaveCallback->Execute((itk::Object *) 0,itk::NoEvent());
-    else 
-      m_LoadCallback->Execute((itk::Object *) 0,itk::NoEvent());
-  
-    // Hide the window
-    m_Window->hide();
-  }
-  catch(...) { }
-}
-
-void 
-SimpleFileDialogLogic
-::OnCancelAction()
-{
-  // Hide the window
-  m_Window->hide();
-}
diff --git a/UserInterface/MainComponents/SimpleFileDialogLogic.h b/UserInterface/MainComponents/SimpleFileDialogLogic.h
deleted file mode 100644
index 99fbcd9..0000000
--- a/UserInterface/MainComponents/SimpleFileDialogLogic.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SimpleFileDialogLogic.h,v $
-  Language:  C++
-  Date:      $Date: 2009/05/25 17:09:44 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SimpleFileDialogLogic_h_
-#define __SimpleFileDialogLogic_h_
-
-#include "itkSmartPointer.h"
-#include "SNAPCommonUI.h"
-#include "SimpleFileDialog.h"
-#include "itkCommand.h"
-
-class Fl_Native_File_Chooser;
-namespace itk {
-  class Command;
-}
-
-/**
- * \class SimpleFileDialogLogic
- * \brief A very basic file dialog with a history list
- * A simple file dialog used to load and save text files, such as
- * projects, voxel counts, etc.  
- */
-class SimpleFileDialogLogic : public SimpleFileDialog {
-public: 
-  SimpleFileDialogLogic();
-  virtual ~SimpleFileDialogLogic();
-
-  // Vector type for passing in history
-  typedef std::string StringType;
-  typedef std::vector<StringType> HistoryListType;
-
-  /** Called on creation, this method configures some controls */
-  void MakeWindow();
-
-  /** Display a load dialog.  The first parameter to this dialog
-   * is a registry representing the history of recently loaded
-   * files.  The second parameter is the optional text to display
-   * in the filename box.  If NULL is passed in (default), the previously
-   * used file name will be retained.  
-   *
-   * The history will not be updated until a 
-   *
-   * The return from this method is analogous
-   * to fl_file_chooser, ie, a filename or NULL if user cancelled.*/
-  void DisplayLoadDialog(
-    const HistoryListType &history, const char *file = NULL);
-
-  /** Display a save dialog.  \see DisplayLoadDialog */
-  void DisplaySaveDialog(
-    const HistoryListType &history, const char *file = NULL);
-
-  /** Set the title of the dialog */
-  void SetTitle(const char *title)
-    {
-    m_Title = title;
-    m_Window->label(m_Title.c_str());
-    }
-
-  /** Set the text displayed above the filename box */
-  void SetFileBoxTitle(const char *title) 
-    {
-    m_FileBoxTitle = title;
-    m_InFile->label(m_FileBoxTitle.c_str());
-    }
-
-  /** Set the filename pattern (FLTK format) */
-  irisSetMacro(Pattern,const char *);
-
-  /** Get the file name currently in the box */
-  const char *GetFileName() { return m_InFile->value(); }
-
-  /** Set the command to call when the user clicks OK in the load dialog
-   * This command should fire an exception (any exception) if the load 
-   * fails, and then the dialog will remain open and the history list will
-   * not be updated */
-  template <class T> void SetLoadCallback(T *object, void (T::*member)())
-  {
-    typedef itk::SimpleMemberCommand<T> CommandType;
-    typename CommandType::Pointer cmd = CommandType::New();
-    cmd->SetCallbackFunction(object,member);
-    m_LoadCallback = cmd;
-  }
-
-  /** Set save callback. \see SetLoadCallback */
-  template <class T> void SetSaveCallback(T *object, void (T::*member)())
-  {
-    typedef itk::SimpleMemberCommand<T> CommandType;
-    typename CommandType::Pointer cmd = CommandType::New();
-    cmd->SetCallbackFunction(object,member);
-    m_SaveCallback = cmd;
-  }
-  
-  // User interface callbacks
-  void OnFileChange();
-  void OnHistoryChange();
-  void OnBrowseAction();
-  void OnOkAction();
-  void OnCancelAction();
- 
-private:
-
-  /** Common dialog config, regardless of save/load */
-  void DisplayDialog(const HistoryListType &history, const char *file);
-
-  // Whether we are in save or load mode
-  bool m_SaveMode;
-  
-  // Labels
-  StringType m_FileBoxTitle;
-  StringType m_HistoryBoxTitle;
-  StringType m_Pattern;
-  StringType m_Title;
-
-  // Callback commands
-  typedef itk::SmartPointer<itk::Command> CommandPointer;
-  CommandPointer m_SaveCallback;
-  CommandPointer m_LoadCallback;
-
-  // File chooser
-  Fl_Native_File_Chooser *m_FileChooser;
-
-};
-
-#endif // __SimpleFileDialogLogic_h_
diff --git a/UserInterface/MainComponents/SnakeParametersUI.fl b/UserInterface/MainComponents/SnakeParametersUI.fl
deleted file mode 100644
index 429d5bf..0000000
--- a/UserInterface/MainComponents/SnakeParametersUI.fl
+++ /dev/null
@@ -1,435 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0300 
-header_name {.h} 
-code_name {.cxx}
-class SnakeParametersUI {open : {private SnakeParametersUIBase}
-} {
-  Function {MakeWindow()} {open
-  } {
-    Fl_Window m_Window {
-      label {Snake Parameters} open selected
-      xywh {157 237 715 480} type Double box PLASTIC_DOWN_BOX
-      code0 {\#include "SnakeParametersUIBase.h"} non_modal visible
-    } {
-      Fl_Tabs m_TabsMode {open
-        xywh {5 5 350 360} box PLASTIC_UP_BOX color 60 labelfont 2 labelsize 12 align 0
-      } {
-        Fl_Group m_GrpEasy {
-          label {Intuitive Mode} open
-          xywh {5 25 350 340} color 22 selection_color 94 labelfont 2 labelsize 11
-        } {
-          Fl_Group m_GrpPropagationEasy {
-            label {Balloon force:} open
-            xywh {15 55 330 70} box PLASTIC_DOWN_BOX color 22 labelsize 12 align 5
-          } {
-            Fl_Group {} {open
-              xywh {55 90 245 35}
-            } {
-              Fl_Value_Slider m_InPropagationWeightEasy {
-                callback {o->take_focus();
-OnPropagationWeightChange(o);}
-                xywh {55 90 225 15} type Horizontal color 52 labelsize 12 align 4 minimum -3 maximum 3 step 0.1 value 1
-              }
-              Fl_Group {} {
-                label expanding open
-                xywh {250 110 50 15} labelsize 10 align 144
-              } {}
-              Fl_Group {} {
-                label contracting open
-                xywh {70 110 50 15} labelsize 10 align 16
-              } {}
-              Fl_Group {} {
-                label static open
-                xywh {160 110 50 15} labelsize 10 align 16
-              } {}
-              Fl_Group {} {
-                label {^} open
-                xywh {70 105 50 10} labelfont 1 labelsize 10 align 16
-              } {}
-              Fl_Group {} {
-                label {^} open
-                xywh {250 105 50 10} labelfont 1 labelsize 10 align 16
-              } {}
-              Fl_Group {} {
-                label {^} open
-                xywh {160 105 50 10} labelfont 1 labelsize 10 align 16
-              } {}
-            }
-            Fl_Button m_BtnEasyHelpPropagation {
-              label {More info...}
-              callback {this->ShowHelp("TutorialSectionIntroductionToAutomatic.html\#Propagation");}
-              xywh {274 61 65 21} box PLASTIC_UP_BOX color 180 labelsize 11
-            }
-          }
-          Fl_Group m_GrpCurvatureEasy {
-            label {Curvature force:} open
-            xywh {15 155 330 70} box PLASTIC_DOWN_BOX color 22 labelsize 12 align 5
-          } {
-            Fl_Group {} {
-              xywh {55 190 245 35}
-            } {
-              Fl_Value_Slider m_InCurvatureWeightEasy {
-                callback {o->take_focus();
-OnCurvatureWeightChange(o);}
-                xywh {55 190 225 15} type Horizontal color 52 labelsize 12 align 4 value 0.2
-              }
-              Fl_Group {} {
-                label spherical open
-                xywh {250 210 50 15} labelsize 10 align 144
-              } {}
-              Fl_Group {} {
-                label detailed open
-                xywh {70 210 50 15} labelsize 10 align 16
-              } {}
-              Fl_Group {} {
-                label smooth open
-                xywh {155 210 50 15} labelsize 10 align 16
-              } {}
-              Fl_Group {} {
-                label {^} open
-                xywh {70 205 50 10} labelfont 1 labelsize 10 align 16
-              } {}
-              Fl_Group {} {
-                label {^} open
-                xywh {250 205 50 10} labelfont 1 labelsize 10 align 16
-              } {}
-              Fl_Group {} {
-                label {^} open
-                xywh {155 205 50 10} labelfont 1 labelsize 10 align 16
-              } {}
-            }
-            Fl_Group {} {
-              label {Makes the boundary smoother and may help prevent leaking at corners and narrow places.}
-              xywh {20 160 245 25} labelsize 10 align 148
-            } {}
-            Fl_Button m_BtnEasyHelpCurvature {
-              label {More info...}
-              callback {this->ShowHelp("TutorialSectionIntroductionToAutomatic.html\#Curvature");}
-              xywh {274 161 65 20} box PLASTIC_UP_BOX color 180 labelsize 11
-            }
-          }
-          Fl_Group m_GrpAdvectionEasy {
-            label {Advection force:} open
-            xywh {15 255 330 70} box PLASTIC_DOWN_BOX color 22 labelsize 12 align 5
-          } {
-            Fl_Group {} {
-              xywh {55 290 250 35}
-            } {
-              Fl_Value_Slider m_InAdvectionWeightEasy {
-                callback {o->take_focus();
-OnAdvectionWeightChange(o);}
-                xywh {55 290 225 15} type Horizontal color 52 labelsize 12 align 4 maximum 5 value 0.7
-              }
-              Fl_Group {} {
-                label {large effect} open
-                xywh {245 310 60 15} labelsize 10 align 144
-              } {}
-              Fl_Group {} {
-                label {no effect} open
-                xywh {70 310 50 15} labelsize 10 align 16
-              } {}
-              Fl_Group {} {
-                label smooth open
-                xywh {155 310 50 15} labelsize 10 align 16 hide
-              } {}
-              Fl_Group {} {
-                label {^} open
-                xywh {70 305 50 10} labelfont 1 labelsize 10 align 16
-              } {}
-              Fl_Group {} {
-                label {^} open
-                xywh {250 305 50 10} labelfont 1 labelsize 10 align 16
-              } {}
-              Fl_Group {} {
-                label {^} open
-                xywh {155 305 50 10} labelfont 1 labelsize 10 align 16 hide
-              } {}
-            }
-            Fl_Group {} {
-              label {Pushes boundary back as it tries to cross edges, 
-causing the segmentation to converge.} open
-              xywh {20 260 260 25} labelsize 10 align 148
-            } {}
-            Fl_Button m_BtnEasyHelpAdvection {
-              label {More info...}
-              callback {this->ShowHelp("TutorialSectionIntroductionToAutomatic.html\#Advection");}
-              xywh {274 261 65 20} box PLASTIC_UP_BOX color 180 labelsize 11
-            }
-          }
-          Fl_Group {} {
-            label {Pushes the boundary inwards or outwards, propor-
-tionally to the preprocessed image intensity.} open
-            xywh {20 60 260 25} labelsize 10 align 148
-          } {}
-        }
-        Fl_Group m_GrpMath {
-          label {Mathematical Mode} open
-          xywh {5 25 350 320} color 22 selection_color 102 labelfont 2 labelsize 11 align 2 hide
-        } {
-          Fl_Group {} {
-            label {Front propagation equation:} open
-            xywh {20 55 330 60} labelsize 12 align 5
-          } {
-            Fl_Check_Button m_BtnAdvancedEquation {
-              label {Use experimental equation (advanced)}
-              callback {OnAdvancedEquationAction();}
-              xywh {110 90 235 15} down_box DOWN_BOX color 109 selection_color 32 labelsize 11
-            }
-            Fl_Wizard m_WizEquation {open
-              xywh {20 55 325 30}
-            } {
-              Fl_Group m_GrpEquationEdge {open
-                image {Artwork/formula01.gif} xywh {20 55 325 30} box BORDER_BOX color 7 align 16
-              } {}
-              Fl_Group m_GrpEquationRegion {open
-                image {Artwork/formula02.gif} xywh {20 55 325 30} box BORDER_BOX color 7 align 16 hide
-              } {}
-              Fl_Group m_GrpEquationExperimental {open
-                image {Artwork/formula03.gif} xywh {20 55 325 30} box BORDER_BOX color 7 align 16 hide
-              } {}
-            }
-          }
-          Fl_Group m_GrpCurvatureMath {
-            label {Curvature term:} open
-            xywh {20 210 325 40} box PLASTIC_DOWN_BOX color 22 labelsize 12 align 5
-          } {
-            Fl_Value_Input m_InCurvatureExponentMathText {
-              callback {OnCurvatureExponentChange(o);}
-              image {Artwork/rb.gif} xywh {235 220 30 20} labelsize 11 maximum 2 step 1 textsize 12 hide
-            }
-            Fl_Slider m_InCurvatureWeightMathSlider {
-              callback {o->take_focus();
-OnCurvatureWeightChange(o);}
-              xywh {145 220 110 20} type Horizontal step 0.01
-            }
-            Fl_Slider m_InCurvatureExponentMathSlider {
-              callback {OnCurvatureExponentChange(o);}
-              xywh {270 220 65 20} type Horizontal color 51 selection_color 60 maximum 3 step 1 hide
-            }
-            Fl_Value_Input m_InCurvatureWeightMathText {
-              label {beta:}
-              callback {OnCurvatureWeightChange(o);}
-              xywh {95 220 45 20} labelsize 12 maximum 5 step 0.01 textsize 12
-            }
-          }
-          Fl_Group m_GrpAdvectionMath {
-            label {Advection Term:} open
-            xywh {20 275 325 40} box PLASTIC_DOWN_BOX color 22 labelsize 12 align 5
-          } {
-            Fl_Value_Input m_InAdvectionWeightMathText {
-              label {gamma:}
-              callback {OnAdvectionWeightChange(o);}
-              xywh {95 285 45 20} labelsize 12 maximum 5 step 0.01 textsize 12
-            }
-            Fl_Value_Input m_InAdvectionExponentMathText {
-              callback {OnAdvectionExponentChange(o);}
-              image {Artwork/rc.gif} xywh {235 285 30 20} labelsize 11 maximum 2 step 1 textsize 12 hide
-            }
-            Fl_Slider m_InAdvectionWeightMathSlider {
-              callback {o->take_focus();
-OnAdvectionWeightChange(o);}
-              xywh {145 285 110 20} type Horizontal maximum 5 step 0.01
-            }
-            Fl_Slider m_InAdvectionExponentMathSlider {
-              callback {OnAdvectionExponentChange(o);}
-              xywh {270 285 65 20} type Horizontal color 51 selection_color 60 maximum 2 step 1 hide
-            }
-          }
-          Fl_Group m_GrpPropagationMath {
-            label {Propagation (baloon force) term:} open
-            xywh {20 145 325 40} box PLASTIC_DOWN_BOX color 22 selection_color 59 labelsize 12 align 5
-          } {
-            Fl_Value_Input m_InPropagationWeightMathText {
-              label {alpha:}
-              callback {OnPropagationWeightChange(o);}
-              xywh {95 155 45 20} labelsize 12 minimum -5 maximum 5 step 0.01 value 1 textsize 12
-            }
-            Fl_Slider m_InPropagationWeightMathSlider {
-              callback {o->take_focus();
-OnPropagationWeightChange(o);}
-              xywh {145 155 110 20} type Horizontal minimum -1 step 0.1 value 1
-            }
-            Fl_Value_Input m_InPropagationExponentMathText {
-              callback {OnPropagationExponentChange(o);}
-              image {Artwork/ra.gif} xywh {235 155 30 20} labelfont 2 labelsize 12 maximum 2 step 1 value 1 textsize 12 hide
-            }
-            Fl_Slider m_InPropagationExponentMathSlider {
-              callback {OnPropagationExponentChange(o);}
-              xywh {270 155 65 20} type Horizontal color 51 selection_color 60 maximum 2 step 1 value 1 hide
-            }
-          }
-        }
-        Fl_Group {} {
-          label {Advanced Settings} open
-          xywh {5 25 350 320} color 22 selection_color 210 labelfont 2 labelsize 11 hide
-        } {
-          Fl_Group m_GrpTimeStep {
-            label {Time step computation:} open
-            xywh {20 185 320 100} box PLASTIC_DOWN_BOX color 22 selection_color 245 labelsize 12 align 5
-          } {
-            Fl_Value_Slider m_InTimeStep {
-              label {Speed-up factor:}
-              callback {o->take_focus();
-OnTimeStepChange(o);}
-              tooltip {Specify how much faster the snake evolution should be performed} xywh {185 230 145 20} type Horizontal labelsize 11 align 4 minimum 1 maximum 10 step 0.25 value 2 textsize 11 deactivate
-            }
-            Fl_Round_Button {m_BtnTimeStepAuto[0]} {
-              callback {this->OnTimeStepAutoAction();}
-              xywh {30 190 260 20} type Radio down_box ROUND_DOWN_BOX value 1
-            }
-            Fl_Round_Button {m_BtnTimeStepAuto[1]} {
-              callback {this->OnTimeStepAutoAction();}
-              xywh {30 210 150 20} type Radio down_box ROUND_DOWN_BOX
-            }
-            Fl_Group {} {
-              label {Automatically compute optimal time step} open
-              xywh {45 190 200 20} labelsize 11 align 20
-            } {}
-            Fl_Group {} {
-              label {Override optimal time step (faster but less robust):}
-              callback {this->OnTimeStepAutoAction();} open
-              xywh {45 210 285 20} labelsize 11 align 20
-            } {}
-            Fl_Value_Slider m_InSmoothingWeight {
-              label {Noise reduction:}
-              callback {o->take_focus();
-OnSmoothingWeightChange(o);}
-              tooltip {Experimental feature: additional smoothing of the snake} xywh {185 255 145 20} type Horizontal labelsize 11 align 4 value 0.1 textsize 11 deactivate
-            }
-          }
-          Fl_Group {} {
-            label {Algorithm configuration:} open
-            xywh {20 55 320 110} box PLASTIC_DOWN_BOX color 22 labelsize 12 align 5
-          } {
-            Fl_Choice m_InSolver {
-              label {Use algorithm:}
-              callback {OnSolverChange();} open
-              xywh {105 65 225 20} down_box BORDER_BOX labelsize 11 textsize 11
-            } {
-              MenuItem {} {
-                label {ITK Sparse Field Level Set Algorithm}
-                xywh {0 0 100 20} labelsize 11
-              }
-              MenuItem {} {
-                label {ITK Narrow Band Level Set Algorithm}
-                xywh {10 10 100 20} labelsize 11
-              }
-              MenuItem {} {
-                label {ITK Dense Level Set Algorithm}
-                xywh {20 20 100 20} labelsize 11
-              }
-              MenuItem {} {
-                label {SNAP Original Algorithm}
-                xywh {30 30 100 20} labelsize 11 hide
-              }
-            }
-            Fl_Wizard m_WizSolverOptions {
-              label {Options:} open
-              xywh {35 105 295 50} box THIN_UP_FRAME color 245 labelsize 11 align 5
-            } {
-              Fl_Group m_GrpSparseSolverOptions {open
-                xywh {35 105 290 50}
-              } {}
-              Fl_Group m_GrpNarrowSolverOptions {open
-                xywh {35 105 290 50} hide
-              } {}
-              Fl_Group m_GrpLegacySolverOptions {open
-                xywh {35 105 295 50} hide
-              } {
-                Fl_Check_Button m_ChkLegacyClamp {
-                  label {Clamp to ground (faster, less accurate)}
-                  callback {OnLegacyClampChange(o);}
-                  xywh {45 110 270 15} down_box DOWN_BOX value 1 labelsize 11
-                }
-                Fl_Value_Slider m_InLegacyGround {
-                  label {'Ground' value:}
-                  callback {OnLegacyGroundChange(o);}
-                  xywh {190 130 130 15} type Horizontal labelsize 11 align 4 maximum 5 step 0.1 value 2
-                }
-              }
-            }
-          }
-        }
-      }
-      Fl_Button m_BtnClose {
-        label Cancel
-        callback {this->OnCloseAction();}
-        xywh {405 445 64 25} box PLASTIC_UP_BOX shortcut 0xff1b color 180 labelsize 12
-      }
-      Fl_Button m_BtnHelp {
-        label {&Help!}
-        callback {this->OnHelpAction();}
-        xywh {330 445 64 25} box PLASTIC_UP_BOX shortcut 0x80068 color 180 labelsize 12
-      }
-      Fl_Button m_BtnAccept {
-        label {&Accept}
-        callback {this->OnOkAction();}
-        xywh {255 445 64 25} box PLASTIC_UP_BOX shortcut 0x80061 color 180 labelfont 1 labelsize 12
-      }
-      Fl_Group {} {
-        label {Conceptual illustration of the forces in 2D:} open
-        xywh {365 25 345 405} box PLASTIC_UP_BOX color 22 labelfont 2 labelsize 12
-      } {
-        Fl_Group {} {
-          label {Curvature force} open
-          xywh {540 46 164 164} box FLAT_BOX color 0 labelsize 12
-        } {
-          Fl_Box {m_BoxPreview[1]} {
-            xywh {542 48 160 160} box FLAT_BOX color 27 labelsize 10
-            code0 {\#include "SnakeParametersPreviewBox.h"}
-            class SnakeParametersPreviewBox
-          }
-        }
-        Fl_Group {} {
-          label {Advection force} open
-          xywh {370 231 164 164} box FLAT_BOX color 0 labelsize 12
-        } {
-          Fl_Box {m_BoxPreview[2]} {
-            xywh {372 233 160 160} box FLAT_BOX color 27 labelsize 10
-            code0 {\#include "SnakeParametersPreviewBox.h"}
-            class SnakeParametersPreviewBox
-          }
-        }
-        Fl_Group {} {
-          label {Combined force} open
-          xywh {540 231 164 164} box FLAT_BOX color 0 labelsize 12
-        } {
-          Fl_Box {m_BoxPreview[3]} {
-            xywh {542 233 160 160} box FLAT_BOX color 27 labelsize 10
-            code0 {\#include "SnakeParametersPreviewBox.h"}
-            class SnakeParametersPreviewBox
-          }
-        }
-        Fl_Group {} {
-          label {Balloon force} open
-          xywh {370 46 164 164} box FLAT_BOX color 0 labelsize 12
-        } {
-          Fl_Box {m_BoxPreview[0]} {
-            xywh {372 48 160 160} box FLAT_BOX color 27 labelsize 10
-            code0 {\#include "SnakeParametersPreviewBox.h"}
-            class SnakeParametersPreviewBox
-          }
-        }
-        Fl_Check_Button m_BtnAnimate {
-          label {Show animated 2D segmentation preview}
-          callback {this->OnAnimateAction();}
-          xywh {485 405 220 20} down_box DOWN_BOX labelsize 11
-        }
-      }
-      Fl_Group {} {open
-        xywh {5 375 350 55} box PLASTIC_UP_BOX color 22
-      } {
-        Fl_Button m_BtnLoadParameters {
-          label {&Load Parameters...}
-          callback {this->OnLoadParametersAction();}
-          xywh {65 390 105 25} box PLASTIC_UP_BOX shortcut 0x8006c color 180 labelsize 11
-        }
-        Fl_Button m_BtnSaveParameters {
-          label {&Save Parameters...}
-          callback {this->OnSaveParametersAction();}
-          xywh {185 390 105 25} box PLASTIC_UP_BOX shortcut 0x80073 color 180 labelsize 11
-        }
-      }
-    }
-  }
-} 
diff --git a/UserInterface/MainComponents/SnakeParametersUIBase.h b/UserInterface/MainComponents/SnakeParametersUIBase.h
deleted file mode 100644
index 16875d3..0000000
--- a/UserInterface/MainComponents/SnakeParametersUIBase.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SnakeParametersUIBase.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:18 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SnakeParametersUIBase_h_
-#define __SnakeParametersUIBase_h_
-
-class Fl_Valuator;
-class Fl_Check_Button;
-
-/**
- * \class SnakeParametersUIBase
- * \brief Base class for the parameter setting user interface.
- */
-class SnakeParametersUIBase 
-{
-public:
-  virtual ~SnakeParametersUIBase() {}
-  virtual void OnAdvectionExponentChange(Fl_Valuator *input) = 0;
-  virtual void OnAdvectionWeightChange(Fl_Valuator *input) = 0;
-  virtual void OnCurvatureExponentChange(Fl_Valuator *input) = 0;
-  virtual void OnCurvatureWeightChange(Fl_Valuator *input) = 0;
-  virtual void OnPropagationExponentChange(Fl_Valuator *input) = 0;
-  virtual void OnPropagationWeightChange(Fl_Valuator *input) = 0;
-  virtual void OnHelpAction() = 0 ;
-  virtual void OnOkAction() = 0;
-  virtual void OnCloseAction() = 0;
-  virtual void OnSaveParametersAction() = 0;
-  virtual void OnLoadParametersAction() = 0;
-  virtual void OnAdvancedEquationAction() = 0;  
-
-  // Advanced page
-  virtual void OnTimeStepAutoAction() = 0;
-  virtual void OnTimeStepChange(Fl_Valuator *input) = 0;
-  virtual void OnSmoothingWeightChange(Fl_Valuator *input) = 0;
-  virtual void OnLegacyClampChange(Fl_Check_Button *input) = 0;
-  virtual void OnLegacyGroundChange(Fl_Valuator *input) = 0;
-  virtual void OnSolverChange() = 0;
-
-  // Force example
-  virtual void OnAnimateAction() = 0;
-
-  // Help System
-  virtual void ShowHelp(const char *link) = 0;
-};
-
-#endif // __SnakeParametersUIBase_h_
diff --git a/UserInterface/MainComponents/SnakeParametersUILogic.cxx b/UserInterface/MainComponents/SnakeParametersUILogic.cxx
deleted file mode 100644
index 6a57ee5..0000000
--- a/UserInterface/MainComponents/SnakeParametersUILogic.cxx
+++ /dev/null
@@ -1,751 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SnakeParametersUILogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/19 19:15:14 $
-  Version:   $Revision: 1.10 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-// Borland compiler is very lazy so we need to instantiate the template
-//  by hand 
-#if defined(__BORLANDC__)
-#include "SNAPBorlandDummyTypes.h"
-#endif
-
-#include "SnakeParametersUILogic.h"
-#include "FL/fl_ask.H"
-
-#include "itkEventObject.h" 
-#include "itkOrientedImage.h"
-#include "itkImageFileReader.h"
-#include "itkImageRegionIterator.h"
-#include "itkShiftScaleImageFilter.h"
-#include "itkPNGImageIO.h"
-#include "itkRGBPixel.h"
-#include "GlobalState.h"
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-#include "SNAPImageData.h"
-#include "SNAPRegistryIO.h"
-#include "SimpleFileDialogLogic.h"
-#include "SnakeParametersPreviewPipeline.h"
-#include "SystemInterface.h"
-#include "ThresholdSettings.h"
-#include "UserInterfaceBase.h"
-
-
-void 
-SnakeParametersUILogic
-::OnAdvectionExponentChange(Fl_Valuator *input)
-{
-  int clamped = (int) input->clamp(input->value());
-  m_Parameters.SetAdvectionSpeedExponent(clamped);
-  this->OnParameterUpdate();
-}
-
-void 
-SnakeParametersUILogic
-::OnAdvectionWeightChange(Fl_Valuator *input)
-{
-  m_Parameters.SetAdvectionWeight(input->value());
-  this->OnParameterUpdate();
-}
-
-void 
-SnakeParametersUILogic
-::OnCurvatureExponentChange(Fl_Valuator *input)
-{
-  int clamped = (int) input->clamp(input->value());
-  m_Parameters.SetCurvatureSpeedExponent(clamped - 1);
-  this->OnParameterUpdate();
-}
-
-void 
-SnakeParametersUILogic
-::OnCurvatureWeightChange(Fl_Valuator *input)
-{
-  m_Parameters.SetCurvatureWeight(input->value());
-  this->OnParameterUpdate();
-}
-
-void 
-SnakeParametersUILogic
-::OnPropagationExponentChange(Fl_Valuator *input)
-{
-  int clamped = (int) input->clamp(input->value());
-  m_Parameters.SetPropagationSpeedExponent(clamped);
-  this->OnParameterUpdate();
-}
-
-void 
-SnakeParametersUILogic
-::OnPropagationWeightChange(Fl_Valuator *input)
-{
-  m_Parameters.SetPropagationWeight(input->value());
-  this->OnParameterUpdate();
-}
-
-void 
-SnakeParametersUILogic
-::OnTimeStepChange(Fl_Valuator *input)
-{
-  m_Parameters.SetTimeStepFactor(input->value());
-  this->OnParameterUpdate();
-}
-
-void 
-SnakeParametersUILogic
-::OnSmoothingWeightChange(Fl_Valuator *input)
-{
-  m_Parameters.SetLaplacianWeight(input->value());
-  this->OnParameterUpdate();
-}
-
-void 
-SnakeParametersUILogic
-::OnLegacyClampChange(Fl_Check_Button *input)
-{
-  m_Parameters.SetClamp(input->value() > 0);
-  this->OnParameterUpdate();
-}
-
-void 
-SnakeParametersUILogic
-::OnLegacyGroundChange(Fl_Valuator *input)
-{ 
-  m_Parameters.SetGround(input->value());
-  this->OnParameterUpdate();
-}
-
-void 
-SnakeParametersUILogic
-::OnSolverChange()
-{
-  if(m_WarnOnSolverUpdate) 
-    {
-    int rc = 
-      fl_choice("Changing the algorithm while level set evolution is running\n"
-                "will cause the results to be lost!  Are you sure?",
-                "Yes, change it","No",NULL);
-    if(rc == 1) 
-      {
-      this->OnParameterUpdate();
-      return;
-      }      
-    }
-
-  SnakeParameters::SolverType solver;
-  switch(m_InSolver->value()) 
-    {
-    case 0: solver = SnakeParameters::PARALLEL_SPARSE_FIELD_SOLVER; break;
-    case 1: solver = SnakeParameters::NARROW_BAND_SOLVER; break;
-    case 2: solver = SnakeParameters::DENSE_SOLVER; break;
-    case 3: solver = SnakeParameters::LEGACY_SOLVER; break;
-    default: solver = SnakeParameters::PARALLEL_SPARSE_FIELD_SOLVER;
-    }
-
-  if(solver != SnakeParameters::LEGACY_SOLVER)
-    m_Parameters.SetAutomaticTimeStep(true);
-
-  m_Parameters.SetSolver(solver);
-  this->OnParameterUpdate();
-}
-
-void
-SnakeParametersUILogic
-::OnTimeStepAutoAction()
-{
-  m_Parameters.SetAutomaticTimeStep(m_BtnTimeStepAuto[0]->value() == 1);
-  this->OnParameterUpdate();
-}
-
-void 
-SnakeParametersUILogic
-::OnAdvancedEquationAction()
-{
-  // Just call the parameters update method
-  this->OnParameterUpdate();
-}
-
-void SnakeParametersUILogic
-::OnParameterUpdate()
-{
-  // Propagate the values of the parameters to all the controls in 
-  // this user interface
-
-  // Activate or disactivate widgets based on the snake type
-  if(m_Parameters.GetSnakeType() == SnakeParameters::EDGE_SNAKE)
-    {
-    m_GrpAdvectionEasy->show();
-    m_GrpAdvectionMath->show();
-
-    m_InAdvectionWeightMathText->show();
-    m_InAdvectionExponentMathText->show();
-    m_InCurvatureExponentMathText->show();
-    m_InPropagationExponentMathText->show();
-
-    m_InAdvectionWeightMathSlider->show();
-    m_InAdvectionExponentMathSlider->show();
-    m_InCurvatureExponentMathSlider->show();
-    m_InPropagationExponentMathSlider->show();
-    }
-  else
-    {
-    m_GrpAdvectionEasy->hide();
-    m_GrpAdvectionMath->hide();
-
-    m_InAdvectionWeightMathText->hide();
-    m_InAdvectionExponentMathText->hide();
-    m_InCurvatureExponentMathText->hide();
-    m_InPropagationExponentMathText->hide();
-
-    m_InAdvectionWeightMathSlider->hide();
-    m_InAdvectionExponentMathSlider->hide();
-    m_InCurvatureExponentMathSlider->hide();
-    m_InPropagationExponentMathSlider->hide();
-    }
-
-  // Curvature weight
-  float value = m_Parameters.GetCurvatureWeight();
-  m_InCurvatureWeightMathText->value(value);
-  m_InCurvatureWeightMathSlider->value(value);
-  m_InCurvatureWeightEasy->value(value);
-
-  // Curvature exponent
-  value = m_Parameters.GetCurvatureSpeedExponent() + 1;
-  m_InCurvatureExponentMathText->value(value);
-  m_InCurvatureExponentMathSlider->value(value);
-  //m_InCurvatureExponentEasy->value(value);
-  
-  // Propagation weight 
-  value = m_Parameters.GetPropagationWeight();
-  m_InPropagationWeightMathText->value(value);
-  m_InPropagationWeightMathSlider->value(value);
-  //m_InPropagationWeightEasy->value(value);
-  
-  // Propagation exponent 
-  value = m_Parameters.GetPropagationSpeedExponent();
-  m_InPropagationExponentMathText->value(value);
-  m_InPropagationExponentMathSlider->value(value);
-  //m_InPropagationExponentEasy->value(value);
-  
-  // Advection weight 
-  value = m_Parameters.GetAdvectionWeight();
-  m_InAdvectionWeightMathText->value(value);
-  m_InAdvectionWeightMathSlider->value(value);
-  m_InAdvectionWeightEasy->value(value);
-  
-  // Advection exponent 
-  value = m_Parameters.GetAdvectionSpeedExponent();
-  m_InAdvectionExponentMathText->value(value);
-  m_InAdvectionExponentMathSlider->value(value);
-  //m_InAdvectionExponentEasy->value(value);
-
-  // Experimental / normal equation display
-  if(m_BtnAdvancedEquation->value() > 0)
-    {
-    // Show the right equation
-    m_WizEquation->value(m_GrpEquationExperimental);
-
-    // Enable all the controls
-    m_InAdvectionExponentMathText->show();
-    m_InAdvectionExponentMathSlider->show();
-    m_InCurvatureExponentMathText->show();
-    m_InCurvatureExponentMathSlider->show();
-    m_InPropagationExponentMathText->show();    
-    m_InPropagationExponentMathSlider->show();    
-    m_GrpAdvectionEasy->show();
-    }
-  else
-    {
-    m_InAdvectionExponentMathText->hide();
-    m_InAdvectionExponentMathSlider->hide();
-    m_InCurvatureExponentMathText->hide();
-    m_InCurvatureExponentMathSlider->hide();
-    m_InPropagationExponentMathText->hide();    
-    m_InPropagationExponentMathSlider->hide();    
-    
-    if(m_Parameters.GetSnakeType() == SnakeParameters::EDGE_SNAKE)
-      {
-      // Show the right equation
-      m_WizEquation->value(m_GrpEquationEdge);
-
-      m_GrpAdvectionEasy->show();
-      m_GrpAdvectionMath->show();
-      }
-    else
-      {
-      // Show the right equation
-      m_WizEquation->value(m_GrpEquationRegion);
-
-      m_GrpAdvectionEasy->hide();
-      m_GrpAdvectionMath->hide();
-      }
-    }
-
-  // Update the display in the 2D preview boxes
-  if(m_Parameters.GetSnakeType() == SnakeParameters::EDGE_SNAKE)
-    m_PreviewPipeline->SetSpeedImage(m_ExampleImage[0]);
-  else
-    m_PreviewPipeline->SetSpeedImage(m_ExampleImage[1]);
-  
-  // Pass the parameters to the pipeline
-  m_PreviewPipeline->SetSnakeParameters(m_Parameters);
-    
-  // Advanced page : solver
-  if(m_Parameters.GetSolver() == SnakeParameters::LEGACY_SOLVER) 
-    {
-    // Show the right solver
-    m_InSolver->value(2);
-
-    // Show the options page
-    m_WizSolverOptions->value(m_GrpLegacySolverOptions);
-
-    // Fill the option page controls
-    m_ChkLegacyClamp->value(m_Parameters.GetClamp() ? 1 : 0);
-    m_InLegacyGround->value(m_Parameters.GetGround());
-
-    // Disable the automatic timestep selection
-    m_Parameters.SetAutomaticTimeStep(false);
-    m_BtnTimeStepAuto[0]->deactivate();
-    }
-  else
-    {
-    if(m_Parameters.GetSolver() == SnakeParameters::NARROW_BAND_SOLVER)
-      {
-      // Show the right solver
-      m_InSolver->value(1);
-
-      // Show the options page
-      m_WizSolverOptions->value(m_GrpNarrowSolverOptions);
-      }
-    else if(m_Parameters.GetSolver() == SnakeParameters::DENSE_SOLVER)
-      {
-      // Show the right solver
-      m_InSolver->value(2);
-
-      // Show the options page
-      m_WizSolverOptions->value(m_GrpNarrowSolverOptions);
-      }
-    else
-      {
-      // Show the right solver
-      m_InSolver->value(0);
-
-      // Show the options page
-      m_WizSolverOptions->value(m_GrpSparseSolverOptions);
-      }
-
-    // Enable the automatic timestep selection
-    m_BtnTimeStepAuto[0]->activate();
-    }
-
-  // Advanced page : time step
-  if(m_Parameters.GetAutomaticTimeStep())
-    {
-    m_BtnTimeStepAuto[0]->setonly();
-    m_InTimeStep->deactivate();
-    m_Parameters.SetLaplacianWeight(0);
-    m_InSmoothingWeight->deactivate();
-    }
-  else
-    {
-    m_BtnTimeStepAuto[1]->setonly();
-    m_InTimeStep->activate();
-    m_InSmoothingWeight->activate();
-    }
-
-  m_InTimeStep->value(m_Parameters.GetTimeStepFactor());
-  m_InSmoothingWeight->value(m_Parameters.GetLaplacianWeight());
-
-  // Update the parameter display windows
-  RedrawAllBoxes();
-}
-
-void 
-SnakeParametersUILogic
-::RedrawAllBoxes()
-{
-  m_BoxPreview[0]->redraw();
-  m_BoxPreview[1]->redraw();
-  m_BoxPreview[2]->redraw();
-  m_BoxPreview[3]->redraw();
-}
-
-
-
-void 
-SnakeParametersUILogic
-::OnHelpAction()
-{
-
-}
-
-void SnakeParametersUILogic
-::CloseWindow()
-{
-  // Close the window
-  m_Window->hide();
-}
-
-void SnakeParametersUILogic
-::OnOkAction()
-{
-  m_UserAccepted = true;
-  CloseWindow();
-}
-
-void SnakeParametersUILogic
-::OnCloseAction()
-{
-  m_UserAccepted = false;
-  CloseWindow();
-}
-
-void SnakeParametersUILogic
-::OnSaveParametersAction()
-{
-  // Show the save dialog using the correct history
-  m_IODialog->SetTitle("Save Snake Parameters");
-  m_IODialog->DisplaySaveDialog(
-    m_SystemInterface->GetHistory("SnakeParameters"),NULL);
-}
-
-void SnakeParametersUILogic
-::SaveParametersCallback()
-{
-  // Get the selected file name
-  const char *file = m_IODialog->GetFileName();
-
-  try 
-    {
-    // Create a registry for the file
-    Registry regParameters;
-
-    // Use a registry IO object to put the parameters into a registry
-    SNAPRegistryIO().WriteSnakeParameters(m_Parameters,regParameters);
-
-    // Write the registry to file
-    regParameters.WriteToFile(file,"# ITK-SNAP Snake Parameters File");
-    
-    // Add the filename to the history
-    m_SystemInterface->UpdateHistory("SnakeParameters",file);
-    }
-  catch(...)
-    {
-    fl_alert("Unable to write to file %s!",file);  
-    throw;
-    }
-}
-
-void SnakeParametersUILogic
-::OnLoadParametersAction()
-{
-  // Show the save dialog using the correct history
-  m_IODialog->SetTitle("Load Snake Parameters");
-  m_IODialog->DisplayLoadDialog(
-    m_SystemInterface->GetHistory("SnakeParameters"),NULL);
-}
-
-void SnakeParametersUILogic
-::LoadParametersCallback()
-{
-  // Get the selected file name
-  const char *file = m_IODialog->GetFileName();
-  SnakeParameters parameters;
-
-  try 
-    {
-    // Read a registry from the indicated file
-    Registry regParameters(file);
-
-    // Read the parameters from the registry
-    parameters = 
-      SNAPRegistryIO().ReadSnakeParameters(regParameters,m_Parameters);
-    }
-  catch(...)
-    {
-    fl_alert("Unable to load parameters from file %s!",file);  
-    throw;
-    }
-
-  // Make sure the parameters are of valid type
-  if(parameters.GetSnakeType() != m_Parameters.GetSnakeType())
-    {
-    int rc = 0;
-    if(m_Parameters.GetSnakeType() == SnakeParameters::EDGE_SNAKE)
-      {
-      rc = fl_choice(
-        "Warning!  The snake evolution parameters in the file are for the\n"
-        "REGION COMPETITION mode.  ITK-SNAP is currently in EDGE STOPPING mode.\n"
-        "Do you wish to load the parameters anyway?",
-        "Yes", "No", NULL);
-      }
-    else
-      {
-      rc = fl_choice(
-        "Warning!  The snake evolution parameters in the file are for the\n"
-        "EDGE STOPPING mode.  ITK-SNAP is currently in REGION COMPETITION mode.\n"
-        "Do you wish to load the parameters anyway?",
-        "Yes", "No", NULL);
-      }
-
-    // Show the message
-    if(rc == 1) throw rc;
-
-    // If region competition, drop the advection stuff
-    if(m_Parameters.GetSnakeType() == SnakeParameters::REGION_SNAKE)
-      {
-      parameters.SetAdvectionSpeedExponent(0);
-      parameters.SetAdvectionWeight(0);
-      parameters.SetCurvatureSpeedExponent(-1);
-      }
-
-    // Keep the mode
-    parameters.SetSnakeType(m_Parameters.GetSnakeType());
-    }
-
-  // Set the parameters
-  SetParameters(parameters);
-
-  // Add the filename to the history
-  m_SystemInterface->UpdateHistory("SnakeParameters",file);
-}
-
-void SnakeParametersUILogic
-::SetParameters(const SnakeParameters &parms)
-{
-  // Set the parameters
-  m_Parameters = parms;
-
-   // Update the user interface controls
-  OnParameterUpdate();
-}
-
-void SnakeParametersUILogic
-::Register(UserInterfaceBase *parent)
-{
-  // Get the parent's system object
-  m_ParentUI = parent;
-  m_SystemInterface = parent->GetSystemInterface();
-  
-  // Get the edge and region example image file names
-  string fnImage[2];
-  fnImage[0] = 
-    m_SystemInterface->GetFileInRootDirectory("Images2D/EdgeForcesExample.png");
-  fnImage[1] = 
-    m_SystemInterface->GetFileInRootDirectory("Images2D/RegionForcesExample.png");
-
-  // Typedefs
-  typedef itk::ImageFileReader<ExampleImageType> ReaderType;
-  typedef itk::ImageRegionIterator<ExampleImageType> IteratorType;
-  typedef itk::ShiftScaleImageFilter<ExampleImageType, ExampleImageType> ScaleShiftType;
-
-  // Initialize the pipeline
-  m_PreviewPipeline = new SnakeParametersPreviewPipeline(
-    m_ParentUI->GetDriver()->GetGlobalState());
-
-  // Load each of these images
-  static const float scale_factor[] = { 1.0f / 255.0f, -2.0f / 255.0f };
-  static const float shift_factor[] = { 0.0f, -127.5f };
-
-  for(unsigned int i = 0; i < 2; i++) 
-    {
-    try 
-      {
-      // Read the image in
-      ReaderType::Pointer reader = ReaderType::New();
-      reader->SetFileName(fnImage[i].c_str());
-
-      ScaleShiftType::Pointer scaler = ScaleShiftType::New();
-      scaler->SetScale(scale_factor[i]);
-      scaler->SetShift(shift_factor[i]);
-      scaler->SetInput(reader->GetOutput());
-
-      scaler->Update();
-
-      // Allocate the example image
-      m_ExampleImage[i] = scaler->GetOutput();
-      }
-    catch(itk::ExceptionObject &exc)
-      {
-      // An exception occurred.  
-      fl_alert("Unable to load image %s\n"
-               "Exception %s\n"
-               "Force illustration example will not be available.", 
-               exc.GetDescription(), fnImage[i].c_str());
-
-      // Initialize an image to zeros
-      m_ExampleImage[i] = NULL;
-      }
-    }
-
-  // Load the points from the registry
-  std::vector<Vector2d> points;
-  string fnPreset = m_SystemInterface->GetFileInRootDirectory(
-      "Presets/SnakeParameterPreviewCurve.txt");
-  try 
-    {
-    Registry regPoints(fnPreset.c_str());
-    points = regPoints.Folder("Points").GetArray(Vector2d(0.0));
-    }
-  catch(...)
-    {
-    // An exception occurred.  
-    fl_alert("Unable to load file %s\n"
-             "Force illustration example will not be available.",
-             fnPreset.c_str());
-    }
-  
-  // Assign our previewer to the preview windows
-  for(unsigned int i=0;i<4;i++)
-    {
-    m_BoxPreview[i]->SetParentUI(this);
-    m_BoxPreview[i]->SetPipeline(m_PreviewPipeline);
-    }
-  
-  // If there are some points in there, draw them
-  if(points.size() >= 4)
-    {
-    // Set spline points, etc
-    m_PreviewPipeline->SetControlPoints(points);
-
-    // Set which forces to display
-    m_BoxPreview[0]->SetForceToDisplay(SnakeParametersPreviewBox::PROPAGATION_FORCE);
-    m_BoxPreview[1]->SetForceToDisplay(SnakeParametersPreviewBox::CURVATURE_FORCE);
-    m_BoxPreview[2]->SetForceToDisplay(SnakeParametersPreviewBox::ADVECTION_FORCE);
-    m_BoxPreview[3]->SetForceToDisplay(SnakeParametersPreviewBox::TOTAL_FORCE);
-    }
-
-  // Don't warn by default
-  m_WarnOnSolverUpdate = false;
-}
-
-void 
-SnakeParametersUILogic
-::DisplayWindow()
-{
-  // Show everything
-  m_Window->show();
-  for(unsigned int j=0;j<4;j++) 
-    {
-    m_BoxPreview[j]->show();
-    }
-
-  // Update parameters
-  OnParameterUpdate();
-}
-
-SnakeParametersUILogic
-::SnakeParametersUILogic()
-  : SnakeParametersUI()
-{
-  // Clear the pipeline
-  m_PreviewPipeline = NULL;
-
-  // Create the parameter IO dialog window
-  m_IODialog = new SimpleFileDialogLogic;
-  m_IODialog->MakeWindow();
-  m_IODialog->SetFileBoxTitle("Snake Parameters File:");
-  m_IODialog->SetPattern("Text files\t*.txt");
-  m_IODialog->SetLoadCallback(
-    this,&SnakeParametersUILogic::LoadParametersCallback);
-  m_IODialog->SetSaveCallback(
-    this,&SnakeParametersUILogic::SaveParametersCallback);
-}
-
-SnakeParametersUILogic
-::~SnakeParametersUILogic()
-{
-  if(m_PreviewPipeline)
-    delete m_PreviewPipeline;
-  delete m_IODialog;
-}
-
-void 
-SnakeParametersUILogic
-::ShowHelp(const char *link)
-{
-  m_ParentUI->ShowHTMLPage(link);
-}
-
-void
-SnakeParametersUILogic
-::OnAnimateAction()
-{
-  // Remove a timeout callback if it exists
-  Fl::remove_timeout(SnakeParametersUILogic::OnTimerCallback, this);
-  m_PreviewPipeline->SetDemoLoopRunning(false);
-
-  // If the button value is one, add the timeout
-  if(m_BtnAnimate->value())
-    {
-    Fl::add_timeout(0.2, SnakeParametersUILogic::OnTimerCallback, this);
-    m_PreviewPipeline->SetDemoLoopRunning(true);
-    }
-  else
-    {
-    RedrawAllBoxes();
-    }
-}
-
-void 
-SnakeParametersUILogic
-::OnTimerCallback(void *cbdata)
-{
-  // Get the object that this refers to
-  SnakeParametersUILogic *self = 
-    reinterpret_cast<SnakeParametersUILogic *>(cbdata);
-
-  // If the window is not visible, there is nothing to do
-  if(!self->m_Window->visible())
-    {
-    self->m_PreviewPipeline->SetDemoLoopRunning(false);
-    self->m_BtnAnimate->value(0);
-    }
-  else
-    {
-    // Call the pipeline's animation method
-    self->m_PreviewPipeline->AnimationCallback();
-
-    // Redraw all the windows
-    self->RedrawAllBoxes();
-
-    // Schedule another run
-    Fl::repeat_timeout(0.05, SnakeParametersUILogic::OnTimerCallback, self);
-    }
-}
-
-void 
-SnakeParametersUILogic
-::OnSpeedColorMapUpdate()
-{
-  if(m_Window->visible())
-    RedrawAllBoxes();
-}
diff --git a/UserInterface/MainComponents/SnakeParametersUILogic.h b/UserInterface/MainComponents/SnakeParametersUILogic.h
deleted file mode 100644
index 20aef95..0000000
--- a/UserInterface/MainComponents/SnakeParametersUILogic.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SnakeParametersUILogic.h,v $
-  Language:  C++
-  Date:      $Date: 2009/01/23 20:09:38 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SnakeParametersUILogic_h_
-#define __SnakeParametersUILogic_h_
-
-#include "SnakeParametersUI.h"
-#include "SNAPCommonUI.h"
-#include "SnakeParameters.h"
-#include "itkSmartPointer.h"
-
-// Forward references to application classes
-class GlobalState;
-class IRISApplication;
-class UserInterfaceBase;
-class SnakeParametersPreviewPipeline;
-class SimpleFileDialogLogic;
-class SystemInterface;
-
-// ITK forward references
-namespace itk {
-  template<class TPixel, unsigned int VDimension> class OrientedImage;
-  template<class TObject> class SimpleMemberCommand;
-}
-
-/**
- * \class SnakeParametersUILogic
- * \brief Logic for the preprocessing UI.
- */
-class SnakeParametersUILogic : public SnakeParametersUI
-{
-public:
-  SnakeParametersUILogic();
-  virtual ~SnakeParametersUILogic();
-  
-  /** Register with the parent object (required for examples to work) */
-  void Register(UserInterfaceBase *parent);
-
-  /** Initialize the internal snake parameters with external value */
-  void SetParameters(const SnakeParameters &parms);
-
-  /** Show the window */
-  void DisplayWindow();
-
-  /** Get the internal snake parameters */
-  irisGetMacro(Parameters,SnakeParameters);
-
-  /** Find out whether the user accepted the parameters or not */
-  irisGetMacro(UserAccepted,bool);
-
-  /** Provide access to the window */
-  irisGetMacro(Window,Fl_Window *);
-
-  /** This dialog can warn the user about changing solvers */
-  irisSetMacro(WarnOnSolverUpdate,bool);
-  irisGetMacro(WarnOnSolverUpdate,bool);
-
-  void OnAdvectionExponentChange(Fl_Valuator *input); 
-  void OnAdvectionWeightChange(Fl_Valuator *input); 
-  void OnCurvatureExponentChange(Fl_Valuator *input); 
-  void OnCurvatureWeightChange(Fl_Valuator *input); 
-  void OnPropagationExponentChange(Fl_Valuator *input); 
-  void OnPropagationWeightChange(Fl_Valuator *input); 
-  void OnHelpAction(); 
-  void OnOkAction(); 
-  void OnCloseAction(); 
-  void OnSaveParametersAction();
-  void OnLoadParametersAction();
-  void OnAdvancedEquationAction();
-
-  // Advanced page
-  void OnTimeStepAutoAction();
-  void OnTimeStepChange(Fl_Valuator *input);
-  void OnSmoothingWeightChange(Fl_Valuator *input);
-  void OnLegacyClampChange(Fl_Check_Button * input);
-  void OnLegacyGroundChange(Fl_Valuator *input);
-  void OnSolverChange();
-
-  // Force example
-  void OnAnimateAction();
-
-  // This method should be called when the speed color map is updated
-  void OnSpeedColorMapUpdate();
-
-  // Help System
-  void ShowHelp(const char *link);
-
-  // Redraw the boxes
-  void RedrawAllBoxes();
-
-private:
-  /** Called internally when the parameters change */
-  void OnParameterUpdate();
-
-  /** Internal parameter values */
-  SnakeParameters m_Parameters;
-
-  /** Whether or not the user accepted the parameter values */
-  bool m_UserAccepted;
-
-  // Image used to demonstrate examples
-  typedef itk::OrientedImage<float,2> ExampleImageType;
-  typedef itk::SmartPointer<ExampleImageType> ExampleImagePointer;
-
-  /** Internally used example images */
-  ExampleImagePointer m_ExampleImage[2];
-
-  /** The preview pipeline used by all the preview windows */
-  SnakeParametersPreviewPipeline *m_PreviewPipeline;
-  
-  /** Whether or not to warn if the user tries to change the solver */
-  bool m_WarnOnSolverUpdate;
-
-  /** Parent user interface, needed for invoking the help system */
-  UserInterfaceBase *m_ParentUI;
-
-  /** A pointer to the system interface object */
-  SystemInterface *m_SystemInterface;
-
-  /** An interface used to save and load parameters */
-  SimpleFileDialogLogic *m_IODialog;
-
-  // IO Dialog callback functions
-  void LoadParametersCallback();
-  void SaveParametersCallback();
-
-  // FLTK timer callback for animation
-  static void OnTimerCallback(void *);
-
-  // Common code for closing the window
-  void CloseWindow();
-};
-
-#endif // __SnakeParametersUILogic_h_
diff --git a/UserInterface/MainComponents/UserInterface.fl b/UserInterface/MainComponents/UserInterface.fl
deleted file mode 100644
index ba1ebfd..0000000
--- a/UserInterface/MainComponents/UserInterface.fl
+++ /dev/null
@@ -1,1942 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0300 
-use_FL_COMMAND 
-header_name {.h} 
-code_name {.cxx}
-decl {\#include <stdio.h>} {public local
-} 
-
-decl {\#include <string.h>} {public local
-} 
-
-decl {\#include <FL/fl_ask.H>} {public local
-} 
-
-class UserInterface {open : {public UserInterfaceBase}
-} {
-  declblock {\#if 1 // Local variable declarations} {after {\#endif}
-  } {
-    decl {Vector3i fileRAI;} {public local
-    }
-    decl {Vector3i intRAI;} {public local
-    }
-    decl {Vector3i labelRAI;} {public local
-    }
-    decl {Vector3i preprocRAI;} {public local
-    }
-  }
-  Function {UserInterface()} {open
-  } {
-    Fl_Window m_WinMain {
-      label {ITK-SNAP Main Window}
-      callback {OnMainWindowCloseAction();} open
-      xywh {530 159 875 735} type Double align 0 resizable
-      code0 {\#include "UserInterfaceBase.h"}
-      class SNAPMainWindow visible
-    } {
-      Fl_Wizard m_WizMainLayout {open
-        xywh {0 0 875 735} box NO_BOX resizable
-      } {
-        Fl_Group m_GrpMainLayoutNormal {open
-          xywh {0 0 875 735} color 86 resizable
-        } {
-          Fl_Menu_Bar m_MenubarMain {
-            xywh {0 0 875 25} labelsize 12 textsize 12
-          } {
-            Submenu {} {
-              label {&File}
-              xywh {15 15 100 20} labelsize 12
-            } {
-              MenuItem m_MenuLoadGrey {
-                label {Open &Greyscale Image...}
-                callback {this->OnMenuLoadGrey();}
-                tooltip {Load an image that you want to segment} xywh {10 10 100 20} shortcut 0x40067 labelsize 12
-              }
-              MenuItem m_MenuLoadRGB {
-                label {Open &RGB Image...}
-                callback {this->OnMenuLoadRGB();}
-                tooltip {Load an RGB (color)  image, e.g., from a diffusion tensor imaging study} xywh {20 20 100 20} shortcut 0x40072 labelsize 12
-              }
-              MenuItem m_MenuLoadAdvection {
-                label {Advection Field (Advanced)}
-                callback {this->OnMenuLoadAdvection();}
-                tooltip {experimental feature} xywh {40 40 100 20} labelsize 12 hide deactivate divider
-              }
-              Submenu m_MenuLoadPrevious {
-                label {&Open Recent}
-                xywh {10 10 100 20} labelsize 12 divider
-              } {
-                MenuItem m_MenuLoadPreviousFirst {
-                  label {Not Available}
-                  callback {OnLoadRecentAction(0);}
-                  xywh {5 5 100 20} shortcut 0x40031 labelsize 12 deactivate
-                }
-                MenuItem {} {
-                  label {Not Available}
-                  callback {OnLoadRecentAction(1);}
-                  xywh {15 15 100 20} shortcut 0x40032 labelsize 12 deactivate
-                }
-                MenuItem {} {
-                  label {Not Available}
-                  callback {OnLoadRecentAction(2);}
-                  xywh {25 25 100 20} shortcut 0x40033 labelsize 12 deactivate
-                }
-                MenuItem {} {
-                  label {Not Available}
-                  callback {OnLoadRecentAction(3);}
-                  xywh {35 35 100 20} shortcut 0x40034 labelsize 12 deactivate
-                }
-                MenuItem m_MenuLoadPreviousLast {
-                  label {Not Available}
-                  callback {OnLoadRecentAction(4);}
-                  xywh {45 45 100 20} shortcut 0x40035 labelsize 12 deactivate
-                }
-              }
-              Submenu m_MenuSave {
-                label {&Save} open
-                xywh {25 25 100 20} labelsize 12
-              } {
-                MenuItem m_MenuSaveGrey {
-                  label {&Greyscale Image...}
-                  callback {this->OnMenuSaveGrey();}
-                  tooltip {Save the segmentation results as an image} xywh {45 45 100 20} labelsize 12 deactivate divider
-                }
-                MenuItem m_MenuSavePreprocessed {
-                  label {&Preprocessed Image...}
-                  callback {this->OnMenuSavePreprocessed();}
-                  xywh {45 45 100 20} shortcut 0x50070 labelsize 12 deactivate
-                }
-                MenuItem m_MenuSaveGreyROI {
-                  label {Greyscale Image &Region...}
-                  callback {this->OnMenuSaveGreyROI();}
-                  xywh {45 45 100 20} shortcut 0x50072 labelsize 12 deactivate
-                }
-                MenuItem m_MenuSaveLevelSet {
-                  label {&Level Set Function...}
-                  callback {this->OnMenuSaveLevelSet();}
-                  tooltip {Save the floating-point level set function during segmentation} xywh {55 55 100 20} shortcut 0x5006c labelsize 12 deactivate
-                }
-                MenuItem m_MenuSaveVoxelCounts {
-                  label {&Volumes && Statistics...}
-                  callback {this->OnMenuWriteVoxelCounts();}
-                  xywh {15 15 100 20} shortcut 0x50076 labelsize 12 hide deactivate
-                }
-              }
-              Submenu m_MenuExport {
-                label {&Export} open
-                xywh {25 25 100 20} labelsize 12 divider
-              } {
-                Submenu m_MenuExportSlice {
-                  label {&Image Slice} open
-                  xywh {5 5 100 20} labelsize 12 deactivate
-                } {
-                  MenuItem m_MenuExportSliceAxial {
-                    label {&Axial...}
-                    callback {OnMenuExportSlice(0);}
-                    xywh {55 55 100 20} labelsize 12
-                  }
-                  MenuItem m_MenuExportSliceSagittal {
-                    label {&Sagittal...}
-                    callback {OnMenuExportSlice(1);}
-                    xywh {65 65 100 20} labelsize 12
-                  }
-                  MenuItem m_MenuExportSliceCoronal {
-                    label {&Coronal...}
-                    callback {OnMenuExportSlice(2);}
-                    xywh {75 75 100 20} labelsize 12
-                  }
-                }
-                Submenu m_MenuSaveScreenshot {
-                  label {&Screenshot} open
-                  xywh {15 15 100 20} labelsize 12 deactivate
-                } {
-                  MenuItem m_MenuSaveScreenshotAxial {
-                    label {&Axial...}
-                    callback {OnMenuSaveScreenshot(0);}
-                    xywh {55 55 100 20} labelsize 12
-                  }
-                  MenuItem m_MenuSaveScreenshotSaggital {
-                    label {&Sagittal...}
-                    callback {OnMenuSaveScreenshot(1);}
-                    xywh {55 55 100 20} labelsize 12
-                  }
-                  MenuItem m_MenuSaveScreenshotCoronal {
-                    label {&Coronal...}
-                    callback {OnMenuSaveScreenshot(2);}
-                    xywh {55 55 100 20} labelsize 12
-                  }
-                }
-                Submenu m_MenuSaveScreenshotSeries {
-                  label {Screenshot S&eries} open
-                  xywh {15 15 100 20} labelsize 12 deactivate
-                } {
-                  MenuItem m_MenuSaveScreenshotSeriesAxial {
-                    label {&Axial...}
-                    callback {OnMenuSaveScreenshotSeries(0);}
-                    xywh {55 55 100 20} labelsize 12
-                  }
-                  MenuItem m_MenuSaveScreenshotSeriesSaggital {
-                    label {&Sagittal...}
-                    callback {OnMenuSaveScreenshotSeries(1);}
-                    xywh {55 55 100 20} labelsize 12
-                  }
-                  MenuItem m_MenuSaveScreenshotSeriesCoronal {
-                    label {&Coronal...}
-                    callback {OnMenuSaveScreenshotSeries(2);}
-                    xywh {55 55 100 20} labelsize 12
-                  }
-                }
-              }
-              MenuItem m_MenuResetAll {
-                label {&Unload All Images}
-                callback {this->OnMenuResetAll()}
-                tooltip Reset xywh {5 5 30 20} shortcut 0x40075 labelsize 12
-              }
-              MenuItem m_MenuLaunchNewInstance {
-                label {&New ITK-SNAP Window}
-                callback {this->OnMenuLaunchNewInstance()}
-                tooltip Reset xywh {15 15 30 20} shortcut 0x5006e labelsize 12 divider
-              }
-              MenuItem {} {
-                label {&Quit}
-                callback {this->OnMenuQuit();}
-                xywh {50 50 100 20} shortcut 0x40071 labelsize 12
-              }
-            }
-            Submenu {} {
-              label {&Segmentation}
-              xywh {10 10 100 20} labelsize 12
-            } {
-              MenuItem m_MenuLoadSegmentation {
-                label {&Load From Image...}
-                callback {this->OnMenuLoadSegmentation();}
-                tooltip {Load a previously created segmentation} xywh {20 20 100 20} shortcut 0x40064 labelsize 12 deactivate
-              }
-              MenuItem m_MenuNewSegmentation {
-                label {&Clear}
-                callback {this->OnMenuNewSegmentation()}
-                tooltip {Creates a new empty segmentation} xywh {5 5 30 20} shortcut 0x4006e labelsize 12 divider
-              }
-              MenuItem m_MenuSaveSegmentation {
-                label {&Save As Image...}
-                callback {this->OnMenuSaveSegmentation();}
-                tooltip {Save the segmentation results as an image} xywh {35 35 100 20} shortcut 0x40073 labelsize 12 deactivate
-              }
-              MenuItem m_MenuSaveSegmentationMesh {
-                label {Export As Surface &Mesh...}
-                callback {this->OnMenuSaveSegmentationMesh();}
-                tooltip {Save the segmentation results as an image} xywh {45 45 100 20} shortcut 0x5006d labelsize 12 deactivate divider
-              }
-              MenuItem m_MenuLoadLabels {
-                label {Load Label &Descriptions...}
-                callback {this->OnMenuLoadLabels();}
-                xywh {30 30 100 20} shortcut 0x4006c labelsize 12
-              }
-              MenuItem m_MenuSaveLabels {
-                label {Save Label D&escriptions...}
-                callback {this->OnMenuSaveLabels();}
-                xywh {45 45 100 20} shortcut 0x5006c labelsize 12 divider
-              }
-              MenuItem m_MenuShowVolumes {
-                label {&Volumes and Statistics...}
-                callback {this->OnMenuShowVolumes();}
-                tooltip {Change the mapping between voxel coordinates and world coordinates} xywh {25 25 100 20} shortcut 0x50076 labelsize 12
-              }
-            }
-            Submenu {} {
-              label {&Overlay}
-              xywh {10 10 100 20} labelsize 12
-            } {
-              MenuItem m_MenuLoadGreyOverlay {
-                label {Add &Greyscale Overlay...}
-                callback {this->OnMenuLoadGreyOverlay();}
-                tooltip {Load a Grey image on top of an already loaded grayscale image} xywh {20 20 100 20} shortcut 0x50067 labelsize 12 deactivate
-              }
-              MenuItem m_MenuLoadRGBOverlay {
-                label {Add &RGB Overlay...}
-                callback {this->OnMenuLoadRGBOverlay();}
-                tooltip {Load an RGB image on top of an already loaded grayscale image} xywh {20 20 100 20} shortcut 0x50072 labelsize 12 deactivate divider
-              }
-              MenuItem m_MenuUnloadOverlayLast {
-                label {&Unload Last Overlay}
-                callback {this->OnMenuUnloadOverlayLast()}
-                tooltip {Unload Last Greyscale Overlay} xywh {5 5 30 20} labelsize 12
-              }
-              MenuItem m_MenuUnloadOverlays {
-                label {Unload &All Overlays}
-                callback {this->OnMenuUnloadOverlays()}
-                tooltip {Unload All Greyscale Overlays} xywh {5 5 30 20} labelsize 12 divider
-              }
-              MenuItem m_MenuLayerInspector {
-                label {&Layer Inspector...}
-                callback {OnMenuShowLayerInspector()}
-                xywh {10 10 30 20} labelsize 12
-              }
-            }
-            Submenu {} {
-              label {&Tools} open
-              xywh {10 10 100 20} labelsize 12
-            } {
-              Submenu {} {
-                label {Active Main &Tool} open
-                xywh {0 0 62 20} labelsize 12
-              } {
-                MenuItem m_MenuCrosshairsMode {
-                  label {&Crosshair}
-                  callback {SetToolbarMode(CROSSHAIRS_MODE);}
-                  xywh {0 0 31 20} shortcut 0x31 value 1 labelsize 12
-                }
-                MenuItem m_MenuZoomPanMode {
-                  label {&Zoom / Pan}
-                  callback {SetToolbarMode(NAVIGATION_MODE);}
-                  xywh {10 10 31 20} shortcut 0x32 labelsize 12
-                }
-                MenuItem m_MenuPolygonMode {
-                  label {&Polygon}
-                  callback {SetToolbarMode(POLYGON_DRAWING_MODE);}
-                  xywh {20 20 31 20} shortcut 0x33 labelsize 12
-                }
-                MenuItem m_MenuSNAPMode {
-                  label {&Snake ROI}
-                  callback {SetToolbarMode(ROI_MODE);}
-                  xywh {30 30 31 20} shortcut 0x34 labelsize 12
-                }
-                MenuItem m_MenuPaintbrushMode {
-                  label {Paint&brush}
-                  callback {SetToolbarMode(PAINTBRUSH_MODE);}
-                  xywh {40 40 31 20} shortcut 0x35 labelsize 12
-                }
-                MenuItem m_MenuAnnotationMode {
-                  label {&Annotation}
-                  callback {SetToolbarMode(ANNOTATION_MODE);}
-                  xywh {50 50 31 20} shortcut 0x36 labelsize 12 hide
-                }
-              }
-              Submenu {} {
-                label {Active &3D Tool} open
-                xywh {15 15 62 20} labelsize 12 divider
-              } {
-                MenuItem m_MenuTrackballMode {
-                  label {&Trackball}
-                  callback {SetToolbarMode3D(TRACKBALL_MODE);}
-                  xywh {10 10 31 20} value 1 labelsize 12
-                }
-                MenuItem m_MenuCrosshair3DMode {
-                  label {&Crosshair}
-                  callback {SetToolbarMode3D(CROSSHAIRS_3D_MODE);}
-                  xywh {20 20 31 20} labelsize 12
-                }
-                MenuItem m_MenuScalpelMode {
-                  label {&Scalpel}
-                  callback {SetToolbarMode3D(SCALPEL_MODE);}
-                  xywh {30 30 31 20} labelsize 12
-                }
-                MenuItem m_MenuSpraypaintMode {
-                  label {Spray&paint}
-                  callback {SetToolbarMode3D(SPRAYPAINT_MODE);}
-                  xywh {40 40 31 20} labelsize 12
-                }
-              }
-              MenuItem m_MenuIntensityCurve {
-                label {Image &Contrast...}
-                callback {this->OnMenuIntensityCurve();}
-                xywh {20 20 100 20} shortcut 0x40069 labelsize 12 deactivate
-              }
-              MenuItem m_MenuColorMap {
-                label {Image Color &Map...}
-                callback {this->OnMenuColorMap();}
-                xywh {20 20 100 20} shortcut 0x4006b labelsize 12 deactivate
-              }
-              MenuItem m_MenuImageInfo {
-                label {&Image Info...}
-                callback {this->OnMenuImageInfo();}
-                xywh {10 10 100 20} labelsize 12 divider
-              }
-              MenuItem m_MenuReorientImage {
-                label {&Reorient Image...}
-                callback {this->OnMenuReorientImage();}
-                tooltip {Change the mapping between voxel coordinates and world coordinates} xywh {30 30 100 20} labelsize 12 divider
-              }
-              MenuItem {} {
-                label {&Display Options...}
-                callback {OnMenuShowDisplayOptions();}
-                xywh {10 10 100 20} labelsize 12
-              }
-            }
-            Submenu {} {
-              label {&Layout}
-              xywh {0 0 62 20} labelsize 12
-            } {
-              MenuItem {} {
-                label {Toggle User Interface Elements}
-                callback {this->OnMenuViewToggleUI();}
-                xywh {15 15 30 20} shortcut 0xffc0 labelsize 12
-              }
-              MenuItem {} {
-                label {Toggle Full-Screen Mode}
-                callback {this->OnMenuViewToggleFullscreen();}
-                xywh {0 0 30 20} shortcut 0xffc1 labelsize 12
-              }
-              MenuItem {} {
-                label {Restore Default Layout}
-                callback {this->OnMenuViewRestoreDefault();}
-                xywh {10 10 30 20} shortcut 0x40ffc0 labelsize 12
-              }
-            }
-            Submenu {} {
-              label {&Help}
-              xywh {5 5 100 20} labelsize 12
-            } {
-              MenuItem {} {
-                label {&Help Index...}
-                callback {fl_open_uri("http://www.itksnap.org/pmwiki/pmwiki.php?n=Documentation.HomePage");}
-                xywh {35 35 100 20} shortcut 0xffbe labelsize 12
-              }
-              MenuItem {} {
-                label {&Keyboard shortcuts...}
-                callback {fl_open_uri("http://www.itksnap.org/pmwiki/pmwiki.php?n=Documentation.KeyboardShortcuts");}
-                xywh {45 45 100 20} labelsize 12
-              }
-              MenuItem {} {
-                label {&Credits...}
-                callback {fl_open_uri("http://www.itksnap.org/pmwiki/pmwiki.php?n=Credits");}
-                xywh {25 25 100 20} shortcut 0x1ffbe labelsize 12
-              }
-              MenuItem {} {
-                label {&About...}
-                callback {m_WinAbout->show();}
-                xywh {35 35 100 20} labelsize 12
-              }
-              MenuItem {} {
-                label {Check for &Updates...}
-                callback {this->OnMenuCheckForUpdate();}
-                tooltip {Connect to the ITK-SNAP server to check if your version is up to date.} xywh {55 55 100 20} labelsize 12
-              }
-            }
-          }
-          Fl_Group m_GrpControls {open
-            xywh {0 24 145 711} box BORDER_FRAME color 0
-          } {
-            Fl_Wizard m_WizControlPane {
-              label {Control Pane} open
-              xywh {0 25 145 700} box NO_BOX color 22 align 16
-            } {
-              Fl_Group m_GrpToolbarPage {open
-                xywh {0 25 145 700} color 53 labelsize 12
-              } {
-                Fl_Group m_GrpInteractionModes {
-                  label {Main Toolbox}
-                  xywh {5 45 135 95} box PLASTIC_UP_BOX color 22 labeltype EMBOSSED_LABEL labelsize 12 labelcolor 4
-                } {
-                  Fl_Button m_BtnCrosshairsMode {
-                    callback {SetToolbarMode(CROSSHAIRS_MODE);}
-                    tooltip {Crosshairs tool: left clicking moves the cursor} image {Artwork/crosshair.gif} xywh {15 55 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX value 1 color 180 selection_color 180 align 16 when 1
-                  }
-                  Fl_Button m_BtnNavigationMode {
-                    callback {SetToolbarMode(NAVIGATION_MODE);}
-                    tooltip {Navigation tool: zoom and pan around the 2D slices} image {Artwork/zoom.gif} xywh {55 55 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 180 align 16 when 1
-                  }
-                  Fl_Button m_BtnPolygonMode {
-                    callback {SetToolbarMode(POLYGON_DRAWING_MODE);}
-                    tooltip {Polygon tool: slice-by-slice manual segmentation} image {Artwork/poly.gif} xywh {95 55 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 180 align 16 when 1
-                  }
-                  Fl_Button m_BtnSNAPMode {
-                    callback {SetToolbarMode(ROI_MODE);}
-                    tooltip {Snake ROI tool: select a region of interest for automatic segmentation} image {Artwork/snake.gif} xywh {15 95 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 180 labelsize 10 align 144 when 1
-                  }
-                  Fl_Button m_BtnPaintbrushMode {
-                    callback {SetToolbarMode(PAINTBRUSH_MODE);}
-                    tooltip {Paintbrush tool} image {Artwork/paintbrush.gif} xywh {55 95 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 180 labelfont 1 labelsize 20 align 16 when 1
-                  }
-                  Fl_Button m_BtnAnnotationMode {
-                    label A
-                    callback {SetToolbarMode(ANNOTATION_MODE);}
-                    tooltip {Annotation tool (in development)} xywh {95 95 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0x36 color 180 selection_color 180 labeltype EMBOSSED_LABEL labelfont 1 labelsize 18 align 144 when 1 hide
-                  }
-                }
-                Fl_Group {} {
-                  label {Tool Options} open
-                  xywh {5 164 135 167} box PLASTIC_UP_BOX color 22 labeltype EMBOSSED_LABEL labelsize 12 labelcolor 4
-                } {
-                  Fl_Wizard m_TabsToolOptions {
-                    label {Active Tool Settings} open
-                    xywh {5 165 135 166} box NO_BOX color 22 labeltype NO_LABEL labelsize 12 labelcolor 4
-                  } {
-                    Fl_Group m_GrpToolOptionCrosshairs {
-                      label 1
-                      xywh {5 165 135 165} labeltype NO_LABEL labelfont 1 labelsize 12 align 17 hide
-                    } {
-                      Fl_Output m_OutGreyProbe {
-                        label {Intensity:}
-                        tooltip {Intensity value at cursor position} xywh {15 214 50 20} box THIN_DOWN_BOX color 52 selection_color 48 labelsize 11 align 5 textsize 11
-                      }
-                      Fl_Output m_OutLabelProbe {
-                        label {Label:}
-                        tooltip {Label at current position} xywh {80 214 50 20} box THIN_DOWN_BOX color 52 selection_color 48 labelsize 11 align 5 textsize 11
-                      }
-                      Fl_Output m_OutLabelProbeText {
-                        label {Label description:}
-                        tooltip {Label at current position} xywh {15 254 115 20} box THIN_DOWN_BOX color 52 selection_color 48 labelsize 11 align 5 textsize 11
-                      }
-                      Fl_Group {} {
-                        label {Crosshairs Tool} open
-                        tooltip {This tool navigates around the image. Press and drag with the left mouse button to reposition the cursor in the three slice views. Use the mouse wheel to change the slice. The arrow and PgUp/PgDn also work.} xywh {10 170 125 25} box PLASTIC_DOWN_BOX color 61 labelsize 12 align 16
-                      } {}
-                      Fl_Check_Button m_BtnSynchronizeCursor {
-                        label {Multisession cursor}
-                        callback {this->OnSynchronizeCursorAction();}
-                        tooltip {Synchronizes the crosshair position across multple sessions of ITK-SNAP} xywh {15 285 115 20} down_box DOWN_BOX value 1 labelsize 11
-                      }
-                    }
-                    Fl_Group m_GrpToolOptionPolygon {
-                      label 3
-                      xywh {5 165 135 165} color 22 labelsize 10 labelcolor 4 hide
-                    } {
-                      Fl_Group {} {
-                        label {Polygon Tool} open
-                        tooltip {Use this tool to draw polygons. The left mouse button is used to add points to the polygon, the right button will close the polygon. After the polygon is closed you select and move control points. Once you 'accept' a polygon, it is added to the segmentation.} xywh {10 170 125 25} box PLASTIC_DOWN_BOX color 243 labelsize 12 align 16
-                      } {}
-                      Fl_Group {} {
-                        label {Freehand drawing:} open
-                        xywh {15 217 120 78} labelsize 11 align 5
-                      } {
-                        Fl_Round_Button m_InIRISFreehandContinuous {
-                          label continuous
-                          callback {OnIRISFreehandFittingRateUpdate()}
-                          xywh {20 220 115 15} type Radio down_box ROUND_DOWN_BOX labeltype NO_LABEL labelsize 12
-                        }
-                        Fl_Round_Button m_InIRISFreehandLineSegment {
-                          label {line segments:}
-                          callback {OnIRISFreehandFittingRateUpdate()}
-                          xywh {20 235 115 15} type Radio down_box ROUND_DOWN_BOX value 1 labeltype NO_LABEL labelsize 12
-                        }
-                        Fl_Value_Slider m_InIRISFreehandFittingRate {
-                          label {segment length}
-                          callback {OnIRISFreehandFittingRateUpdate()}
-                          tooltip {Changes what happens when you draw a freehand curve. The larger this number, the fewer line segments will be used to represent the freehand drawing.} xywh {40 255 90 15} type Horizontal labelsize 11 minimum 1 maximum 16 step 1 value 8
-                        }
-                        Fl_Group {} {
-                          label {continuous curve} open
-                          xywh {35 220 15 15} labelsize 11 align 20
-                        } {}
-                        Fl_Group {} {
-                          label {piecewise linear} open
-                          xywh {35 235 15 15} labelsize 11 align 20
-                        } {}
-                      }
-                      Fl_Button {} {
-                        label {?}
-                        callback {this->ShowHTMLPage("ContextHelp_Freehand.html");}
-                        xywh {116 202 18 18} box PLASTIC_ROUND_UP_BOX color 180 labelfont 1 labelsize 12 align 16
-                      }
-                    }
-                    Fl_Group m_GrpToolOptionSNAP {
-                      label 5 open
-                      xywh {5 165 135 165} labelsize 10 hide
-                    } {
-                      Fl_Group {} {
-                        label {Snake ROI Tool} open
-                        tooltip {Use this tool to enter the automatic segmentation mode. You can select a region of the image that contains the structure of interest by moving the sides and corners of the region's bounding box. Then enter the automatic segmentation mode. You can optionally change the voxel size of the region before running segmentation.} xywh {10 170 125 25} box PLASTIC_DOWN_BOX color 178 labelsize 12 align 16
-                      } {}
-                      Fl_Button m_BtnResetROI {
-                        label {Reset ROI}
-                        callback {OnResetROIAction();}
-                        tooltip {Set region of interest to entire volume} xywh {20 265 105 25} box PLASTIC_UP_BOX color 181 labelsize 11
-                      }
-                      Fl_Check_Button m_ChkResampleRegion {
-                        label {Resample ROI}
-                        tooltip {Check this is you want to change the voxel size of the ROI before entering automatic segmentation. This is recommended for large ROIs and anisotropic images.} xywh {20 200 110 25} down_box DOWN_BOX labelsize 11
-                      }
-                      Fl_Button m_BtnStartSnake {
-                        label {Segment 3D}
-                        callback {OnSnakeStartAction();}
-                        xywh {20 295 105 25} box PLASTIC_UP_BOX shortcut 0x40061 color 181 labelfont 1 labelsize 11
-                      }
-                    }
-                    Fl_Group m_GrpToolOptionZoomPan {
-                      label 2 open
-                      xywh {5 165 135 165} labelsize 10
-                    } {
-                      Fl_Group {} {
-                        label {Zoom / Pan Tool} open
-                        tooltip {Use this tool to change the zoom level and to pan around the image. Hold and drag the left mouse button to zoom and hold and drag the right button to pan.} xywh {10 170 125 25} box PLASTIC_DOWN_BOX color 91 labelsize 12 align 16
-                      } {}
-                      Fl_Check_Button m_ChkLinkedZoom {
-                        label { Zoom views together}
-                        callback {OnLinkedZoomChange();}
-                        tooltip {Select to use the same zoom factor in all three orthogonal projections of the image} xywh {10 200 120 15} down_box DOWN_BOX labelsize 10
-                      }
-                      Fl_Check_Button m_ChkMultisessionZoom {
-                        label { Multi-session zoom}
-                        callback {OnMultisessionZoomChange();}
-                        tooltip {Select to synchronize zooming across multiple ITK-SNAP sessions} xywh {10 220 120 15} down_box DOWN_BOX labelsize 10 when 1 deactivate
-                      }
-                      Fl_Check_Button m_ChkMultisessionPan {
-                        label { Multi-session pan}
-                        callback {OnMultisessionPanChange();}
-                        tooltip {Select to synchronize panning across multiple ITK-SNAP sessions} xywh {10 240 120 15} down_box DOWN_BOX labelsize 10 when 1 deactivate
-                      }
-                      Fl_Value_Input m_InZoomLevel {
-                        label {Zoom:}
-                        callback {OnZoomLevelChange();}
-                        tooltip {Zoom is specified as the number of screen pixels per millimeter in patient space} xywh {55 265 45 20} color 52 labelsize 11 when 8 step 0.001 textsize 11 deactivate
-                      }
-                      Fl_Group m_GrpLinkedZoomUnits {
-                        label {px/mm} open
-                        xywh {100 265 30 20} labelsize 10 align 20 deactivate
-                      } {}
-                      Fl_Button {} {
-                        label {Reset all views}
-                        callback {this->OnResetAllViews2DAction();}
-                        xywh {25 295 95 25} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0x40066 color 180 selection_color 94 labelsize 11 align 128
-                      }
-                    }
-                    Fl_Group m_GrpToolOptionBrush {
-                      label 6
-                      xywh {5 165 135 165} color 22 labelsize 10 labelcolor 4 hide
-                    } {
-                      Fl_Group {} {
-                        label {Paintbrush Tool} open
-                        tooltip {Use this tool to paint with the currently selected label. You can choose between different brush shapes and sizes. Use the right mouse button to paint with the clear label.} xywh {10 170 125 25} box PLASTIC_DOWN_BOX color 243 labelsize 12 align 16
-                      } {}
-                      Fl_Choice m_InPaintbrushShape {
-                        label {Shape:}
-                        callback {OnPaintbrushAttributesUpdate()} open
-                        tooltip {Choose the shape of the paintbrush tool} xywh {55 200 80 20} down_box BORDER_BOX labelsize 12 when 1 textsize 12
-                      } {
-                        MenuItem {m_ChoicePaintbrush[0]} {
-                          label Square
-                          xywh {5 5 31 21} labelsize 12
-                        }
-                        MenuItem {m_ChoicePaintbrush[1]} {
-                          label Round
-                          xywh {5 5 31 21} labelsize 12
-                        }
-                        MenuItem {m_ChoicePaintbrush[2]} {
-                          label Adaptive
-                          xywh {15 15 31 21} labelsize 12
-                        }
-                      }
-                      Fl_Counter m_InPaintbrushSize {
-                        label {Size:}
-                        callback {OnPaintbrushAttributesUpdate()}
-                        xywh {55 224 80 16} type Simple box PLASTIC_THIN_UP_BOX color 180 selection_color 25 labelsize 12 align 4 minimum 1 maximum 100 step 1 value 1 textsize 11
-                      }
-                      Fl_Check_Button m_BtnPaintbrushIsotropic {
-                        label Isotropic
-                        callback {OnPaintbrushAttributesUpdate()}
-                        tooltip {Enable this in order to make the brush size more or less independent of the voxel size} xywh {75 250 64 15} down_box DOWN_BOX labelsize 11
-                      }
-                      Fl_Check_Button m_BtnPaintbrushChaseMode {
-                        label {Cursor chases brush}
-                        callback {OnPaintbrushAttributesUpdate()}
-                        tooltip {Enable this to make the crosshairs (the cursor) follow the paintbrush} xywh {10 267 120 15} down_box DOWN_BOX labelsize 11
-                      }
-                      Fl_Check_Button m_BtnPaintbrush3D {
-                        label {3D brush}
-                        callback {OnPaintbrushAttributesUpdate()}
-                        tooltip {Enable to make the brush three-dimensional, so it paints in all three views at once} xywh {10 250 64 15} down_box DOWN_BOX labelsize 11
-                      }
-                      Fl_Wizard m_WizPaintbrushParameters {open
-                        xywh {10 285 125 40} box NO_BOX
-                      } {
-                        Fl_Group {m_GrpPaintbrushParameters[0]} {open
-                          xywh {10 285 125 40} hide
-                        } {}
-                        Fl_Group {m_GrpPaintbrushParameters[1]} {open
-                          xywh {10 285 125 40} hide
-                        } {}
-                        Fl_Group {m_GrpPaintbrushParameters[2]} {open
-                          xywh {10 285 125 40}
-                        } {
-                          Fl_Value_Input m_InPaintbrushSmoothing {
-                            label {Smoothing:}
-                            callback {OnPaintbrushAttributesUpdate()}
-                            xywh {95 307 40 18} labelsize 11 minimum 1 maximum 100 step 1 value 15 textsize 11
-                          }
-                          Fl_Value_Input m_InPaintbrushGranularity {
-                            label {Granularity:}
-                            callback {OnPaintbrushAttributesUpdate()}
-                            xywh {95 287 40 18} labelsize 11 step 0.01 value 0.2 textsize 11
-                          }
-                        }
-                      }
-                    }
-                    Fl_Group m_GrpToolOptionAnnotation {
-                      xywh {5 165 135 165} labelsize 10 hide
-                    } {
-                      Fl_Group {} {
-                        label {Annotation Tool} open
-                        tooltip {To add a new line: Left-click and drag to draw line; use left mouse to edit line; right click to accept line. (2) To delete drawn lines: Right click(s) to delete the lines one by one in reverse order; or delete all the lines at once by the "delete" key.  THIS IS A WORK IN PROGRESS.} xywh {10 170 125 25} box PLASTIC_DOWN_BOX color 243 labelsize 12 align 16
-                      } {}
-                      Fl_Check_Button m_BtnAnnotationShownOnAllSlices {
-                        label {Shown on all slices}
-                        callback {OnAnnotationAttributesUpdate()}
-                        tooltip {Enable this in order to make the annotation drawn on a particular slice level to be shown on all other slices} xywh {10 205 120 15} down_box DOWN_BOX labelsize 11
-                      }
-                    }
-                  }
-                }
-                Fl_Group {} {
-                  label {Segmentation Options} open
-                  xywh {5 354 135 211} box PLASTIC_UP_BOX color 22 labeltype EMBOSSED_LABEL labelsize 12 labelcolor 4
-                } {
-                  Fl_Button {} {
-                    label {Label editor}
-                    callback {OnEditLabelsAction();}
-                    tooltip {Press this button to bring up the label editor} xywh {20 500 105 25} box PLASTIC_UP_BOX color 180 labelsize 11
-                  }
-                  Fl_Value_Slider m_InIRISLabelOpacity {
-                    label {Overall label opacity:}
-                    callback {o->take_focus();
-this->OnIRISLabelOpacityChange();}
-                    tooltip {Change the transparency of the labels
-
-Keyboard shortcuts:
- 'a' to decrease, 'd' to increase, 's' to toggle.} xywh {15 475 115 15} type Horizontal labelsize 11 align 5 maximum 255 step 1 value 128
-                  }
-                  Fl_Choice m_InDrawingColor {
-                    label {Active drawing label:}
-                    callback {o->take_focus();
-OnDrawingLabelUpdate();} open
-                    tooltip {This selects the color label with which you paint when using manual tools and automatic segmentation} xywh {15 377 115 18} down_box BORDER_BOX color 52 labelsize 11 align 5 textsize 11
-                  } {}
-                  Fl_Choice m_InDrawOverColor {
-                    label {Draw over:}
-                    callback {o->take_focus();
-OnDrawOverLabelUpdate();} open
-                    tooltip {This selects the label OVER WHICH you paint. Normally you want to paint over all labels, but you can also paint over a specific label, only over unlabeled voxels (clear label) or over all visible labels. To change a label's visibility choose 'Edit Labels'.} xywh {15 412 115 18} down_box BORDER_BOX color 52 labelsize 11 align 5 textsize 11
-                  } {}
-                  Fl_Check_Button m_ChkInvertPolygon {
-                    label {Draw inverted}
-                    callback {m_GlobalState->SetPolygonInvert(o->value() != 0);}
-                    tooltip {When "draw inverted" is checked, paint operations (polygon drawing, 3D tools, automatic segmentation) are applied to the inversly: the outside of the polygon is painted, etc.} xywh {15 435 115 20} down_box DOWN_BOX labelsize 11
-                  }
-                  Fl_Button m_BtnIRISUndo {
-                    label Undo
-                    callback {OnUndoAction();}
-                    tooltip {Undo the last drawing operation} xywh {20 530 50 25} box PLASTIC_UP_BOX color 180 labelsize 11 deactivate
-                  }
-                  Fl_Button m_BtnIRISRedo {
-                    label Redo
-                    callback {OnRedoAction();}
-                    tooltip {Redo the last drawing operation} xywh {75 530 50 25} box PLASTIC_UP_BOX color 180 labelsize 11 deactivate
-                  }
-                  Fl_Button {} {
-                    label {?}
-                    callback {this->ShowHTMLPage("ContextHelp_SegmentationOptions.html");}
-                    xywh {115 437 18 18} box PLASTIC_ROUND_UP_BOX color 180 labelfont 1 labelsize 12 align 16
-                  }
-                }
-                Fl_Group {} {
-                  label {3D Toolbox} open
-                  xywh {5 590 135 95} box PLASTIC_UP_BOX color 22 labeltype EMBOSSED_LABEL labelsize 12 labelcolor 4
-                } {
-                  Fl_Button m_BtnCrosshair3DMode {
-                    callback {SetToolbarMode3D(CROSSHAIRS_3D_MODE);}
-                    tooltip {3D navigation tool: use the left mouse button to position the crosshairs at point on the segmentation surface} image {Artwork/crosshair3D.gif} xywh {55 600 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 180 align 16
-                  }
-                  Fl_Button m_BtnTrackballMode {
-                    callback {SetToolbarMode3D(TRACKBALL_MODE);}
-                    tooltip {3D trackball tool: left mouse button rotates the 3D view, right mouse button zooms and the middle button pans.} image {Artwork/rotate3d.gif} xywh {15 600 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX value 1 color 180 selection_color 180 align 16
-                  }
-                  Fl_Button m_BtnScalpelMode {
-                    callback {SetToolbarMode3D(SPRAYPAINT_MODE);}
-                    tooltip {3D spraypaint tool. Click (and hold) the left mouse button to relabel voxels on the boundaries of segmented objects} image {Artwork/spray.gif} xywh {15 640 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 180 align 16
-                  }
-                  Fl_Button m_BtnSpraypaintMode {
-                    callback {SetToolbarMode3D(SCALPEL_MODE);}
-                    tooltip {3D scalpel tool. Click at two locations in the 3D window to define a cutplane, then choose 'accept' to apply a paint operation on one side of the cutplane} image {Artwork/scalpel.gif} xywh {95 600 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 180 align 16
-                  }
-                }
-              }
-              Fl_Group m_GrpWelcomePage {
-                xywh {0 25 145 695} color 53 hide
-              } {
-                Fl_Group {} {
-                  label {ITK-SNAP} open
-                  xywh {5 195 135 35} labelfont 3 labelsize 20 align 0
-                } {}
-                Fl_Group m_InWelcomePageVersion {
-                  label {Version X.XX
-Build Date X.XXX
-
-itksnap.org} open
-                  xywh {5 225 135 70} labelsize 12 align 145
-                } {}
-                Fl_Group {} {
-                  label {Tip of the day:} open
-                  xywh {5 455 135 254} color 22 labeltype EMBOSSED_LABEL labelsize 12 labelcolor 4 align 133
-                } {
-                  Fl_Button {} {
-                    label {Next Tip}
-                    callback {this->DisplayTips();}
-                    xywh {75 675 65 25} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 134 labelsize 12
-                  }
-                  Fl_Help_View m_OutTips {
-                    xywh {5 460 135 210}
-                  }
-                }
-              }
-              Fl_Group m_GrpSNAPPage {open
-                xywh {0 25 145 680} color 53 hide
-              } {
-                Fl_Group {} {
-                  label {Image Interaction} open
-                  xywh {5 44 135 116} box PLASTIC_UP_BOX color 22 labeltype EMBOSSED_LABEL labelsize 12 labelcolor 4
-                } {
-                  Fl_Button m_BtnSNAPCrosshairs {
-                    callback {SetToolbarMode(CROSSHAIRS_MODE);}
-                    tooltip {Crosshairs: left clicking moves the cursor} image {Artwork/crosshair.gif} xywh {15 54 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0x63 value 1 color 179 selection_color 180 align 16
-                  }
-                  Fl_Button m_BtnSNAPNavigation {
-                    callback {SetToolbarMode(NAVIGATION_MODE);}
-                    tooltip {Navigation: zoom, pan, and rotate} image {Artwork/zoom.gif} xywh {55 54 35 35} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0x6e color 180 selection_color 180 align 16
-                  }
-                  Fl_Output m_OutSNAPProbe {
-                    label {Grey:}
-                    tooltip {Intensity value at cursor position} xywh {10 135 40 20} box THIN_DOWN_BOX color 52 selection_color 48 labelsize 10 align 5 textsize 10
-                  }
-                  Fl_Output m_OutSNAPLabelProbe {
-                    label {Label:}
-                    tooltip {Label at cursor position} xywh {105 135 30 20} box THIN_DOWN_BOX color 52 selection_color 48 labelsize 10 align 5 textsize 10
-                  }
-                  Fl_Group m_GrpSNAPCurrentColor {
-                    label {Segmentation Label:} open
-                    tooltip {Color of current label} xywh {10 110 125 10} box BORDER_BOX color 23 selection_color 57 labelsize 10 align 5
-                  } {}
-                  Fl_Output m_OutSNAPSpeedProbe {
-                    label {Preproc.:}
-                    tooltip {Value of the 'speed' image under the cursor. The speed image affects how fast the active contour propagates at each point in the image.} xywh {55 135 45 20} box THIN_DOWN_BOX color 52 selection_color 48 labelsize 10 align 5 textsize 10
-                  }
-                }
-                Fl_Group {} {
-                  label {Segmentation Pipeline} open
-                  xywh {5 185 135 350} box PLASTIC_UP_BOX color 22 labeltype EMBOSSED_LABEL labelsize 12 labelcolor 4
-                } {
-                  Fl_Wizard m_WizSegmentationPipeline {
-                    label {Segmentation Pipeline} open
-                    xywh {5 185 135 350} box NO_BOX color 23 labeltype NO_LABEL labelsize 12 labelcolor 4
-                  } {
-                    Fl_Group m_GrpSNAPStepPreprocess {
-                      label {Preprocess Image} open
-                      xywh {10 190 125 340} color 22 labeltype EMBOSSED_LABEL labelsize 12 labelcolor 4 hide
-                    } {
-                      Fl_Button m_BtnPreprocess {
-                        label {Preprocess Image}
-                        callback {this->OnPreprocessAction();}
-                        tooltip {Use this button to preprocess the grayscale image to genereate the 'speed' image. The speed image affects how fast the active contour propagates at each point in the image.} xywh {15 400 115 25} box PLASTIC_UP_BOX color 180 labelsize 11 align 144
-                      }
-                      Fl_Group m_GrpSnakeChoiceRadio {
-                        label {Snake mode:} open
-                        xywh {10 279 125 60} labeltype NO_LABEL labelsize 12 align 5
-                      } {
-                        Fl_Round_Button m_RadSnakeInOut {
-                          callback {OnInOutSnakeSelect();}
-                          tooltip {In the inside/outside segmentation mode, the speed image is close to +1 at voxels that are likely to be in the structure of interest and is close to -1 in the background. The snake is attracted to places where the speed function is close to 0.} xywh {11 294 120 25} down_box ROUND_DOWN_BOX value 1 color 205 align 148
-                        }
-                        Fl_Round_Button m_RadSnakeEdge {
-                          callback {OnEdgeSnakeSelect();}
-                          tooltip {In the edge-based segmentation mode, the speed image is close to 0 at 'edges' in the input image and is close to 1 in regions where the intensity is nearly constant. The snake is attracted to the edges in the image.} xywh {11 314 105 25} down_box ROUND_DOWN_BOX
-                        }
-                      }
-                      Fl_Button m_BtnAcceptPreprocessing {
-                        label {  Next @-1>}
-                        callback {OnAcceptPreprocessingAction();}
-                        tooltip {Accept the 'speed' image and proceed to specifying the initial active contour.} xywh {75 505 55 25} box PLASTIC_UP_BOX color 180 labelfont 1 labelsize 12 align 16
-                      }
-                      Fl_Button {} {
-                        label {@-1< Back  }
-                        tooltip {Go to the previous step in the active snake pipeline} xywh {15 505 55 25} box PLASTIC_UP_BOX color 180 labelsize 12 labelcolor 32 align 16 deactivate
-                      }
-                      Fl_Button m_BtnLoadPreprocessedImage {
-                        label {Load from File}
-                        callback {this->OnLoadPreprocessedImageAction();}
-                        tooltip {Load the 'speed' image from an external file.} xywh {15 445 115 25} box PLASTIC_UP_BOX color 180 labelsize 11 align 144
-                      }
-                      Fl_Group {} {
-                        label or open
-                        xywh {10 425 125 20} labelsize 11 align 16
-                      } {}
-                      Fl_Group {} {
-                        label Preprocessing open
-                        xywh {10 190 125 40} box PLASTIC_DOWN_BOX color 78 labelsize 12 align 18
-                      } {
-                        Fl_Group {} {
-                          label {Step 1 of 3} open
-                          xywh {15 190 115 25} labelfont 1 align 16
-                        } {}
-                      }
-                      Fl_Group {} {
-                        label {A. Choose what kinds
-of image features will
-drive active contour
-evolution:} open
-                        xywh {10 235 125 45} labelsize 11 align 21
-                      } {}
-                      Fl_Group {} {
-                        label {B. Use buttons below
-to define image regions or edges:} open
-                        xywh {10 351 125 45} labelsize 11 align 149
-                      } {}
-                      Fl_Group {} {open
-                        xywh {10 325 125 10} color 78 labelsize 12 align 18
-                      } {}
-                      Fl_Group {} {open
-                        xywh {10 460 125 10} color 78 labelsize 12 align 18
-                      } {}
-                      Fl_Group {} {
-                        label {Intensity regions} open
-                        xywh {28 294 100 25} labelsize 12 labelcolor 136 align 20
-                      } {}
-                      Fl_Group {} {
-                        label {Image edges} open
-                        xywh {28 314 100 25} labelsize 12 labelcolor 136 align 148
-                      } {}
-                      Fl_Group {} {
-                        label {C. Press 'Next' to
-accept.} open
-                        xywh {10 476 125 25} labelsize 11 align 21
-                      } {}
-                    }
-                    Fl_Group m_GrpSNAPStepInitialize {
-                      label {Initialize Segmentation} open
-                      xywh {10 190 125 340} color 22 labeltype EMBOSSED_LABEL labelsize 12 labelcolor 4 hide
-                    } {
-                      Fl_Button m_BtnAddBubble {
-                        label {Add Bubble}
-                        callback {OnAddBubbleAction()}
-                        tooltip {Add bubble at cursor position (shortcut: +)} xywh {15 285 55 35} box PLASTIC_UP_BOX color 180 labelsize 11 align 128
-                      }
-                      Fl_Button m_BtnRemoveBubble {
-                        label {Remove Bubble}
-                        callback {OnRemoveBubbleAction()}
-                        tooltip {Remove highlighted bubble from list (shortcut: -)} xywh {75 285 55 35} box PLASTIC_UP_BOX color 180 labelsize 11 align 128
-                      }
-                      Fl_Value_Slider m_InBubbleRadius {
-                        label {Radius:}
-                        callback {o->take_focus();
-OnBubbleRadiusChange()}
-                        xywh {15 340 115 20} type Horizontal color 52 selection_color 197 labelsize 12 labelcolor 136 align 5 maximum 255 step 1 value 128
-                      }
-                      Fl_Browser m_BrsActiveBubbles {
-                        label {Active bubbles:}
-                        callback {OnActiveBubblesChange()}
-                        tooltip {Click a bubble to modify radius or remove} xywh {15 380 115 75} type Hold color 52 labelsize 12 labelcolor 136 align 5 textsize 9
-                      }
-                      Fl_Button m_BtnAcceptInitialization {
-                        label {  Next @-1>}
-                        callback {OnAcceptInitializationAction();}
-                        tooltip {Accept initialization, begin running snake} xywh {75 505 55 25} box PLASTIC_UP_BOX color 180 labelfont 1 labelsize 12 align 16
-                      }
-                      Fl_Button m_BtnRestartPreprocessing {
-                        label {@-1< Back  }
-                        callback {OnRestartPreprocessingAction();}
-                        tooltip {Accept initialization, begin running snake} xywh {15 505 55 25} box PLASTIC_UP_BOX color 180 labelsize 12 align 16
-                      }
-                      Fl_Group {} {
-                        label {A. Place bubbles in
-the image to initialize
-the active contour:} open
-                        xywh {10 235 125 45} labelsize 11 align 21
-                      } {}
-                      Fl_Group {} {
-                        label {Snake Initialization} open
-                        tooltip {In this step, the active contour is initialized. It can be initialized by placing bubbles (seeds) inside of the structure of interest. Alternatively, results from manual segmentation can be used as initialization.} xywh {10 190 125 40} box PLASTIC_DOWN_BOX color 90 labelsize 12 align 18
-                      } {
-                        Fl_Group {} {
-                          label {Step 2 of 3} open
-                          xywh {15 190 115 25} labelfont 1 align 16
-                        } {}
-                      }
-                      Fl_Group {} {
-                        label {B. Press 'Next' to begin segmentation:} open
-                        xywh {10 470 125 30} labelsize 11 align 149
-                      } {}
-                      Fl_Group {} {open
-                        xywh {10 455 125 10} color 90 labelsize 12 align 18
-                      } {}
-                    }
-                    Fl_Group m_GrpSNAPStepSegment {
-                      label {Perform Segmentation} open
-                      xywh {5 185 135 350} color 22 labeltype EMBOSSED_LABEL labelsize 12 labelcolor 4
-                    } {
-                      Fl_Output m_OutCurrentIteration {
-                        label {Iteration:}
-                        tooltip {Current iteration of active contour segmentation} xywh {80 425 50 20} color 52 selection_color 48 labelsize 12 labelcolor 136 align 5 textsize 10
-                      }
-                      Fl_Button m_BtnSnakeParameters {
-                        label {Set Parameters}
-                        callback {OnSnakeParametersAction();}
-                        tooltip {Change active contour evolution parameters} xywh {15 282 115 25} box PLASTIC_UP_BOX color 180 labelsize 12
-                      }
-                      Fl_Choice m_InStepSize {
-                        label {Step size:}
-                        callback {OnSnakeStepSizeChange();} open
-                        tooltip {Number of iterations per step - affects how often the screen updates} xywh {15 425 55 20} down_box BORDER_BOX color 52 selection_color 7 labelsize 12 labelcolor 136 align 5 textsize 10
-                      } {}
-                      Fl_Button m_BtnAcceptSegmentation {
-                        label Finish
-                        callback {OnAcceptSegmentationAction();}
-                        tooltip {Accept segmentation and return to the main program} xywh {75 505 55 25} box PLASTIC_UP_BOX color 180 labelfont 1 labelsize 12
-                      }
-                      Fl_Group m_GrpSnakeControl {
-                        label {Snake controls:} open
-                        xywh {15 375 120 30} labeltype NO_LABEL labelsize 12 labelcolor 136 align 5
-                      } {
-                        Fl_Button m_BtnSnakeRewind {
-                          label {@<<}
-                          callback {OnSnakeRewindAction();}
-                          tooltip {Reset the segmentation to the initial contour} xywh {15 377 28 25} box PLASTIC_UP_BOX color 180 align 18
-                        }
-                        Fl_Button m_BtnSnakePlay {
-                          label {@>}
-                          callback {OnSnakePlayAction();}
-                          tooltip {Iterate continuously} xywh {45 377 28 25} box PLASTIC_UP_BOX color 180 align 22
-                        }
-                        Fl_Button m_BtnSnakeStop {
-                          label {@square}
-                          callback {OnSnakeStopAction();}
-                          tooltip {Stop or pause active contour evolution} xywh {75 377 28 25} box PLASTIC_UP_BOX color 180 labelsize 8
-                        }
-                        Fl_Button m_BtnSnakeStep {
-                          label {@|>}
-                          callback {OnSnakeStepAction();}
-                          tooltip {Perform one step in active contour evolution} xywh {105 377 28 25} box PLASTIC_UP_BOX color 180 align 18
-                        }
-                      }
-                      Fl_Button m_BtnRestartInitialization {
-                        label {@-1< Back  }
-                        callback {OnRestartInitializationAction();}
-                        tooltip {Return to active contour initialization step} xywh {15 505 55 25} box PLASTIC_UP_BOX color 180 selection_color 48 labelsize 12 align 16
-                      }
-                      Fl_Group {} {
-                        label Segmentation open
-                        xywh {10 190 125 40} box PLASTIC_DOWN_BOX color 93 labelsize 12 align 18
-                      } {
-                        Fl_Group {} {
-                          label {Step 3 of 3} open
-                          xywh {15 190 115 25} labelfont 1 align 16
-                        } {}
-                      }
-                      Fl_Group {} {
-                        label {A. Edit the parameters
-of the snake evolution
-equation:} open
-                        xywh {10 235 125 40} labelsize 11 align 21
-                      } {}
-                      Fl_Group {} {
-                        label {B. Use the buttons below to control snake evolution:} open
-                        xywh {10 330 125 45} labelsize 11 align 149
-                      } {}
-                      Fl_Group {} {
-                        label {C. Press 'Finish' to
-accept segmentation:} open
-                        xywh {10 471 125 30} labelsize 11 align 21
-                      } {}
-                      Fl_Group {} {open
-                        xywh {10 315 125 10} box PLASTIC_DOWN_BOX color 93 labelsize 12 align 18
-                      } {}
-                      Fl_Group {} {open
-                        xywh {10 456 125 10} box PLASTIC_DOWN_BOX color 93 labelsize 12 align 18
-                      } {}
-                    }
-                  }
-                }
-                Fl_Group {} {
-                  label {Display Options} open
-                  xywh {5 560 135 110} box PLASTIC_UP_BOX color 22 labeltype EMBOSSED_LABEL labelsize 12 labelcolor 4
-                } {
-                  Fl_Value_Slider m_InSNAPLabelOpacity {
-                    label {Label opacity:}
-                    callback {o->take_focus();
-this->OnSNAPLabelOpacityChange();}
-                    tooltip {Transparency of the segmentation overlay} xywh {10 650 125 15} type Horizontal labelsize 12 align 5 maximum 255 step 1 value 128
-                  }
-                  Fl_Button m_BtnPreprocessedColorMap {
-                    label {Color Map}
-                    callback {OnPreprocessedColorMapAction();}
-                    tooltip {Change the color map used to display the 'speed' image} xywh {65 605 70 20} box PLASTIC_UP_BOX color 180 labelsize 11 align 144
-                  }
-                  Fl_Choice m_ChoiceSNAPView {open
-                    tooltip {Select whether to display the speed image or the original grayscale image} xywh {10 580 125 20} down_box BORDER_BOX labelsize 12 align 5 textsize 12 resizable
-                  } {
-                    MenuItem m_MenuSNAPViewOriginal {
-                      label {Original Grayscale}
-                      callback {OnSNAPViewOriginalSelect();}
-                      xywh {5 5 100 20} labelsize 11
-                    }
-                    MenuItem m_MenuSNAPViewPreprocessed {
-                      label {Preprocessed Image}
-                      callback {OnViewPreprocessedSelect();}
-                      xywh {15 15 100 20} labelsize 11
-                    }
-                  }
-                  Fl_Group {} {
-                    label {Image to display:} open
-                    xywh {10 565 125 15} labelsize 12 align 22
-                  } {}
-                }
-                Fl_Button m_BtnCancelSegmentation {
-                  label {Cancel Segmentation}
-                  callback {OnCancelSegmentationAction();}
-                  tooltip {Cancel segmentation and return} xywh {5 680 135 25} box PLASTIC_UP_BOX color 180 labelsize 12
-                }
-              }
-            }
-            Fl_Group {} {
-              label Spacer open
-              xywh {0 730 145 5} color 53 labeltype NO_LABEL resizable
-            } {}
-          }
-          Fl_Group m_GrpRightPanePlaceholderNormal {open
-            xywh {145 25 730 710} resizable
-          } {
-            Fl_Group m_GrpRightPane {open
-              xywh {145 25 730 710} box FLAT_BOX color 166
-            } {
-              Fl_Wizard {m_WizSliceLayout[0]} {open
-                xywh {145 25 365 355} box UP_BOX
-              } {
-                Fl_Group {m_GrpSliceLayoutNormal[0]} {open
-                  xywh {145 25 365 355}
-                } {
-                  Fl_Group {m_GrpSlicePlaceholder[0]} {
-                    xywh {150 30 333 320} resizable
-                  } {
-                    Fl_Box {m_SliceWindow[0]} {
-                      label {m_GrpIRISAxial(0)}
-                      xywh {150 30 333 320} box BORDER_BOX color 0 labelcolor 7
-                      code0 {\#include "FLTKCanvas.h"}
-                      class FLTKCanvas
-                    }
-                  }
-                  Fl_Group {m_GrpSliceToolbar[0]} {open
-                    xywh {145 350 365 30} color 48
-                  } {
-                    Fl_Button {m_BtnResetView[0]} {
-                      label {zoom to fit}
-                      callback {this->OnResetView2DAction(0);}
-                      tooltip {Restore the view to default zoom level} xywh {365 355 65 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 146
-                    }
-                    Fl_Output {m_OutSliceIndex[0]} {
-                      xywh {435 355 70 20} box FLAT_BOX color 49 align 0 textsize 10 deactivate
-                    }
-                    Fl_Wizard {m_WizPolygon[0]} {open selected
-                      xywh {150 350 210 30} box NO_BOX hide
-                    } {
-                      Fl_Group {m_GrpPolygonInit[0]} {open
-                        xywh {150 350 210 30} hide
-                      } {
-                        Fl_Button {m_BtnPolygonPaste[0]} {
-                          label {paste polygon}
-                          callback {OnPastePolygonAction(0);}
-                          tooltip {Paste the previously used polygon into the window} xywh {270 355 80 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                      }
-                      Fl_Group {m_GrpPolygonDraw[0]} {open
-                        xywh {150 350 210 30} hide
-                      } {
-                        Fl_Button {m_BtnPolygonClose[0]} {
-                          label {close loop}
-                          callback {OnClosePolygonAction(0);}
-                          tooltip {Connect last point to the first point and enter polygon editing mode} xywh {180 355 60 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonUndoPoint[0]} {
-                          label {undo point}
-                          callback {OnUndoPointPolygonAction(0);}
-                          tooltip {Remove the last point from the polygon} xywh {245 355 60 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonClearDrawing[0]} {
-                          label clear
-                          callback {OnClearPolygonAction(0);}
-                          tooltip {Clear the polygon so you can start over} xywh {310 355 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                      }
-                      Fl_Group {m_GrpPolygonEdit[0]} {open
-                        xywh {150 350 210 30}
-                      } {
-                        Fl_Button {m_BtnPolygonAccept[0]} {
-                          label accept
-                          callback {OnAcceptPolygonAction(0);}
-                          tooltip {Fill in the polygon using the currently selected label} xywh {175 355 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonInsert[0]} {
-                          label split
-                          callback {OnInsertIntoPolygonSelectedAction(0);}
-                          tooltip {Insert a new vertex between pairs of selected vertices} xywh {265 355 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonDelete[0]} {
-                          label delete
-                          callback {OnDeletePolygonSelectedAction(0);}
-                          tooltip {Delete the selected vertices} xywh {220 355 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonClearEditing[0]} {
-                          label clear
-                          callback {OnClearPolygonAction(0);}
-                          tooltip {Clear the polygon so you can start over} xywh {310 355 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                      }
-                    }
-                    Fl_Group {} {
-                      xywh {145 350 5 30} color 154 resizable
-                    } {}
-                  }
-                  Fl_Group {m_GrpSliceSidebar[0]} {
-                    xywh {485 30 21 320}
-                  } {
-                    Fl_Pack {} {open
-                      xywh {485 30 21 75}
-                    } {
-                      Fl_Button {m_BtnPanelZoom[0]} {
-                        label {@+}
-                        callback {OnWindowFocus(0);}
-                        tooltip {Expand this view to occupy the entire screen} xywh {486 30 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139 align 18
-                      }
-                      Fl_Group {} {open
-                        xywh {486 50 20 5}
-                      } {}
-                      Fl_Button {m_BtnPanelCollapse[0]} {
-                        label {@\#+19<-}
-                        callback {OnWindowCollapse(0);}
-                        tooltip {Collapse ITK-SNAP so only this view is shown} xywh {486 55 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139 align 18
-                      }
-                      Fl_Group {} {open
-                        xywh {486 75 20 5}
-                      } {}
-                      Fl_Button {m_BtnSaveAsPNG[0]} {
-                        callback {OnActiveWindowSaveSnapshot(0);}
-                        tooltip {Save a snapshot of this window as a PNG image} image {Artwork/screencapture.gif} deimage {Artwork/screencapture2.gif} xywh {486 80 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139 deactivate
-                      }
-                      Fl_Group {} {open
-                        xywh {486 100 20 5}
-                      } {}
-                    }
-                    Fl_Scrollbar {m_InSliceSlider[0]} {
-                      callback {OnSliceSliderChange(0);}
-                      xywh {487 105 18 245} box THIN_DOWN_BOX minimum 1 maximum 0 resizable
-                    }
-                  }
-                }
-                Fl_Group {m_GrpSliceLayoutTight[0]} {
-                  xywh {145 25 365 355} hide
-                } {}
-              }
-              Fl_Wizard {m_WizSliceLayout[1]} {open
-                xywh {510 25 365 355} box UP_BOX
-              } {
-                Fl_Group {m_GrpSliceLayoutNormal[1]} {open
-                  xywh {510 25 365 355}
-                } {
-                  Fl_Group {m_GrpSlicePlaceholder[1]} {open
-                    xywh {515 30 333 320} resizable
-                  } {
-                    Fl_Box {m_SliceWindow[1]} {
-                      label {m_GrpIRISSagittal(1)}
-                      xywh {515 30 333 320} box BORDER_BOX color 0 labelcolor 7
-                      code0 {\#include "FLTKCanvas.h"}
-                      class FLTKCanvas
-                    }
-                  }
-                  Fl_Group {m_GrpSliceToolbar[1]} {open
-                    xywh {510 350 365 30}
-                  } {
-                    Fl_Button {m_BtnResetView[1]} {
-                      label {zoom to fit}
-                      callback {this->OnResetView2DAction(1);}
-                      tooltip {Restore the view to default zoom level} xywh {730 355 62 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 146
-                    }
-                    Fl_Output {m_OutSliceIndex[1]} {
-                      xywh {797 355 70 20} box FLAT_BOX color 49 align 0 textsize 10 deactivate
-                    }
-                    Fl_Wizard {m_WizPolygon[1]} {open
-                      xywh {515 350 210 30} box NO_BOX hide
-                    } {
-                      Fl_Group {m_GrpPolygonInit[1]} {open
-                        xywh {515 350 210 30}
-                      } {
-                        Fl_Button {m_BtnPolygonPaste[1]} {
-                          label {paste polygon}
-                          callback {OnPastePolygonAction(1);}
-                          tooltip {Paste the previously used polygon into the window} xywh {635 355 80 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                      }
-                      Fl_Group {m_GrpPolygonDraw[1]} {
-                        xywh {515 350 210 30} hide
-                      } {
-                        Fl_Button {m_BtnPolygonClose[1]} {
-                          label {close loop}
-                          callback {OnClosePolygonAction(1);}
-                          tooltip {Connect last point to the first point and enter polygon editing mode} xywh {545 355 60 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonUndoPoint[1]} {
-                          label {undo point}
-                          callback {OnUndoPointPolygonAction(1);}
-                          tooltip {Remove the last point from the polygon} xywh {610 355 60 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonClearDrawing[1]} {
-                          label clear
-                          callback {OnClearPolygonAction(1);}
-                          tooltip {Clear the polygon so you can start over} xywh {675 355 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                      }
-                      Fl_Group {m_GrpPolygonEdit[1]} {open
-                        xywh {515 350 210 30} hide
-                      } {
-                        Fl_Button {m_BtnPolygonAccept[1]} {
-                          label accept
-                          callback {OnAcceptPolygonAction(1);}
-                          tooltip {Fill in the polygon using the currently selected label} xywh {540 355 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonInsert[1]} {
-                          label split
-                          callback {OnInsertIntoPolygonSelectedAction(1);}
-                          tooltip {Insert a new vertex between pairs of selected vertices} xywh {630 355 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonDelete[1]} {
-                          label delete
-                          callback {OnDeletePolygonSelectedAction(1);}
-                          tooltip {Delete the selected vertices} xywh {585 355 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonClearEditing[1]} {
-                          label clear
-                          callback {OnClearPolygonAction(1);}
-                          tooltip {Clear the polygon so you can start over} xywh {675 355 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                      }
-                    }
-                    Fl_Group {} {open
-                      xywh {510 350 5 30} color 154 resizable
-                    } {}
-                  }
-                  Fl_Group {m_GrpSliceSidebar[1]} {open
-                    xywh {850 30 23 320}
-                  } {
-                    Fl_Pack {} {open
-                      xywh {850 30 21 75}
-                    } {
-                      Fl_Button {m_BtnPanelZoom[1]} {
-                        label {@+}
-                        callback {OnWindowFocus(1);}
-                        tooltip {Expand this view to occupy the entire screen} xywh {851 30 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139
-                      }
-                      Fl_Group {} {open
-                        xywh {851 50 20 5}
-                      } {}
-                      Fl_Button {m_BtnPanelCollapse[1]} {
-                        label {@\#+19<-}
-                        callback {OnWindowCollapse(1);}
-                        tooltip {Collapse ITK-SNAP so only this view is shown} xywh {851 55 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139 align 18
-                      }
-                      Fl_Group {} {open
-                        xywh {851 75 20 5}
-                      } {}
-                      Fl_Button {m_BtnSaveAsPNG[1]} {
-                        callback {OnActiveWindowSaveSnapshot(1);}
-                        tooltip {Save a snapshot of this window as a PNG image} image {Artwork/screencapture.gif} deimage {Artwork/screencapture2.gif} xywh {851 80 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139 deactivate
-                      }
-                      Fl_Group {} {open
-                        xywh {851 100 20 5}
-                      } {}
-                    }
-                    Fl_Scrollbar {m_InSliceSlider[1]} {
-                      callback {this->OnSliceSliderChange(1);}
-                      xywh {852 105 18 245} box THIN_DOWN_BOX minimum 1 maximum 0 resizable
-                    }
-                  }
-                }
-                Fl_Group {m_GrpSliceLayoutTight[1]} {open
-                  xywh {510 25 365 355} hide
-                } {}
-              }
-              Fl_Wizard {m_WizSliceLayout[2]} {open
-                xywh {510 380 365 355} box UP_BOX
-              } {
-                Fl_Group {m_GrpSliceLayoutNormal[2]} {open
-                  xywh {510 380 365 355}
-                } {
-                  Fl_Group {m_GrpSlicePlaceholder[2]} {open
-                    xywh {515 385 333 320} resizable
-                  } {
-                    Fl_Box {m_SliceWindow[2]} {
-                      label {m_GrpIRISCoronal(2)}
-                      xywh {515 385 333 320} box BORDER_BOX color 0 labelcolor 7
-                      code0 {\#include "FLTKCanvas.h"}
-                      class FLTKCanvas
-                    }
-                  }
-                  Fl_Group {m_GrpSliceToolbar[2]} {open
-                    xywh {510 705 365 30}
-                  } {
-                    Fl_Button {m_BtnResetView[2]} {
-                      label {zoom to fit}
-                      callback {this->OnResetView2DAction(2);}
-                      tooltip {Restore the view to default zoom level} xywh {730 710 65 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 146
-                    }
-                    Fl_Output {m_OutSliceIndex[2]} {
-                      xywh {800 710 70 20} box FLAT_BOX color 49 align 0 textsize 10 deactivate
-                    }
-                    Fl_Wizard {m_WizPolygon[2]} {open
-                      xywh {515 705 210 30} box NO_BOX hide
-                    } {
-                      Fl_Group {m_GrpPolygonInit[2]} {open
-                        xywh {515 705 210 30}
-                      } {
-                        Fl_Button {m_BtnPolygonPaste[2]} {
-                          label {paste polygon}
-                          callback {OnPastePolygonAction(2);}
-                          tooltip {Paste the previously used polygon into the window} xywh {635 710 80 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                      }
-                      Fl_Group {m_GrpPolygonDraw[2]} {
-                        xywh {515 705 210 30} hide
-                      } {
-                        Fl_Button {m_BtnPolygonClose[2]} {
-                          label {close loop}
-                          callback {OnClosePolygonAction(2);}
-                          tooltip {Connect last point to the first point and enter polygon editing mode} xywh {545 710 60 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonUndoPoint[2]} {
-                          label {undo point}
-                          callback {OnUndoPointPolygonAction(2);}
-                          tooltip {Remove the last point from the polygon} xywh {610 710 60 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonClearDrawing[2]} {
-                          label clear
-                          callback {OnClearPolygonAction(2);}
-                          tooltip {Clear the polygon so you can start over} xywh {675 710 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                      }
-                      Fl_Group {m_GrpPolygonEdit[2]} {open
-                        xywh {515 705 210 30} hide
-                      } {
-                        Fl_Button {m_BtnPolygonAccept[2]} {
-                          label accept
-                          callback {OnAcceptPolygonAction(2);}
-                          tooltip {Fill in the polygon using the currently selected label} xywh {540 710 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonInsert[2]} {
-                          label split
-                          callback {OnInsertIntoPolygonSelectedAction(2);}
-                          tooltip {Insert a new vertex between pairs of selected vertices} xywh {630 710 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonDelete[2]} {
-                          label delete
-                          callback {OnDeletePolygonSelectedAction(2);}
-                          tooltip {Delete the selected vertices} xywh {585 710 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                        Fl_Button {m_BtnPolygonClearEditing[2]} {
-                          label clear
-                          callback {OnClearPolygonAction(2);}
-                          tooltip {Clear the polygon so you can start over} xywh {675 710 40 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 18
-                        }
-                      }
-                    }
-                    Fl_Group {} {open
-                      xywh {510 705 5 30} resizable
-                    } {}
-                  }
-                  Fl_Group {m_GrpSliceSidebar[2]} {open
-                    xywh {851 385 20 320}
-                  } {
-                    Fl_Pack {} {open
-                      xywh {851 385 20 75}
-                    } {
-                      Fl_Button {m_BtnPanelZoom[2]} {
-                        label {@+}
-                        callback {OnWindowFocus(2);}
-                        tooltip {Expand this view to occupy the entire screen} xywh {851 385 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139
-                      }
-                      Fl_Group {} {open
-                        xywh {851 405 20 5}
-                      } {}
-                      Fl_Button {m_BtnPanelCollapse[2]} {
-                        label {@\#+19<-}
-                        callback {OnWindowCollapse(2);}
-                        tooltip {Collapse ITK-SNAP so only this view is shown} xywh {851 410 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139 align 18
-                      }
-                      Fl_Group {} {open
-                        xywh {851 430 20 5}
-                      } {}
-                      Fl_Button {m_BtnSaveAsPNG[2]} {
-                        callback {OnActiveWindowSaveSnapshot(2);}
-                        tooltip {Save a snapshot of this window as a PNG image} image {Artwork/screencapture.gif} deimage {Artwork/screencapture2.gif} xywh {851 435 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139 deactivate
-                      }
-                      Fl_Group {} {open
-                        xywh {851 455 20 5}
-                      } {}
-                    }
-                    Fl_Scrollbar {m_InSliceSlider[2]} {
-                      callback {this->OnSliceSliderChange(2);}
-                      xywh {852 460 18 245} box THIN_DOWN_BOX minimum 1 maximum 0 resizable
-                    }
-                  }
-                }
-                Fl_Group {m_GrpSliceLayoutTight[2]} {open
-                  xywh {510 380 365 355} hide
-                } {}
-              }
-              Fl_Wizard {m_WizSliceLayout[3]} {open
-                xywh {145 380 365 355} box UP_BOX
-              } {
-                Fl_Group {m_GrpSliceLayoutNormal[3]} {open
-                  xywh {145 380 365 355}
-                } {
-                  Fl_Group {m_GrpSlicePlaceholder[3]} {open
-                    xywh {150 385 355 320} resizable
-                  } {
-                    Fl_Box {m_SliceWindow[3]} {
-                      label 3D
-                      xywh {150 385 355 320} box BORDER_BOX color 0 labelcolor 7
-                      class FLTKCanvas
-                    }
-                  }
-                  Fl_Group m_View3DToolbar {open
-                    xywh {145 705 365 30} color 214
-                  } {
-                    Fl_Pack m_ToolbarRenderWindow {open
-                      xywh {355 710 148 20} type HORIZONTAL color 80
-                    } {
-                      Fl_Button {m_BtnResetView[3]} {
-                        label {reset view}
-                        callback {OnMeshResetViewAction();}
-                        tooltip {Reset the 3D view to default zoom and camera position} xywh {355 710 65 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 146
-                      }
-                      Fl_Button {m_BtnSaveAsPNG[3]} {
-                        callback {OnActiveWindowSaveSnapshot(3);}
-                        tooltip {Save a snapshot of this window as a PNG image} image {Artwork/screencapture.gif} deimage {Artwork/screencapture2.gif} xywh {483 710 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139 deactivate
-                      }
-                      Fl_Button {m_BtnPanelCollapse[3]} {
-                        label {@\#+19<-}
-                        callback {OnWindowCollapse(3);}
-                        tooltip {Collapse ITK-SNAP so only this view is shown} xywh {458 710 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139
-                      }
-                      Fl_Button {m_BtnPanelZoom[3]} {
-                        label {@+}
-                        callback {OnWindowFocus(3);}
-                        tooltip {Expand this view to occupy the entire screen} xywh {433 710 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139
-                      }
-                    }
-                    Fl_Wizard m_WizRenderingToolbar {
-                      xywh {150 705 205 30} box NO_BOX
-                    } {
-                      Fl_Group m_GrpRenderingIRISPage {open
-                        xywh {150 705 205 30}
-                      } {
-                        Fl_Button m_BtnMeshUpdate {
-                          label {update mesh}
-                          callback {OnIRISMeshUpdateAction();}
-                          tooltip {Update the 3D rendering from the segmentation data} xywh {270 710 77 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 146
-                        }
-                        Fl_Button m_BtnAccept3D {
-                          label accept
-                          callback {OnIRISMeshAcceptAction();}
-                          tooltip {Apply the last 3D paint operation to the image} xywh {210 710 55 20} box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX color 180 selection_color 94 labelsize 10 align 146 deactivate
-                        }
-                      }
-                      Fl_Group m_GrpRenderingSNAPPage {open
-                        xywh {150 705 205 30} hide
-                      } {
-                        Fl_Button m_BtnSNAPCrosshairsMode3D {
-                          callback {SetToolbarMode3D(CROSSHAIRS_3D_MODE);}
-                          tooltip {3D crosshair tool: click on the segmentation to move cursor} image {Artwork/crosshair3Dtiny.gif} xywh {155 707 25 25} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0x63 color 180 selection_color 180 align 16
-                        }
-                        Fl_Button m_BtnSNAPTrackballMode3D {
-                          callback {SetToolbarMode3D(TRACKBALL_MODE);}
-                          tooltip {3D trackball tool: rotate, zoom and pan 3D view} image {Artwork/rotate3dTiny.gif} xywh {185 707 25 25} type Radio box PLASTIC_UP_BOX down_box PLASTIC_DOWN_BOX shortcut 0x63 value 1 color 180 selection_color 180 align 16
-                        }
-                        Fl_Button m_BtnSNAPMeshUpdate {
-                          label {update mesh}
-                          callback {OnSNAPMeshUpdateAction();}
-                          tooltip {Update the 3D mesh of the segmentation} xywh {220 710 75 20} box PLASTIC_UP_BOX color 180 labelsize 10 align 128 deactivate
-                        }
-                        Fl_Check_Button m_ChkContinuousView3DUpdate {
-                          label {auto-
-update}
-                          callback {OnSNAPMeshContinuousUpdateAction();}
-                          tooltip {Select this to have the mesh update automatically after every step in active contour evolution. This will slow down the program!} xywh {300 707 55 25} down_box DOWN_BOX labelsize 11 deactivate
-                        }
-                      }
-                    }
-                    Fl_Group {} {open
-                      xywh {145 705 5 30} resizable
-                    } {}
-                  }
-                }
-                Fl_Group {m_GrpSliceLayoutTight[3]} {open
-                  xywh {145 380 365 355} hide
-                } {}
-              }
-            }
-          }
-        }
-        Fl_Group m_GrpMainLayoutTight {open
-          xywh {0 0 875 735} hide
-        } {
-          Fl_Group m_GrpRightPanePlaceholderTight {open
-            xywh {0 0 875 735} resizable
-          } {}
-        }
-      }
-    }
-    Fl_Window m_WinSplash {
-      label {Welcome to ITK-SNAP}
-      xywh {60 512 430 195} type Double align 16 resizable visible
-    } {
-      Fl_Group {} {open
-        image {Artwork/logo_new.gif} xywh {5 5 420 155} color 0 align 16
-      } {}
-      Fl_Group m_OutSplashMessage {
-        label {Loading progress} open
-        xywh {5 165 420 25} box BORDER_BOX color 55 labelsize 11 align 20
-      } {}
-      Fl_Group {} {
-        label {Initializing...} open
-        xywh {325 15 95 20} labeltype ENGRAVED_LABEL align 24
-      } {}
-    }
-    Fl_Window m_WinProgress {
-      label {SNAP Progress Meter}
-      xywh {434 461 485 70} type Double box BORDER_BOX color 53 modal noborder visible
-    } {
-      Fl_Group {} {
-        label {Working... Please Wait!} open
-        xywh {0 0 480 25} labeltype EMBOSSED_LABEL labelfont 1 labelsize 12 align 16
-      } {}
-      Fl_Group {} {open
-        xywh {10 25 470 40} box ENGRAVED_BOX
-      } {
-        Fl_Slider m_OutProgressMeter {
-          xywh {20 35 395 20} type {Horz Fill} box PLASTIC_DOWN_BOX selection_color 62 align 16 maximum 100 step 0.1 value 50
-        }
-        Fl_Value_Output m_OutProgressCounter {
-          label {%}
-          xywh {420 35 40 20} color 7 labelsize 12 align 8 maximum 100 step 0.1 value 50 textsize 12
-        }
-      }
-    }
-    Fl_Window m_WinColorMap {
-      label {Preprocessed Image Color Map}
-      xywh {60 50 315 105} type Double non_modal visible
-    } {
-      Fl_Wizard m_WizColorMap {open
-        xywh {0 0 325 115}
-      } {
-        Fl_Group {m_GrpColorMapPage[0]} {open
-          xywh {0 0 315 105} hide
-        } {
-          Fl_Box {m_BoxColorMap[0]} {
-            xywh {15 25 285 25} box FLAT_BOX color 5 align 5
-            code0 {\#include "ColorMapBox.h"}
-            class ColorMapBox
-          }
-          Fl_Group {} {open
-            xywh {0 45 315 25}
-          } {
-            Fl_Group {} {
-              label {-1.0} open
-              xywh {0 45 35 25} labelsize 12 align 0
-            } {}
-            Fl_Group {} {
-              label {0.5} open
-              xywh {205 45 40 25} labelsize 12 align 0
-            } {}
-            Fl_Group {} {
-              label {-0.5} open
-              xywh {65 45 40 25} labelsize 12 align 0
-            } {}
-            Fl_Group {} {
-              label {0.0} open
-              xywh {135 45 40 25} labelsize 12 align 0
-            } {}
-            Fl_Group {} {
-              label {1.0} open
-              xywh {280 45 35 25} labelsize 12 align 0
-            } {}
-          }
-          Fl_Group {} {
-            label {Preprocessed image intensity:} open
-            xywh {15 5 285 20} labelsize 12 align 20
-          } {}
-          Fl_Button {} {
-            label Close
-            callback {OnColorMapCloseAction();}
-            xywh {235 75 65 25} box PLASTIC_UP_BOX color 180 labelfont 1 labelsize 12
-          }
-          Fl_Choice {m_ChoiceColorMap[0]} {
-            label {Color map:}
-            callback {OnColorMapSelectAction();} open
-            xywh {70 75 150 20} down_box BORDER_BOX labelsize 12 when 1 textsize 12
-          } {
-            MenuItem {} {
-              label {Black to White}
-              xywh {20 20 100 20} labelsize 11
-            }
-            MenuItem {} {
-              label {Blue -- Black -- White}
-              xywh {10 10 100 20} labelsize 11
-            }
-            MenuItem {} {
-              label {Blue -- White -- Red}
-              xywh {40 40 100 20} labelsize 11
-            }
-          }
-        }
-        Fl_Group {m_GrpColorMapPage[1]} {open
-          xywh {0 0 325 110}
-        } {
-          Fl_Box {m_BoxColorMap[1]} {
-            xywh {15 25 285 25} box FLAT_BOX color 5 align 5
-            code0 {\#include "ColorMapBox.h"}
-            class ColorMapBox
-          }
-          Fl_Group {} {open
-            xywh {0 45 315 25}
-          } {
-            Fl_Group {} {
-              label {0.0} open
-              xywh {0 45 35 25} labelsize 12 align 0
-            } {}
-            Fl_Group {} {
-              label {0.75} open
-              xywh {205 45 40 25} labelsize 12 align 0
-            } {}
-            Fl_Group {} {
-              label {0.25} open
-              xywh {65 45 40 25} labelsize 12 align 0
-            } {}
-            Fl_Group {} {
-              label {0.5} open
-              xywh {135 45 40 25} labelsize 12 align 0
-            } {}
-            Fl_Group {} {
-              label {1.0} open
-              xywh {280 45 35 25} labelsize 12 align 0
-            } {}
-          }
-          Fl_Group {} {
-            label {Preprocessed image intensity:} open
-            xywh {15 5 285 20} labelsize 12 align 20
-          } {}
-          Fl_Button {} {
-            label Close
-            callback {OnColorMapCloseAction();}
-            xywh {235 75 65 25} box PLASTIC_UP_BOX color 180 labelfont 1 labelsize 12
-          }
-          Fl_Choice {m_ChoiceColorMap[1]} {
-            label {Color map:}
-            callback {OnColorMapSelectAction();} open
-            xywh {70 75 150 20} down_box BORDER_BOX labelsize 12 when 1 textsize 12
-          } {
-            MenuItem {} {
-              label {Black to White}
-              xywh {30 30 100 20} labelsize 11
-            }
-            MenuItem {} {
-              label {Black -- Yellow -- White}
-              xywh {40 40 100 20} labelsize 11
-            }
-          }
-        }
-      }
-    }
-    Fl_Window m_WinAbout {
-      label {About ITK-SNAP}
-      xywh {523 551 430 195} type Double
-      code0 {\#include "FL/filename.H"} visible
-    } {
-      Fl_Group {} {open
-        image {Artwork/logo_new.gif} xywh {6 5 420 155} color 0 align 16
-      } {}
-      Fl_Group m_InAboutPageVersion {
-        label {Version X.XX
-Build Date X.XX} open
-        xywh {309 10 115 35} labeltype SHADOW_LABEL labelsize 11 align 153
-      } {}
-      Fl_Group {} {
-        label {ITK-SNAP on the web:} open
-        xywh {10 170 185 20} labelsize 12 align 24
-      } {}
-      Fl_Button {} {
-        label {http://www.itksnap.org}
-        xywh {200 170 220 20} box BORDER_FRAME down_box BORDER_FRAME color 176 selection_color 176 labelsize 12 labelcolor 176
-      }
-    }
-    Fl_Window m_WinConfirmDiscard {
-      label {Discard Unsaved Changes?}
-      callback {m_ChkHiddenDiscardChanges->value(0);
-m_WinConfirmDiscard->hide();} open
-      xywh {920 369 500 130} type Double box PLASTIC_DOWN_BOX modal visible
-    } {
-      Fl_Button {} {
-        label {Go Back}
-        callback {m_ChkHiddenDiscardChanges->value(0);
-m_WinConfirmDiscard->hide();}
-        xywh {250 90 90 30} box PLASTIC_UP_BOX color 180 labelfont 1 labelsize 12 hotspot
-      }
-      Fl_Button {} {
-        label {Discard Changes}
-        callback {m_ChkHiddenDiscardChanges->value(1);
-m_WinConfirmDiscard->hide();}
-        xywh {350 90 125 30} box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-      Fl_Group {} {
-        label {The changes you have made to the segmentation will be lost if you continue. Please confirm that you want to discard these changes, or press 'go back' in order to save the changes first.} open
-        xywh {85 15 400 70} align 149
-      } {}
-      Fl_Group {} {
-        label {!} open
-        xywh {15 20 55 55} box OFLAT_BOX color 224 selection_color 37 labelfont 9 labelsize 48 labelcolor 7 align 16
-      } {}
-      Fl_Check_Button m_ChkHiddenDiscardChanges {
-        label button
-        xywh {35 100 64 15} down_box DOWN_BOX hide deactivate
-      }
-    }
-    Fl_Window m_WinOpenDropped {
-      label {ITK-SNAP: Open Document}
-      xywh {461 285 530 310} type Double hide modal
-    } {
-      Fl_Group {} {
-        label {What should ITK-SNAP do with this image?} open
-        xywh {10 40 455 25} labelsize 12 align 20
-      } {}
-      Fl_Group {} {
-        label {A. Open it in the current window} open
-        xywh {15 90 500 50} box ENGRAVED_FRAME labelsize 12 align 5
-      } {
-        Fl_Button {} {
-          label {Load as Main Image}
-          callback {this->OnOpenDroppedAction(1);}
-          xywh {25 100 150 30} box PLASTIC_UP_BOX color 180 labelsize 12
-        }
-        Fl_Button {} {
-          label {Load as Segmentation}
-          callback {this->OnOpenDroppedAction(2);}
-          xywh {190 100 150 30} box PLASTIC_UP_BOX color 180 labelsize 12
-        }
-        Fl_Button {} {
-          label {Load as Overlay}
-          callback {this->OnOpenDroppedAction(3);}
-          xywh {355 100 150 30} box PLASTIC_UP_BOX color 180 labelsize 12
-        }
-      }
-      Fl_Group {} {
-        label {B. Open it in a new ITK-SNAP window} open
-        xywh {15 168 500 82} box ENGRAVED_FRAME labelsize 12 align 5
-      } {
-        Fl_Button {} {
-          label {Open in New ITK-SNAP}
-          callback {this->OnOpenDroppedAction(4);}
-          xywh {25 185 150 30} box PLASTIC_UP_BOX color 180 labelsize 12
-        }
-        Fl_Group {} {
-          label {Initial layout of new window:} open
-          xywh {190 200 305 50} labelsize 12 align 5
-        } {
-          Fl_Round_Button {m_InOpenDroppedViewMode[0]} {
-            label {Default 4-pane layout}
-            xywh {195 205 140 20} type Radio down_box ROUND_DOWN_BOX value 1 labelsize 12
-          }
-          Fl_Round_Button {m_InOpenDroppedViewMode[1]} {
-            label {Compact layout, axial}
-            xywh {195 225 140 20} type Radio down_box ROUND_DOWN_BOX labelsize 12
-          }
-          Fl_Round_Button {m_InOpenDroppedViewMode[2]} {
-            label {Compact layout, coronal}
-            xywh {345 205 150 20} type Radio down_box ROUND_DOWN_BOX labelsize 12
-          }
-          Fl_Round_Button {m_InOpenDroppedViewMode[3]} {
-            label {Compact layout, sagittal}
-            xywh {345 225 150 20} type Radio down_box ROUND_DOWN_BOX labelsize 12
-          }
-        }
-      }
-      Fl_Group m_OutOpenDroppedFileName {
-        label Filename open
-        xywh {15 31 490 1} box BORDER_FRAME color 35 labeltype ENGRAVED_LABEL labelfont 3 labelsize 16 align 5
-      } {}
-      Fl_Button {} {
-        label Cancel
-        callback {this->OnOpenDroppedAction(0);}
-        xywh {425 270 80 30} box PLASTIC_UP_BOX color 35 labelsize 12
-      }
-    }
-    Fl_Window m_WinStatistics {
-      label {ITK-SNAP Volumes and Statistics}
-      xywh {458 232 680 320} type Double hide resizable
-    } {
-      Fl_Button m_BtnStatisticsUpdate {
-        label Update
-        callback {OnStatisticsUpdateAction();}
-        xywh {85 285 120 25} box PLASTIC_UP_BOX color 180 labelfont 1 labelsize 12
-      }
-      Fl_Button m_BtnStatisticsExport {
-        label {Export to File...}
-        callback {OnStatisticsExportAction();}
-        xywh {345 285 120 25} box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-      Fl_Button m_BtnStatisticsClose {
-        label Close
-        callback {m_WinStatistics->hide();}
-        xywh {475 285 120 25} box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-      Fl_Box m_TableStatistics {
-        label {Segmentation volumes and statistics:
- }
-        xywh {10 40 660 231} color 53 selection_color 246 labeltype EMBOSSED_LABEL labelcolor 4 align 5 resizable
-        code0 {\#include "StatisticsTable.h"}
-        class StatisticsTable
-      }
-      Fl_Button m_BtnStatisticsCopy {
-        label {Copy to Clipboard}
-        callback {OnStatisticsCopyAction();}
-        xywh {215 285 120 25} box PLASTIC_UP_BOX shortcut 0x400063 color 180 labelsize 12
-      }
-    }
-    Fl_Window m_WinTestPop {
-      label Test open
-      xywh {1247 403 45 20} type Single align 2 non_modal noborder visible
-    } {
-      Fl_Button m_BtnCollapsedViewRestore {
-        label {@\#+11<-}
-        callback {this->OnMenuViewRestoreDefault();}
-        tooltip {Collapse ITK-SNAP so only this view is shown} xywh {2 2 20 20} box PLASTIC_UP_BOX color 180 labelsize 9 labelcolor 139 align 18
-        code0 {\#include "FL/Fl_Menu_Window.H"}
-      }
-      Fl_Button m_BtnCollapsedViewMenu {
-        label {...}
-        callback {this->OnCollapsedViewPopupMenu();}
-        tooltip {Display ITK-SNAP Main Menu} xywh {24 2 20 20} box PLASTIC_UP_BOX color 180 labelsize 12 labelcolor 139 align 18
-        code0 {\#include "FL/Fl_Menu_Window.H"}
-      }
-    }
-    Fl_Window m_WinPrecisionWarning {
-      label {Insufficient Precision Warning} open
-      xywh {344 409 495 155} type Double box PLASTIC_DOWN_BOX hide modal
-    } {
-      Fl_Button {} {
-        label Ok
-        callback {m_WinPrecisionWarning->hide();}
-        xywh {380 115 100 30} box PLASTIC_UP_BOX shortcut 0xff0d color 180 labelfont 1 labelsize 12 hotspot
-      }
-      Fl_Group {} {
-        label {The numerical precision of the image you loaded is greater than the 16 bit precision used by ITK-SNAP. Intensity values reported by ITK-SNAP will be approximate.} open
-        xywh {85 10 400 75} align 149
-      } {}
-      Fl_Group {} {
-        label {!} open
-        xywh {15 20 55 55} box OFLAT_BOX color 224 selection_color 37 labelfont 9 labelsize 48 labelcolor 7 align 16
-      } {}
-      Fl_Check_Button m_ChkPrecisionWarningDisable {
-        label {Do not show this warning again}
-        xywh {275 85 210 20} down_box DOWN_BOX labelsize 12
-      }
-      Fl_Button {} {
-        label {Learn more...}
-        callback {fl_open_uri("http://www.itksnap.org/pmwiki/pmwiki.php?n=Documentation.PrecisionWarning");}
-        xywh {270 115 100 30} box PLASTIC_UP_BOX color 180 labelsize 12
-      }
-    }
-  }
-} 
diff --git a/UserInterface/MainComponents/UserInterfaceBase.h b/UserInterface/MainComponents/UserInterfaceBase.h
deleted file mode 100644
index 1478033..0000000
--- a/UserInterface/MainComponents/UserInterfaceBase.h
+++ /dev/null
@@ -1,330 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: UserInterfaceBase.h,v $
-  Language:  C++
-  Date:      $Date: 2011/04/18 15:06:07 $
-  Version:   $Revision: 1.45 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __UserInterfaceBase__h_
-#define __UserInterfaceBase__h_
-
-// This should all be gone
-#include "SNAPCommonUI.h"
-#include "GlobalState.h" 
-#include "FL/Fl_Double_Window.H"
-
-// Borland compiler stuff. Note to whoever went through the code and added all 
-// these borland things: you just can't add ITK headers to headers like this one
-// that get included in lots of files. This makes compilation time insane!!!
-#if defined(__BORLANDC__)
-#include "SNAPBorlandDummyTypes.h"
-#endif
-
-// Forward refences to some classes
-class IRISApplication;
-class SystemInterface;
-class SNAPAppearanceSettings;
-class SliceWindowCoordinator;
-class Fl_Window;
-class Fl_Menu_Bar;
-class UserInterfaceLogic;
-struct Fl_Menu_Item;
-
-namespace itk {
-  class Object;
-};
-
-// Layout properties
-enum SliceViewConfiguration { FOUR_SLICE=0, AXIAL, SAGITTAL, CORONAL, THREED };
-
-enum WindowSize { FULL_SIZE, HALF_SIZE, CUSTOM_SIZE };
-
-struct DisplayLayout
-{
-  bool full_screen;
-  bool show_main_ui, show_panel_ui;
-  SliceViewConfiguration slice_config;
-  WindowSize size;
-  int fs_restore[4];
-};
-
-class SNAPMainWindow : public Fl_Double_Window
-{
-public:
-  SNAPMainWindow(int w, int h, const char *label=0)
-    : Fl_Double_Window(w,h,label) { m_ParentUI = NULL; }
-
-  SNAPMainWindow(int x, int y, int w, int h, const char *label=0)
-    : Fl_Double_Window(x,y,w,h,label) { m_ParentUI = NULL; }
-
-  virtual ~SNAPMainWindow() {}
-
-  void resize(int x, int y, int w, int h);
-
-  irisSetMacro(ParentUI, UserInterfaceLogic *);
-  irisGetMacro(ParentUI, UserInterfaceLogic *);
-
-private:
-  UserInterfaceLogic *m_ParentUI;
-};
-
-/**
- * \class UserInterfaceBase
- * \brief Base class for the main user interface.
- */
-class UserInterfaceBase {
-public:
-    virtual ~UserInterfaceBase(void) {} /* Needed to avoid compiler warning */
-
-  // Methods for switching between SNAP and IRIS modes
-  virtual void ShowIRIS() = 0;
-  virtual void ShowSNAP() = 0;
-  
-  // Method for exiting IRIS
-  virtual void OnMainWindowCloseAction() = 0;
-
-  // Methods that set the IRIS Toolbar and 3D Toolbar modes
-  virtual void SetToolbarMode(ToolbarModeType mode) = 0;
-  virtual void SetToolbarMode3D(ToolbarMode3DType mode) = 0;
-  
-  // Menu item callbacks
-  virtual void OnMenuNewSegmentation() = 0;
-  virtual void OnMenuLoadGrey() = 0;
-  virtual void OnMenuSaveGrey() = 0;
-  virtual void OnMenuSaveGreyROI() = 0;
-  virtual void OnMenuLoadRGB() = 0;
-  virtual void OnMenuLoadGreyOverlay() = 0;
-  virtual void OnMenuLoadRGBOverlay() = 0;
-  virtual void OnMenuUnloadOverlayLast() = 0;
-  virtual void OnMenuUnloadOverlays() = 0;
-  virtual void OnMenuLoadSegmentation() = 0;
-  virtual void OnMenuSaveSegmentation() = 0;
-  virtual void OnMenuSaveSegmentationMesh() = 0;
-  virtual void OnMenuSavePreprocessed() = 0;
-  virtual void OnMenuSaveLevelSet() = 0;
-  virtual void OnMenuLoadLabels() = 0;
-  virtual void OnMenuSaveLabels() = 0;
-  virtual void OnMenuSaveScreenshot(unsigned int iSlice) = 0;
-  virtual void OnMenuSaveScreenshotSeries(unsigned int iSlice) = 0;
-  virtual void OnMenuLoadAdvection() = 0;
-  virtual void OnMenuWriteVoxelCounts() = 0;
-  virtual void OnLoadRecentAction(unsigned int iRecent) = 0;
-  virtual void OnMenuIntensityCurve() = 0;
-  virtual void OnMenuColorMap() = 0;
-  virtual void OnMenuShowDisplayOptions() = 0;
-  virtual void OnMenuShowLayerInspector() = 0;
-  virtual void OnMenuExportSlice(unsigned int iSlice) = 0;
-  virtual void OnMenuImageInfo() = 0;
-  virtual void OnMenuReorientImage() = 0;
-  virtual void OnMenuShowVolumes() = 0;
-  virtual void OnMenuQuit() = 0;
-  virtual void OnMenuCheckForUpdate() = 0;
-  virtual void OnMenuResetAll() = 0;
-  virtual void OnMenuViewToggleUI() = 0;
-  virtual void OnMenuViewToggleFullscreen() = 0;
-  virtual void OnMenuViewRestoreDefault() = 0;
-  virtual void OnMenuLaunchNewInstance() = 0;
-
-  // IRIS: Slice selection actions
-  virtual void OnSliceSliderChange(int id) = 0;
-  virtual void UpdatePositionDisplay(int id) = 0;
-  virtual void OnSynchronizeCursorAction() = 0;
-
-  // IRIS: Zoom/pan interaction callbacks
-  virtual void OnResetView2DAction(unsigned int window) = 0;
-  virtual void OnResetAllViews2DAction() = 0;
-  virtual void OnLinkedZoomChange() = 0;
-  virtual void OnZoomLevelChange() = 0;
-  virtual void OnMultisessionZoomChange() = 0;
-  virtual void OnMultisessionPanChange() = 0;
-  
-  // IRIS: Color label selection and editing callbacks
-  virtual void OnDrawingLabelUpdate() = 0;
-  virtual void OnDrawOverLabelUpdate() = 0;
-  virtual void UpdateEditLabelWindow() = 0;
-  virtual void OnEditLabelsAction() = 0;
-  
-  // IRIS: Polygon buttons callbacks
-  virtual void OnClosePolygonAction(unsigned int window) = 0;
-  virtual void OnUndoPointPolygonAction(unsigned int window) = 0;
-  virtual void OnClearPolygonAction(unsigned int window) = 0;
-  virtual void OnAcceptPolygonAction(unsigned int window) = 0;
-  virtual void OnDeletePolygonSelectedAction(unsigned int window) = 0;
-  virtual void OnInsertIntoPolygonSelectedAction(unsigned int window) = 0;
-  virtual void OnPastePolygonAction(unsigned int window) = 0;
-  virtual void OnIRISFreehandFittingRateUpdate() = 0;
-
-  // IRIS: Paintbrush tools
-  virtual void OnPaintbrushAttributesUpdate() = 0;
-  virtual void OnPaintbrushPaint() = 0;
-  virtual void UpdatePaintbrushAttributes() = 0;
-
-  // IRIS: Annotation mode
-  virtual void OnAnnotationAttributesUpdate() = 0;
-
-  // IRIS: 3D Window callbacks
-  virtual void OnMeshResetViewAction() = 0;
-  virtual void OnIRISMeshUpdateAction() = 0;
-  virtual void OnIRISMeshAcceptAction() = 0;
-  
-  // IRIS: ROI manipulation callbacks
-  virtual void OnResetROIAction() = 0;
-  virtual void OnSnakeStartAction() = 0;
-
-  // SNAP Preprocessing page actions
-  virtual void OnInOutSnakeSelect() = 0;
-  virtual void OnEdgeSnakeSelect() = 0;
-  virtual void OnPreprocessAction() = 0;
-  virtual void OnPreprocessClose() = 0;
-  virtual void OnLoadPreprocessedImageAction() = 0;
-  virtual void OnAcceptPreprocessingAction() = 0;
-
-  // SNAP Color map operations
-  virtual void OnPreprocessedColorMapAction() = 0;
-  virtual void OnColorMapCloseAction() = 0;
-  virtual void OnColorMapSelectAction() = 0;
-
-  // SNAP Initialization page actions
-  virtual void OnAddBubbleAction() = 0;
-  virtual void OnRemoveBubbleAction() = 0;
-  virtual void OnActiveBubblesChange() = 0;
-  virtual void OnBubbleRadiusChange() = 0;
-  virtual void OnAcceptInitializationAction() = 0;
-  
-  // SNAP Segmentation page actions
-  virtual void OnRestartInitializationAction() = 0;
-  virtual void OnSnakeParametersAction() = 0;
-  virtual void OnAcceptSegmentationAction() = 0;
-  virtual void OnSnakeRewindAction() = 0;
-  virtual void OnSnakeStopAction() = 0;
-  virtual void OnSnakePlayAction() = 0;
-  virtual void OnSnakeStepAction() = 0;
-  virtual void OnSnakeStepSizeChange() = 0;
-  virtual void OnRestartPreprocessingAction() = 0;
-  virtual void OnCancelSegmentationAction() = 0;
-  
-  // SNAP: display interaction actions  
-  virtual void OnSNAPViewOriginalSelect() = 0;
-  virtual void OnViewPreprocessedSelect() = 0;
-  
-  virtual void UpdateMainLabel() = 0;
-
-  virtual void DeleteColorLabelMenu(Fl_Menu_Item *menu) = 0;
-  virtual Fl_Menu_Item *GenerateColorLabelMenu(bool,bool,bool) = 0;
-
-  // Opacity sliders
-  virtual void OnIRISLabelOpacityChange() = 0;
-  virtual void OnSNAPLabelOpacityChange() = 0;
-
-  // Undo/Redo buttons
-  virtual void OnUndoAction() = 0;
-  virtual void OnRedoAction() = 0;
-
-  // SNAP: 3D window related callbacks
-  virtual void OnSNAPMeshUpdateAction() = 0;
-  virtual void OnSNAPMeshContinuousUpdateAction() = 0;
-
-  // Volume and statistics actions
-  virtual void OnStatisticsUpdateAction() = 0;
-  virtual void OnStatisticsExportAction() = 0;
-  virtual void OnStatisticsCopyAction() = 0;
-
-  // virtual void Activate3DAccept(bool on) = 0;
-
-  // Help related callbacks
-  virtual void OnLaunchTutorialAction() = 0;
-  virtual void ShowHTMLPage(const char *link) = 0;
-
-  // Window size manipulation calls
-  virtual void OnWindowFocus(int i) = 0;
-  virtual void OnWindowCollapse(int i) = 0;
-
-  // Save as PNG
-  virtual void OnActiveWindowSaveSnapshot(unsigned int window) = 0;
-
-  // The following methods are not referenced in the .fl file, but are defined here
-  // so that other classes in the project can include UserInterfaceBase.h instead of
-  // UserInterfaceLogic.h; this way there is not a huge build every time we change
-  // a user interface element
-  virtual IRISApplication *GetDriver() const = 0;
-  virtual SystemInterface *GetSystemInterface() const = 0;
-  virtual SNAPAppearanceSettings *GetAppearanceSettings() const = 0;
-  virtual SliceWindowCoordinator *GetSliceCoordinator() const = 0;
-
-  virtual void OnMainImageUpdate() = 0;
-  virtual void OnOverlayImageUpdate() = 0;
-  virtual void OnImageGeometryUpdate() = 0;
-  virtual void RedrawWindows() = 0;
-  virtual void OnIRISMeshDisplaySettingsUpdate() = 0;
-  virtual void ResetScrollbars() = 0;
-  virtual void UpdateImageProbe() = 0;
-  virtual void OnLabelListUpdate() = 0;
-  virtual void OnSegmentationImageUpdate(bool) = 0;
-  virtual void CenterChildWindowInMainWindow(Fl_Window *) = 0;
-  virtual void OnPreprocessingPreviewStatusUpdate(bool) = 0;
-  virtual void OnSpeedImageUpdate() = 0;
-  virtual void OnCrosshairPositionUpdate(bool flagBroadcastUpdate = true) = 0;
-  virtual void OnViewPositionsUpdate(bool flagBroadcastUpdate = true) = 0;
-  virtual void OnTrackballUpdate(bool flagBroadcastUpdate = true) = 0;
-  virtual void OnPolygonStateUpdate(unsigned int) = 0;
-  virtual void OnZoomUpdate(bool flagBroadcastUpdate = true) = 0;
-  virtual void OnIRISMeshEditingAction() = 0;
-
-  // Progress callbacks
-  virtual void OnITKProgressEvent(itk::Object *source, const itk::EventObject &event) = 0;
-
-  // Non-callbacks
-  virtual double GetFreehandFittingRate() = 0;
-
-  virtual void StoreUndoPoint(const char *text) = 0;
-  virtual void ClearUndoPoints() = 0;
-  
-  virtual void OnHiddenFeaturesToggleAction() = 0;
-
-  virtual void DisplayTips() = 0;
-
-  virtual void OpenDraggedContent(const char *fn_open, bool interactive) = 0;
-  
-  virtual void OnOpenDroppedAction(int selection) = 0;
-
-  virtual DisplayLayout GetDisplayLayout() const = 0;
-  virtual void SetDisplayLayout(DisplayLayout dlo) = 0;
-
-  virtual Fl_Menu_Bar* GetMainMenuBar() = 0;
-  virtual Fl_Window* GetMainWindow() = 0;
-  virtual Fl_Window* GetPopupToolbarWindow() = 0;
-  
-  virtual void OnCollapsedViewPopupMenu() = 0;
-
-protected:
-    GlobalState *m_GlobalState;
-};
-
-#endif // __UserInterfaceBase__h_
diff --git a/UserInterface/MainComponents/UserInterfaceLogic.cxx b/UserInterface/MainComponents/UserInterfaceLogic.cxx
deleted file mode 100644
index 99f342d..0000000
--- a/UserInterface/MainComponents/UserInterfaceLogic.cxx
+++ /dev/null
@@ -1,7030 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: UserInterfaceLogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2011/05/04 15:25:42 $
-  Version:   $Revision: 1.124 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-// Borland compiler is very lazy so we need to instantiate the template
-//  by hand 
-#if defined(__BORLANDC__)
-#include "SNAPBorlandDummyTypes.h"
-#endif
-
-#if defined(_MSC_VER)
-#pragma warning ( disable : 4996 )
-#endif
-
-#ifdef __APPLE__
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-#include "FL/Fl.H"
-#include "FL/Fl_Native_File_Chooser.H"
-#include "FL/filename.H"
-#include "FL/x.H"
-
-#include "UserInterfaceLogic.h"
-
-#include "GlobalState.h"
-#include "GreyImageWrapper.h"
-#include "RGBImageWrapper.h"
-#include "EdgePreprocessingImageFilter.h"
-#include "LayerInspectorUILogic.h"
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-#include "IRISVectorTypesToITKConversion.h"
-#include "LabelEditorUILogic.h"
-#include "RestrictedImageIOWizardLogic.h"
-#include "SNAPImageData.h"
-#include "SNAPLevelSetDriver.h"
-#include "SNAPRegistryIO.h"
-#include "SmoothBinaryThresholdImageFilter.h"
-#include "SystemInterface.h"
-#include "IRISSliceWindow.h"
-#include "SNAPSliceWindow.h"
-#include "Window3D.h"
-
-
-// Additional UI component inludes
-#include "AppearanceDialogUILogic.h"
-#include "HelpViewerLogic.h"
-#include "PreprocessingUILogic.h"
-#include "SnakeParametersUILogic.h"
-#include "ResizeRegionDialogLogic.h"
-#include "RestoreSettingsDialogLogic.h"
-#include "ReorientImageUILogic.h"
-#include "MeshIOWizardUILogic.h"
-#include "SimpleFileDialogLogic.h"
-#include "SliceWindowCoordinator.h"
-#include "SNAPAppearanceSettings.h"
-#include "FLTKWidgetActivationManager.h"
-
-#include "itkImageIOBase.h"
-#include <itksys/SystemTools.hxx>
-// #include <strstream>
-#include <iomanip>
-#include <string>
-#include <vector>
-#include <cctype>
-
-// Global pointer to the 'current' UI object
-UserInterfaceLogic* UserInterfaceLogic::m_GlobalUI = NULL;
-
-// Disable some utterly annoying windows messages
-#if defined(_MSC_VER)
-#pragma warning ( disable : 4786 )
-#pragma warning ( disable : 4503 )
-#endif
-
-using namespace std;
-
-#define COLORBAR_LABEL FL_FREE_LABELTYPE
-
-void xyz_draw(const Fl_Label *label, int x, int y, int w, int h, Fl_Align align) {  
-  // We can't trust the label's color because it can be changed when the menu item
-  // is selected. Instead, we encode the color in the label itself using octal notation
-  unsigned int box_color;  
-  sscanf(label->value,"%x",&box_color);
-  fl_font(label->font, label->size);
-  fl_color((Fl_Color)label->color);
-  fl_draw(label->value + 9, x + h + label->size / 2, y, w-h, h, FL_ALIGN_LEFT);
-  fl_draw_box(FL_BORDER_BOX, x, y, h, h, (Fl_Color) box_color);
-}
-
-void xyz_measure(const Fl_Label *label, int &w, int &h) 
-{  
-  fl_font(label->font, label->size);
-  fl_measure(label->value + 9, w, h);
-  w += h + label->size / 2; 
-}
-
-/**
- * \class GreyImageInfoCallback
- * \brief Adapter for the interface ImageInfoCallbackInterface, used to 
- * pass on registry information to the IO Wizard.
- */
-class GreyImageInfoCallback : public ImageInfoCallbackInterface
-{
-public:
-    virtual ~GreyImageInfoCallback() {}
-  GreyImageInfoCallback(SystemInterface *system)
-    { m_SystemInterface = system; }
-
-  // This method finds the registry associated with a file
-  bool FindRegistryAssociatedWithImage(const char *file, Registry &registry)
-    { 
-    m_Registry.Clear();
-    if(!m_SystemInterface->FindRegistryAssociatedWithFile(file, m_Registry))
-      return false;
-    registry = m_Registry.Folder("Files.Grey");
-    return true;
-    }
-
-  // This method updates the registry with values that the user specified
-  void UpdateRegistryAssociatedWithImage(const char *file, Registry &folder)
-    {
-    // Create a registry into which to load the values
-    Registry regNew;
-    m_SystemInterface->FindRegistryAssociatedWithFile(file, regNew);
-
-    // Update the corresponding folder
-    regNew.Folder("Files.Grey").Update(folder);
-      
-    // Associate the settings
-    m_SystemInterface->AssociateRegistryWithFile(file, regNew);
-    }
-
-private:
-  SystemInterface *m_SystemInterface;
-  Registry m_Registry;
-};
-
-class UserInterfaceLogicMemberObserver : 
-  public FLTKWidgetActivationManager<UserInterfaceLogic::UIStateFlags>::Observer
-{
-public:
-  // Member function type
-  typedef void (UserInterfaceLogic::*TMemberFunctionPointer)(
-    UserInterfaceLogic::UIStateFlags flag, bool value);
-
-  // Constructor
-  UserInterfaceLogicMemberObserver(
-    UserInterfaceLogic *p, TMemberFunctionPointer member)
-    {
-    m_Pointer = p;
-    m_Member = member;
-    }
-
-  // Callback
-  void OnStateChange(UserInterfaceLogic::UIStateFlags flag, bool state)
-    {
-    if(m_Member && m_Pointer)
-      {
-      ((*m_Pointer).*(m_Member))(flag, state);
-      }
-    }
-private:
-  UserInterfaceLogic *m_Pointer;
-  TMemberFunctionPointer m_Member;
-};
-
-void UserInterfaceLogic
-::InitializeActivationFlags()
-{
-  unsigned int i;   
-  
-  // ---------------------------------------------------------
-  //    Intialize activation object
-  // ---------------------------------------------------------
-  m_Activation = new FLTKWidgetActivationManager<UIStateFlags>;
-  
-  // ---------------------------------------------------------
-  //    Configure Flag Relationships
-  // ---------------------------------------------------------
-  
-  // Set the parent-child relationships between flags
-  m_Activation->SetFlagImplies(UIF_SNAP_SPEED_AVAILABLE, UIF_SNAP_ACTIVE);
-  m_Activation->SetFlagImplies(UIF_SNAP_MESH_CONTINUOUS_UPDATE, UIF_SNAP_SNAKE_INITIALIZED);
-  m_Activation->SetFlagImplies(UIF_GRAY_LOADED, UIF_BASEIMG_LOADED);
-  m_Activation->SetFlagImplies(UIF_RGB_LOADED, UIF_BASEIMG_LOADED);
-  m_Activation->SetFlagImplies(UIF_IRIS_WITH_GRAY_LOADED, UIF_GRAY_LOADED);
-  m_Activation->SetFlagImplies(UIF_IRIS_WITH_BASEIMG_LOADED, UIF_BASEIMG_LOADED);
-  m_Activation->SetFlagImplies(UIF_IRIS_WITH_BASEIMG_LOADED, UIF_IRIS_ACTIVE);
-  m_Activation->SetFlagImplies(UIF_IRIS_WITH_GRAY_LOADED, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->SetFlagImplies(UIF_IRIS_MESH_DIRTY, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->SetFlagImplies(UIF_IRIS_MESH_ACTION_PENDING, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->SetFlagImplies(UIF_IRIS_ROI_VALID, UIF_GRAY_LOADED);
-  // m_Activation->SetFlagImplies(UIF_LINKED_ZOOM, UIF_BASEIMG_LOADED);
-  m_Activation->SetFlagImplies(UIF_SNAP_PREPROCESSING_ACTIVE, UIF_SNAP_ACTIVE);
-
-  m_Activation->SetFlagImplies(UIF_SNAP_PAGE_PREPROCESSING, UIF_SNAP_ACTIVE);
-  m_Activation->SetFlagImplies(UIF_SNAP_PAGE_BUBBLES, UIF_SNAP_ACTIVE);
-  m_Activation->SetFlagImplies(UIF_SNAP_PAGE_SEGMENTATION, UIF_SNAP_ACTIVE);
-
-  m_Activation->SetFlagImplies(UIF_SNAP_SNAKE_RUNNING, UIF_SNAP_SNAKE_INITIALIZED);
-  m_Activation->SetFlagImplies(UIF_SNAP_SNAKE_EDITABLE, UIF_SNAP_SNAKE_INITIALIZED);
-  m_Activation->SetFlagImplies(UIF_SNAP_SNAKE_EDITABLE, UIF_SNAP_SNAKE_RUNNING, true, false);
-  m_Activation->SetFlagImplies(UIF_SNAP_SNAKE_INITIALIZED, UIF_SNAP_ACTIVE);
-
-  m_Activation->SetFlagImplies(UIF_UNDO_POSSIBLE, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->SetFlagImplies(UIF_REDO_POSSIBLE, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->SetFlagImplies(UIF_UNSAVED_CHANGES, UIF_IRIS_WITH_BASEIMG_LOADED);
-
-  // Set up the exclusive relationships between flags
-  m_Activation->SetFlagImplies( UIF_SNAP_ACTIVE, UIF_IRIS_ACTIVE, true, false );
-  m_Activation->SetFlagImplies(UIF_SNAP_PREPROCESSING_DONE, 
-    UIF_SNAP_PREPROCESSING_ACTIVE, true, false );  
-  m_Activation->SetFlagsMutuallyExclusive( 
-    UIF_SNAP_PAGE_SEGMENTATION, 
-    UIF_SNAP_PAGE_BUBBLES, 
-    UIF_SNAP_PAGE_PREPROCESSING );
-
-  // ---------------------------------------------------------
-  //    Add observers to flags
-  // ---------------------------------------------------------
-  m_Activation->AddObserver(
-    new UserInterfaceLogicMemberObserver(
-      this, &UserInterfaceLogic::OnUnsavedChangesStateChange),
-    UIF_UNSAVED_CHANGES);
-
-  m_Activation->AddObserver(
-    new UserInterfaceLogicMemberObserver(
-      this, &UserInterfaceLogic::OnMeshAvailabilityStateChange),
-    UIF_IRIS_WITH_BASEIMG_LOADED);
-
-  m_Activation->AddObserver(
-    new UserInterfaceLogicMemberObserver(
-      this, &UserInterfaceLogic::OnMeshAvailabilityStateChange),
-    UIF_SNAP_SNAKE_INITIALIZED);
-
-  
-  // ---------------------------------------------------------
-  //    Relate flags to widgets
-  // ---------------------------------------------------------
-  
-  // Link widget activation to flags
-  m_Activation->AddWidget(m_BtnAcceptPreprocessing, UIF_SNAP_PREPROCESSING_DONE);
-  m_Activation->AddWidget(m_ChoiceSNAPView, UIF_SNAP_PREPROCESSING_DONE);
-  m_Activation->AddWidget(m_BtnPreprocessedColorMap, UIF_SNAP_SPEED_AVAILABLE);
-  m_Activation->AddWidget(m_BtnSNAPMeshUpdate, UIF_SNAP_SNAKE_INITIALIZED);
-  m_Activation->AddWidget(m_BtnMeshUpdate, UIF_IRIS_MESH_DIRTY);
-  m_Activation->AddWidget(m_BtnStartSnake, UIF_IRIS_ROI_VALID);
-  m_Activation->AddWidget(m_InZoomLevel, UIF_LINKED_ZOOM);
-  m_Activation->AddWidget(m_GrpLinkedZoomUnits, UIF_LINKED_ZOOM);
-  m_Activation->AddWidget(m_ChkMultisessionZoom, UIF_LINKED_ZOOM);
-  m_Activation->AddWidget(m_ChkMultisessionPan, UIF_LINKED_ZOOM);
-  m_Activation->AddWidget(m_BtnAccept3D, UIF_IRIS_MESH_ACTION_PENDING);
-
-  m_Activation->AddWidget(m_BtnAcceptSegmentation, UIF_SNAP_SNAKE_INITIALIZED);
-  m_Activation->AddWidget(m_BtnRestartInitialization, UIF_SNAP_SNAKE_INITIALIZED);
-  m_Activation->AddWidget(m_BtnSnakePlay, UIF_SNAP_SNAKE_EDITABLE);
-  m_Activation->AddWidget(m_BtnSnakeRewind, UIF_SNAP_SNAKE_INITIALIZED);
-  m_Activation->AddWidget(m_BtnSnakeStop, UIF_SNAP_SNAKE_INITIALIZED);
-  m_Activation->AddWidget(m_BtnSnakeStep, UIF_SNAP_SNAKE_INITIALIZED);
-
-  m_Activation->AddWidget(m_BtnIRISUndo, UIF_UNDO_POSSIBLE);
-  m_Activation->AddWidget(m_BtnIRISRedo, UIF_REDO_POSSIBLE);
-  m_Activation->AddWidget(m_BtnSNAPMode, UIF_GRAY_LOADED);
-
-  // Add more complex relationships
-  m_Activation->AddCheckBox(m_ChkContinuousView3DUpdate,
-    UIF_SNAP_SNAKE_INITIALIZED, false, false);
-
-  // Activate slice-related widgets indexed by dimension
-  for(i = 0; i < 3; i++)
-    {
-    m_Activation->AddWidget(m_InSliceSlider[i], UIF_BASEIMG_LOADED);
-    m_Activation->AddWidget(m_OutSliceIndex[i], UIF_BASEIMG_LOADED);
-    }
-
-  // Activate the widgets that have four copies
-  for(i = 0; i < 4; i++)
-    {
-    m_Activation->AddWidget(m_BtnSaveAsPNG[i], UIF_BASEIMG_LOADED);
-    m_Activation->AddWidget(m_BtnResetView[i], UIF_BASEIMG_LOADED);
-    m_Activation->AddWidget(m_BtnPanelZoom[i], UIF_BASEIMG_LOADED);
-    m_Activation->AddWidget(m_BtnPanelCollapse[i], UIF_BASEIMG_LOADED);
-    }
-
-  // Link menu items to flags
-  m_Activation->AddMenuItem(m_MenuLoadGrey, UIF_IRIS_ACTIVE);
-  m_Activation->AddMenuItem(m_MenuLoadRGB, UIF_IRIS_ACTIVE);
-  m_Activation->AddMenuItem(m_MenuExport, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuResetAll, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuSave, UIF_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuSaveGrey, UIF_IRIS_WITH_GRAY_LOADED);
-  m_Activation->AddMenuItem(m_MenuLoadGreyOverlay, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuUnloadOverlayLast, UIF_OVERLAY_LOADED);
-  m_Activation->AddMenuItem(m_MenuUnloadOverlays, UIF_OVERLAY_LOADED);
-  m_Activation->AddMenuItem(m_MenuLoadRGBOverlay, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuLoadSegmentation, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuNewSegmentation, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuSaveGreyROI, UIF_SNAP_ACTIVE);
-  m_Activation->AddMenuItem(m_MenuSaveSegmentation, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuSaveSegmentationMesh, UIF_MESH_SAVEABLE);
-  m_Activation->AddMenuItem(m_MenuSaveLabels, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuLoadLabels, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuSaveVoxelCounts, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuShowVolumes, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuSaveScreenshot, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuSaveScreenshotSeries, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuIntensityCurve, UIF_GRAY_LOADED);
-  m_Activation->AddMenuItem(m_MenuColorMap, UIF_GRAY_LOADED);
-  m_Activation->AddMenuItem(m_MenuExportSlice, UIF_GRAY_LOADED);
-  m_Activation->AddMenuItem(m_MenuSavePreprocessed, UIF_SNAP_PREPROCESSING_DONE);
-  m_Activation->AddMenuItem(m_MenuSaveLevelSet, UIF_SNAP_SNAKE_INITIALIZED);
-  m_Activation->AddMenuItem(m_MenuLoadAdvection, UIF_SNAP_PAGE_PREPROCESSING);
-  m_Activation->AddMenuItem(m_MenuImageInfo, UIF_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuReorientImage, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_ChoicePaintbrush[2], UIF_IRIS_WITH_GRAY_LOADED);
-  for (unsigned int i = 0; i < 5; i++)
-    {
-    m_Activation->AddMenuItem(m_MenuLoadPreviousFirst + i, UIF_IRIS_ACTIVE);
-    }
-  m_Activation->AddMenuItem(m_MenuLayerInspector, UIF_BASEIMG_LOADED);
-
-  // Toolbar menu items
-  m_Activation->AddMenuItem(m_MenuCrosshairsMode, UIF_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuZoomPanMode, UIF_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuPolygonMode, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuSNAPMode, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuPaintbrushMode, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuAnnotationMode, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuTrackballMode, UIF_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuCrosshair3DMode, UIF_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuScalpelMode, UIF_IRIS_WITH_BASEIMG_LOADED);
-  m_Activation->AddMenuItem(m_MenuSpraypaintMode, UIF_IRIS_WITH_BASEIMG_LOADED);
-}
-
-UserInterfaceLogic
-::UserInterfaceLogic(IRISApplication *iris)
-: UserInterface()
-{
-  // Initialize the menu lists to NULL
-  m_MenuDrawingLabels = NULL;
-  m_MenuDrawOverLabels = NULL;
-
-  // TODO: move this!
-  Fl::set_labeltype(COLORBAR_LABEL, xyz_draw, xyz_measure);
-
-  // Store the pointers to application and system high level objects
-  m_Driver = iris;
-  m_SystemInterface = iris->GetSystemInterface();
-
-  // This is just done for shorthand
-  m_GlobalState = iris->GetGlobalState();
-
-  // Load the appearance settings from the system interface
-  m_AppearanceSettings = new SNAPAppearanceSettings();
-  Registry &regAppearance = 
-    m_SystemInterface->Folder("UserInterface.AppearanceSettings");
-  m_AppearanceSettings->LoadFromRegistry(regAppearance);
-
-  // Instantiate the IO wizards
-  m_WizGreyIO = new ImageIOWizardLogic; 
-  m_WizSegmentationIO = new RestrictedImageIOWizardLogic;
-  m_WizPreprocessingIO = new RestrictedImageIOWizardLogic;
-  m_WizLevelSetIO = new RestrictedImageIOWizardLogic;
-
-  m_WizMeshExport = new MeshIOWizardUILogic;
-
-  // Allow only 3 components
-  m_WizSegmentationIO->SetNumberOfComponentsRestriction(1);
-  m_WizPreprocessingIO->SetNumberOfComponentsRestriction(1);
-  m_WizLevelSetIO->SetNumberOfComponentsRestriction(1); 
-
-  // Initialize the Image IO wizards
-  m_WizGreyIO->MakeWindow();
-  m_WizSegmentationIO->MakeWindow();
-  m_WizPreprocessingIO->MakeWindow();
-  m_WizLevelSetIO->MakeWindow();
-  m_WizMeshExport->MakeWindow();
-
-  // Provide the registry callback for the greyscale image wizard
-  m_GreyCallbackInterface = new GreyImageInfoCallback(m_SystemInterface);
-  m_WizGreyIO->SetImageInfoCallback(m_GreyCallbackInterface);
-
-  // Create the layer editor
-  m_LayerUI = new LayerInspectorUILogic(this);
-  m_LayerUI->MakeWindow();
-  m_LayerUI->Initialize();
-
-  // Create the label editor window
-  m_LabelEditorUI = new LabelEditorUILogic();
-  m_LabelEditorUI->MakeWindow();
-  m_LabelEditorUI->Register(this);
-
-  // Initialize the progress command
-  m_ProgressCommand = ProgressCommandType::New();
-  m_ProgressCommand->SetCallbackFunction(
-    this,&UserInterfaceLogic::OnITKProgressEvent);
-
-  // Initialize the preprocessing windows
-  m_PreprocessingUI = new PreprocessingUILogic;
-  m_PreprocessingUI->MakeWindow();
-  m_PreprocessingUI->Register(this);
-
-  // Initialize the snake parameter window
-  m_SnakeParametersUI = new SnakeParametersUILogic;
-  m_SnakeParametersUI->MakeWindow();
-  m_SnakeParametersUI->Register(this);
-
-  // Initialize the restore settings dialog
-  m_DlgRestoreSettings = new RestoreSettingsDialogLogic;
-  m_DlgRestoreSettings->MakeWindow();
-
-  // Initialize the resample dialog
-  m_DlgResampleRegion = new ResizeRegionDialogLogic;
-  m_DlgResampleRegion->MakeWindow();
-
-  // Initialize the appearance dialog
-  m_DlgAppearance = new AppearanceDialogUILogic;
-  m_DlgAppearance->MakeWindow();
-  m_DlgAppearance->Register(this);
-
-  // Initialize the reorientation dialog
-  m_DlgReorientImage = new ReorientImageUILogic;
-  m_DlgReorientImage->MakeWindow();
-  m_DlgReorientImage->Register(this);
-
-  // Create the window managers for SNAP and IRIS. Start in IRIS mode
-  for(int i=0; i<3; i++)
-    {    
-    m_IRISWindowManager2D[i] = new IRISSliceWindow(i, this, m_SliceWindow[i]);
-    m_SNAPWindowManager2D[i] = new SNAPSliceWindow(i, this, m_SliceWindow[i]);
-    m_SliceWindow[i]->PushInteractionMode(m_IRISWindowManager2D[i]);
-    }
-
-  // Create the 3D Window managers for SNAP and IRIS
-  m_IRISWindowManager3D = new Window3D(this, m_SliceWindow[3]);
-  m_SNAPWindowManager3D = new Window3D(this, m_SliceWindow[3]);
-  m_SliceWindow[3]->PushInteractionMode(m_IRISWindowManager3D);
-
-  // Initialize the slice window coordinator object
-  m_SliceCoordinator = new SliceWindowCoordinator();
-
-  // Group the three windows inside the window coordinator
-  m_SliceCoordinator->RegisterWindows(
-    reinterpret_cast<GenericSliceWindow **>(m_IRISWindowManager2D));    
-
-  // Create a callback command for the snake loop
-  m_PostSnakeCommand = SimpleCommandType::New();
-
-  // Initialize the Help UI
-  m_HelpUI = new HelpViewerLogic;
-  m_HelpUI->MakeWindow();
-  m_HelpUI->SetContentsLink(
-    m_SystemInterface->GetFileInRootDirectory("HTMLHelp/Tutorial.html").c_str());
-
-  //  Initialize the label IO dialog
-  m_DlgLabelsIO = new SimpleFileDialogLogic();
-  m_DlgLabelsIO->MakeWindow();
-  m_DlgLabelsIO->SetFileBoxTitle("Label description file:");
-  m_DlgLabelsIO->SetPattern("All Label Files\t*.{label,lbl,lab,txt}");
-  m_DlgLabelsIO->SetLoadCallback(this,&UserInterfaceLogic::OnLoadLabelsAction);
-  m_DlgLabelsIO->SetSaveCallback(this,&UserInterfaceLogic::OnSaveLabelsAction);
-
-  /** Write voxels dialog */
-  m_DlgVoxelCountsIO = new SimpleFileDialogLogic();
-  m_DlgVoxelCountsIO->MakeWindow();
-  m_DlgVoxelCountsIO->SetFileBoxTitle("Voxel count file:");
-  m_DlgVoxelCountsIO->SetPattern("Text files\t*.txt");
-  m_DlgVoxelCountsIO->SetSaveCallback(
-    this,&UserInterfaceLogic::OnWriteVoxelCountsAction);
-
-  // Set the welcome page to display
-  m_WizControlPane->value(m_GrpWelcomePage);
-
-  InitializeActivationFlags();
-  InitializeUI();
-
-  // Update the recent files menu
-  GenerateRecentFilesMenu();
-
-  // Enter the IRIS-ACTiVE state
-  m_Activation->UpdateFlag(UIF_IRIS_ACTIVE, true);
-
-  // Opacity toggle value set to default
-  m_OpacityToggleValue = 128;
-
-  // Configure the display layout
-  m_DisplayLayout.full_screen = false;
-  m_DisplayLayout.show_main_ui = true; 
-  m_DisplayLayout.show_panel_ui = true;
-  m_DisplayLayout.slice_config = FOUR_SLICE;
-  m_DisplayLayout.size = FULL_SIZE;
-
-  // Not fullscreen
-  m_FullScreen = false;
-
-}
-
-UserInterfaceLogic
-::~UserInterfaceLogic() 
-{
-  // Delete the menus
-  DeleteColorLabelMenu(m_MenuDrawingLabels);
-  DeleteColorLabelMenu(m_MenuDrawOverLabels);
-
-  // Delete the IO wizards
-  delete m_WizGreyIO;
-  delete m_WizSegmentationIO;
-  delete m_WizPreprocessingIO;
-  delete m_WizLevelSetIO;
-  delete m_WizMeshExport;
-
-  // Delete the IO wizard registry adaptor
-  delete m_GreyCallbackInterface;
-
-  // Other IO dialogs
-  delete m_DlgLabelsIO;
-  delete m_DlgVoxelCountsIO;
-
-  // Delete the UI's
-  delete m_SnakeParametersUI;
-  delete m_PreprocessingUI;
-  delete m_DlgRestoreSettings;
-  delete m_DlgResampleRegion;
-  delete m_DlgAppearance;
-  delete m_DlgReorientImage;
-  delete m_LabelEditorUI;
-  delete m_LayerUI;
-
-  // Delete the window managers
-  for(int i = 0; i < 3; i++)
-    {
-    delete m_IRISWindowManager2D[i];
-    delete m_SNAPWindowManager2D[i];
-    }
-  delete m_IRISWindowManager3D;
-  delete m_SNAPWindowManager3D;
-
-  // Delete the window coordinator
-  delete m_SliceCoordinator;
-
-  // Delete the appearance settings
-  delete m_AppearanceSettings;
-
-  // Delete the activation manager
-  delete m_Activation;
-}
-
-void 
-UserInterfaceLogic
-::OnResetROIAction()
-{
-  // requires grey image
-  if (!m_Driver->GetCurrentImageData()->IsGreyLoaded()) return;
-
-  // Get the grey image's region
-  GlobalState::RegionType roi = 
-    m_Driver->GetIRISImageData()->GetImageRegion();
-
-  // The region can not be empty!
-  assert(roi.GetNumberOfPixels() > 0);
-
-  // Set the Region of interest
-  m_GlobalState->SetSegmentationROI(roi);
-  m_GlobalState->SetIsValidROI(true);
-  
-  // Update the UI
-  RedrawWindows();
-}
-
-void
-UserInterfaceLogic
-::OnMenuResetAll()
-{
-  // Make sure the user doesn't lose any data
-  if(!PromptBeforeLosingChanges(REASON_RESET)) return;
-  
-  UnloadAllImages();
-  m_WizControlPane->value(m_GrpWelcomePage);
-  UpdateMainLabel();
-  RedrawWindows();
-}
-
-void
-UserInterfaceLogic
-::OnMenuViewToggleUI()
-{
-  this->ToggleDisplayElements();
-}
-
-void
-UserInterfaceLogic
-::OnMenuViewToggleFullscreen()
-{
-  this->ToggleFullScreen();
-}
-
-void
-UserInterfaceLogic
-::OnMenuViewRestoreDefault()
-{
-  DisplayLayout dl = m_DisplayLayout;
-  dl.full_screen = false;
-  dl.show_main_ui = true;
-  dl.show_panel_ui = true;
-  dl.slice_config = FOUR_SLICE;
-  dl.size = FULL_SIZE;
-  SetDisplayLayout(dl);
-}
-
-void
-UserInterfaceLogic
-::OnMenuLaunchNewInstance()
-{
-  std::list<std::string> args;
-  try
-    {
-    m_SystemInterface->LaunchChildSNAP(args);
-    }
-  catch(IRISException &exc)
-    {
-    fl_alert("Launching another SNAP instance failed.\nReason: %s", exc.what());
-    }
-}
-
-
-//--------------------------------------------
-//
-//
-// SEGMENT 3D BUTTON CALLBACK
-//
-//
-//--------------------------------------------
-
-unsigned int 
-UserInterfaceLogic
-::GetImageAxisForDisplayWindow(unsigned int window)
-{
-  return m_Driver->GetCurrentImageData()->
-    GetImageGeometry().GetDisplayToImageTransform(window).
-    GetCoordinateIndexZeroBased(2);
-}
-
-void 
-UserInterfaceLogic
-::OnSnakeStartAction()
-{
-  uchar index = m_GlobalState->GetDrawingColorLabel();
-
-  if (0 == index) 
-    {
-    fl_alert("Cannot start snake segmentation with clear color");
-    return;
-    }
-
-  if (!m_Driver->GetColorLabelTable()->GetColorLabel(index).IsVisible()) 
-    {
-    fl_alert("Current label must be visible to start snake segmentation");
-    return;
-    }
-
-  // Get the region of interest
-  SNAPSegmentationROISettings roi = m_GlobalState->GetSegmentationROISettings();
-
-  // The voxel size for the resampled region
-  Vector3d voxelSizeSrc(
-    m_Driver->GetCurrentImageData()->GetGrey()->GetImage()->GetSpacing().GetDataPointer());
-
-  // Check if the user wants to resample the image
-  if(m_ChkResampleRegion->value())
-    {
-    // Show the resampling dialog, updating the ROI object
-    m_DlgResampleRegion->DisplayDialog(voxelSizeSrc.data_block(), roi);
-    }
-  else
-    {
-    roi.SetVoxelScale(Vector3d(1.0));
-    roi.SetResampleFlag(false);
-    }
-
-  // Update the segmentation ROI
-  m_GlobalState->SetSegmentationROISettings(roi);
-
-  // The region can not be empty
-  assert(roi.GetROI().GetNumberOfPixels() > 0);
-
-  // Try allocating memory for snake
-  try 
-    {
-    m_Driver->InitializeSNAPImageData(roi,m_ProgressCommand);
-    }
-  catch(itk::MemoryAllocationError &)
-    {
-    fl_alert("Out of memory! Try using a smaller region of interest or subsampling.");
-    return;
-    }
-
-  // Set the current application image mode to SNAP data
-  m_Driver->SetCurrentImageDataToSNAP();
-
-  // Inform the global state that we're in sNAP
-  m_GlobalState->SetSNAPActive(true);
-
-  // Set bubble radius range according to volume dimensions (world dimensions)
-  Vector3ui size = m_Driver->GetCurrentImageData()->GetVolumeExtents();
-  Vector3d voxdims = m_Driver->GetSNAPImageData()->GetImageSpacing();
-  double mindim = 
-    vector_multiply_mixed<double,unsigned int,3>(voxdims, size).min_value();
-
-  // The largest value of the bubble radius is mindim / 2
-  double xBubbleMax = 0.5 * mindim ;
-
-  // The unit step should be equal or smaller than the smallest voxel edge length
-  // divided by two, and should be a power of 10. Since FLTK accepts rational step
-  // size, we compute it as a ratio two numbers
-  double xMinVoxelEdge = 0.5 * voxdims.min_value();
-  int xBubbleStepA = 1, xBubbleStepB = 1;
-  int xLogVoxelEdge = (int) floor(log10(xMinVoxelEdge));
-  if(xLogVoxelEdge > 0)
-    xBubbleStepA = (int)(0.5 + pow(10.0, xLogVoxelEdge));
-  else if(xLogVoxelEdge < 0)
-    xBubbleStepB = (int)(0.5 + pow(10.0, -xLogVoxelEdge));
-  
-  // It is likely however that 0.1 is not an appropriate step size when min 
-  // voxel size is 0.99, so we try 0.5 and 0.2 as candidates
-  if(xBubbleStepA * 5.0 / xBubbleStepB <= xMinVoxelEdge)
-    xBubbleStepA *= 5;
-  else if(xBubbleStepA * 2.0 / xBubbleStepB <= xMinVoxelEdge)
-    xBubbleStepA *= 2;
-
-  // Set the bubble min value
-  double xBubbleStep = xBubbleStepA * 1.0 / xBubbleStepB;
-  double xBubbleMin = xBubbleStep;
-
-  // Set the default value so that it falls on the step boundary
-  double xBubbleDefault = floor(0.25 * xBubbleMax / xBubbleStep) * xBubbleStep;
-
-  // Set the value for the radius slider
-  m_InBubbleRadius->range(xBubbleMin, xBubbleMax);
-  m_InBubbleRadius->step(xBubbleStepA, xBubbleStepB);
-  m_InBubbleRadius->value(xBubbleDefault);
-  m_InBubbleRadius->redraw();
-
-  // Use the current SnakeParameters to determine which type of snake to use
-  const SnakeParameters &parameters = m_GlobalState->GetSnakeParameters();
-  if(parameters.GetSnakeType() == SnakeParameters::EDGE_SNAKE)
-    {
-    m_RadSnakeEdge->set();
-    m_RadSnakeInOut->clear();
-    m_GlobalState->SetSnakeMode(EDGE_SNAKE);
-    OnEdgeSnakeSelect();
-    }
-  else
-    {
-    m_RadSnakeInOut->set();
-    m_RadSnakeEdge->clear();
-    m_GlobalState->SetSnakeMode(IN_OUT_SNAKE);
-    OnInOutSnakeSelect();
-    }
-  
-  // The edge preprocessing settings pass through unchanged
-  // Get the current thresholding properties
-  ThresholdSettings threshSettings = m_GlobalState->GetThresholdSettings();
-
-  // We want to keep the current preprocessing settings, but we have to be
-  // careful that they are in range of image intensity
-  GreyType iMax =  m_Driver->GetCurrentImageData()->GetGrey()->GetImageMax();
-  GreyType iMin =  m_Driver->GetCurrentImageData()->GetGrey()->GetImageMin();
-  if(threshSettings.GetUpperThreshold() > iMax)
-    threshSettings.SetUpperThreshold(iMax);
-  if(threshSettings.GetLowerThreshold() < iMin)
-    threshSettings.SetLowerThreshold(iMin);
-  m_GlobalState->SetThresholdSettings(threshSettings);
-
-
-  // This method basically sends the current button state from IRIS to SNAP
-  SyncSnakeToIRIS();
-
-  // Initialize GUI widgets 
-  // TODO: WTF is this?
-  m_ChoiceSNAPView->value(m_MenuSNAPViewOriginal);
-  // adioSNAPViewPreprocessed->value(0);
-  //RadioSNAPViewOriginal->value(1);
-  m_BtnAcceptInitialization->show();
-  m_BtnRestartInitialization->hide();
-
-  m_GlobalState->SetShowSpeed(false);
-
-  m_BrsActiveBubbles->clear();
-
-  uchar rgb[3];
-  m_Driver->GetColorLabelTable()->GetColorLabel(index).GetRGBVector(rgb);
-  m_GrpSNAPCurrentColor->color(fl_rgb_color(rgb[0], rgb[1], rgb[2]));
-  m_GrpSNAPCurrentColor->redraw();
-
-  m_SnakeStepSize = 1;
-  m_InStepSize->value(0);
-
-  // reset Mesh in IRIS window
-  m_IRISWindowManager3D->ClearScreen();
-
-  // Hide the label editor since it's open
-  m_LabelEditorUI->OnCloseAction();
-
-  // show the snake window, hide the IRIS window
-  ShowSNAP();
-
-  // We are going to preserve the cursor position if it was in the ROI
-  Vector3ui newCursor, oldCursor = m_Driver->GetCursorPosition();
-
-  // Image geometry has changed. This method also resets the cursor 
-  // position, which is something we don't want.
-  OnImageGeometryUpdate();
-
-  // So we reset the cursor position manually here if the cursor was in the ROI
-  if(roi.TransformImageVoxelToROIVoxel(oldCursor, newCursor))
-    {
-    m_Driver->SetCursorPosition(newCursor);
-    OnCrosshairPositionUpdate();
-    }
-}
-
-//--------------------------------------------
-//
-//
-// PREPROCESSING
-//
-//
-//--------------------------------------------
-void 
-UserInterfaceLogic
-::OnPreprocessAction()
-{
-  // Disable the 'Next' button on the preprocessing page
-  m_Activation->UpdateFlag(UIF_SNAP_PREPROCESSING_ACTIVE, true);
-
-  // Display the right window
-  if(m_GlobalState->GetSnakeMode() == EDGE_SNAKE)
-    {
-    m_PreprocessingUI->DisplayEdgeWindow();
-    }
-  else
-    {
-    m_PreprocessingUI->DisplayInOutWindow();
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnPreprocessClose()
-{
-  // Check if the preprocessing image has been computed
-  if(m_GlobalState->GetSpeedValid())
-    m_Activation->UpdateFlag(UIF_SNAP_PREPROCESSING_DONE, true);
-  else
-    {
-    m_Activation->UpdateFlag(UIF_SNAP_PREPROCESSING_ACTIVE, false);    
-    m_Activation->UpdateFlag(UIF_SNAP_SPEED_AVAILABLE, false);
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnAcceptPreprocessingAction()
-{  
-  SetActiveSegmentationPipelinePage(1);
-}
-
-void 
-UserInterfaceLogic
-::OnPreprocessedColorMapAction()
-{
-  // Set up mapping from color maps to menu items (TODO: this is hacky)
-  static std::map<ColorMapPreset, int> menuMap;
-  if(menuMap.size() == 0)
-    {
-    // Edge items
-    menuMap[COLORMAP_BLACK_BLACK_WHITE] = 0;
-    menuMap[COLORMAP_BLACK_YELLOW_WHITE] = 1;
-
-    // Region items
-    menuMap[COLORMAP_BLACK_GRAY_WHITE] = 0;
-    menuMap[COLORMAP_BLUE_BLACK_WHITE] = 1;    
-    menuMap[COLORMAP_BLUE_WHITE_RED] = 2;
-    }
-
-  // Select current color maps in the menus
-  m_ChoiceColorMap[0]->value(menuMap[m_GlobalState->GetSpeedColorMapInRegionMode()]);
-  m_ChoiceColorMap[1]->value(menuMap[m_GlobalState->GetSpeedColorMapInEdgeMode()]);
-
-  // Set the ranges for the color map boxes
-  m_BoxColorMap[0]->SetRange(-1.0, 1.0);
-  m_BoxColorMap[1]->SetRange(0.0, 1.0);
-
-  // Show the color map box and window
-  m_WinColorMap->show();
-
-  // Update the color map in the speed images
-  UpdateSpeedColorMap();
-}
-
-void 
-UserInterfaceLogic
-::OnColorMapCloseAction()
-{
-  m_WinColorMap->hide();
-}
-
-void 
-UserInterfaceLogic
-::OnColorMapSelectAction()
-{
-  // Mapping from edge menu items to color maps
-  static const ColorMapPreset edgeMenuMap[] = 
-    { COLORMAP_BLACK_BLACK_WHITE, COLORMAP_BLACK_YELLOW_WHITE };
-  static const ColorMapPreset regionMenuMap[] = 
-    { COLORMAP_BLACK_GRAY_WHITE, COLORMAP_BLUE_BLACK_WHITE, 
-      COLORMAP_BLUE_WHITE_RED };
-  
-  // Select the appropriate page in the color map window
-  ColorMapPreset xPreset =  
-    (m_GlobalState->GetSnakeMode() == EDGE_SNAKE) 
-    ? edgeMenuMap[m_ChoiceColorMap[1]->value()] 
-    : regionMenuMap[m_ChoiceColorMap[0]->value()] ;
-
-  // Set the current color map
-  m_GlobalState->SetSpeedColorMap(xPreset);
-
-  // Update the display
-  UpdateSpeedColorMap();
-}
-
-
-void 
-UserInterfaceLogic
-::UpdateSpeedColorMap()
-{
-  // Get the index of the color map box to update
-  int iBox = (m_GlobalState->GetSnakeMode() == EDGE_SNAKE) ? 1 : 0;
-
-  // Select the appropriate page in the color map window
-  m_WizColorMap->value(m_GrpColorMapPage[iBox]);
-
-  // Apply the color map to the preview window
-  m_BoxColorMap[iBox]->SetColorMap(
-    SpeedColorMap::GetPresetColorMap(
-      m_GlobalState->GetSpeedColorMap()));
-  m_BoxColorMap[iBox]->redraw();
-
-  // Apply the color map to the speed wrapper
-  if(m_Driver->GetSNAPImageData()->IsSpeedLoaded())
-    m_Driver->GetSNAPImageData()->GetSpeed()->
-      SetColorMap(SpeedColorMap::GetPresetColorMap(
-        m_GlobalState->GetSpeedColorMap()));
-
-  // Also, apply the color map to the SNAP preview window
-  if(m_Driver->GetSNAPImageData()->IsSpeedLoaded())
-    m_SnakeParametersUI->OnSpeedColorMapUpdate();
-
-  // If the color map window is showing, show the color boxes
-  if(m_WinColorMap->shown())
-    {
-    m_BoxColorMap[1 - iBox]->hide();
-    m_BoxColorMap[iBox]->show();
-    }
-
-  // Redraw the windows
-  RedrawWindows();
-}
-
-
-void 
-UserInterfaceLogic
-::OnPreprocessingPreviewStatusUpdate(bool flagPreview)
-{
-  // Enable the preprocessing widgets and color map button
-  m_Activation->UpdateFlag(UIF_SNAP_SPEED_AVAILABLE, flagPreview);
-  
-  // Make sure that the preview mode is used
-  m_ChoiceSNAPView->value(flagPreview ? 
-    m_MenuSNAPViewPreprocessed : m_MenuSNAPViewOriginal);
-
-  // Set whether speed is shown
-  m_GlobalState->SetShowSpeed(flagPreview);
-
-  // Redraw the windows
-  RedrawWindows();
-}
-
-//--------------------------------------------
-//
-//
-// SWITCH BETWEEN GREY/PREPROC DATA
-//
-//
-//--------------------------------------------
-
-void 
-UserInterfaceLogic
-::OnSNAPViewOriginalSelect()
-{
-  m_GlobalState->SetShowSpeed(false);
-  RedrawWindows();
-}
-
-void 
-UserInterfaceLogic
-::OnViewPreprocessedSelect()
-{
-  if (!m_GlobalState->GetSpeedValid())
-    return;
-  m_GlobalState->SetShowSpeed(true);
-  RedrawWindows();
-}
-
-//--------------------------------------------
-//
-//
-// BUBBLES
-//
-//
-//--------------------------------------------
-
-void 
-UserInterfaceLogic
-::UpdateBubbleUI()
-{
-  // Fill the array of values
-  m_BrsActiveBubbles->clear();
-  GlobalState::BubbleArray ba = m_GlobalState->GetBubbleArray();
-  for(unsigned int i = 0; i < ba.size(); i++)
-    {
-    std::ostringstream oss;
-    oss << "C=" << ba[i].center << "; ";
-    oss << "R=" << std::setprecision(3) << ba[i].radius;
-    m_BrsActiveBubbles->add(oss.str().c_str());
-    }
-  
-  // Get the active bubble
-  int ibub = m_GlobalState->GetActiveBubble();
-  
-  // The browser uses 1-based indexing, so we add 1
-  m_BrsActiveBubbles->value(ibub + 1);
-
-  // Set the radius slider
-  if(ibub >= 0)
-    m_InBubbleRadius->value(ba[ibub].radius);
-
-  // Redraw the browser
-  m_BrsActiveBubbles->redraw();  
-
-  // Redraw the windows as well
-  RedrawWindows();
-}
-
-void 
-UserInterfaceLogic
-::OnAddBubbleAction()
-{
-  // Create a new bubble
-  Bubble bub;
-  bub.center = to_int(m_Driver->GetCursorPosition());
-  bub.radius = m_InBubbleRadius->value();
-
-  // Add the bubble to the global state
-  GlobalState::BubbleArray ba = m_GlobalState->GetBubbleArray();
-  ba.push_back(bub);
-  m_GlobalState->SetBubbleArray(ba);
-
-  // Set the bubble's position
-  m_GlobalState->SetActiveBubble(ba.size() - 1);
-
-  // Update the bubble list in the GUI
-  UpdateBubbleUI();
-}
-
-void 
-UserInterfaceLogic
-::OnRemoveBubbleAction()
-{
-  int ibub = m_GlobalState->GetActiveBubble();
-  if(ibub >= 0) 
-    {
-    // Remove the bubble from the global state
-    GlobalState::BubbleArray ba = m_GlobalState->GetBubbleArray();
-    ba.erase(ba.begin() + ibub);
-    m_GlobalState->SetBubbleArray(ba);
-
-    // Update the active bubble
-    if(ibub == (int) ba.size())
-      m_GlobalState->SetActiveBubble(ibub - 1);
-
-    // Update the bubble list in the GUI
-    UpdateBubbleUI();
-    } 
-  else
-    {
-    fl_alert("To remove a bubble, first select a bubble in the list.");
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnActiveBubblesChange()
-{
-  // Set the active bubble in the global state
-  m_GlobalState->SetActiveBubble(m_BrsActiveBubbles->value() - 1);
-
-  // Update the user interface
-  UpdateBubbleUI();
-}
-
-void 
-UserInterfaceLogic
-::OnBubbleRadiusChange()
-{
-  int ibub = m_GlobalState->GetActiveBubble();
-  if(ibub >= 0)
-    {
-    // Update the bubble in the global state
-    GlobalState::BubbleArray ba = m_GlobalState->GetBubbleArray();
-    ba[ibub].radius = m_InBubbleRadius->value();
-    m_GlobalState->SetBubbleArray(ba);
-
-    // Update the bubble list in the GUI
-    UpdateBubbleUI();
-    }
-}
-
-//--------------------------------------------
-//
-//
-// SNAKE TYPE RADIO BUTTONS
-//
-//
-//--------------------------------------------
-
-void 
-UserInterfaceLogic
-::OnInOutSnakeSelect()
-{
-  m_RadSnakeInOut->set();
-  m_RadSnakeEdge->clear();
-  m_GlobalState->SetSnakeMode(IN_OUT_SNAKE);
-
-  //Nathan Moon
-  if (m_GlobalState->GetSpeedValid()) 
-    {
-    //make sure they want to do this
-    //fl_ask is deprecated if (0 == fl_ask("Preprocessed data will be lost!  Continue?"))
-    if (0 == fl_choice("Preprocessed data will be lost!  Continue?","No","Yes",NULL))
-      {
-      m_RadSnakeInOut->clear();
-      m_RadSnakeEdge->set();
-      m_GlobalState->SetSnakeMode(EDGE_SNAKE);
-      return;
-      }
-    }
-
-  // Set parameters to default values
-  m_GlobalState->SetSnakeParameters(
-    SnakeParameters::GetDefaultInOutParameters());
-
-  m_Driver->GetSNAPImageData()->ClearSpeed();
-
-  m_GlobalState->SetSpeedValid(false);
-
-  // Update widget state
-  m_Activation->UpdateFlag(UIF_SNAP_SPEED_AVAILABLE, false);
-  m_Activation->UpdateFlag(UIF_SNAP_PREPROCESSING_DONE, false);
-
-  m_PreprocessingUI->HidePreprocessingWindows();
-
-  // Set the SNAP view to the grayscale mode
-  m_ChoiceSNAPView->value(m_MenuSNAPViewOriginal);
-  OnSNAPViewOriginalSelect();
-
-  // Update the speed color map
-  UpdateSpeedColorMap();
-  
-  // m_RadioSNAPViewOriginal->setonly();
-}
-
-void 
-UserInterfaceLogic
-::OnEdgeSnakeSelect()
-{
-  m_RadSnakeEdge->set();
-  m_RadSnakeInOut->clear();
-  m_GlobalState->SetSnakeMode(EDGE_SNAKE);
-
-  //Nathan Moon
-  if (m_GlobalState->GetSpeedValid()) 
-    {
-    //make sure they want to do this
-    //fl_ask is deprecated if (0 == fl_ask("Preprocessed data will be lost!  Continue?")) 
-    if (0 == fl_choice("Preprocessed data will be lost!  Continue?","No","Yes",NULL))
-      {
-      m_RadSnakeInOut->set();
-      m_RadSnakeEdge->clear();
-      m_GlobalState->SetSnakeMode(IN_OUT_SNAKE);
-      return;
-      }
-    }
-
-  // Set parameters to default values
-  m_GlobalState->SetSnakeParameters(
-    SnakeParameters::GetDefaultEdgeParameters());
-
-  if (m_Driver->GetSNAPImageData()) m_Driver->GetSNAPImageData()->ClearSpeed();
-  m_GlobalState->SetSpeedValid(false);
-  
-  // Update widget state
-  m_Activation->UpdateFlag(UIF_SNAP_SPEED_AVAILABLE, false);
-  m_Activation->UpdateFlag(UIF_SNAP_PREPROCESSING_DONE, false);
-  
-  m_PreprocessingUI->HidePreprocessingWindows();
-  
-  // Set the SNAP view to the grayscale mode
-  m_ChoiceSNAPView->value(m_MenuSNAPViewOriginal);
-  OnSNAPViewOriginalSelect();
-  
-  // Update the speed color map
-  UpdateSpeedColorMap();
-  
-  // m_RadioSNAPViewOriginal->setonly();
-}
-
-/*
- * This method is called when the user has finished adding bubbles
- */
-void 
-UserInterfaceLogic
-::OnAcceptInitializationAction()
-{
-  // Get bubbles, turn them into segmentation
-  vector<Bubble> bubbles = m_GlobalState->GetBubbleArray();
-
-  // Shorthand
-  SNAPImageData *snapData = m_Driver->GetSNAPImageData();
-
-  // Put on a wait cursor
-  // TODO: Progress bar is needed here
-  m_WinMain->cursor(FL_CURSOR_WAIT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-
-  // Merge bubbles with the segmentation image and initialize the snake
-  bool rc = snapData->InitializeSegmentation(
-    m_GlobalState->GetSnakeParameters(), bubbles, 
-    m_GlobalState->GetDrawingColorLabel());
-
-  // Restore the cursor
-  m_WinMain->cursor(FL_CURSOR_DEFAULT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-  
-  // Check if we need to bail out
-  if (!rc) 
-    {    
-    // There were no voxels selected in the end
-    fl_alert("Can not proceed without an initialization\n"
-             "Please place a bubble into the image!");
-    return;        
-    } 
-
-  m_BtnAcceptInitialization->hide();
-  m_BtnRestartInitialization->show();
-
-  // Set the UI for the segmentation state
-  m_Activation->UpdateFlag(UIF_SNAP_SNAKE_EDITABLE, true);
-  
-  m_SNAPWindowManager3D->ClearScreen(); // reset Mesh object in Window3D_s
-  m_SNAPWindowManager3D->ResetView();   // reset cursor
-
-  // Flip to the next page in the wizard
-  SetActiveSegmentationPipelinePage(2);
-
-  m_GlobalState->SetSnakeActive(true);
-
-  OnSnakeUpdate();
-}
-
-
-void 
-UserInterfaceLogic
-::SetActiveSegmentationPipelinePage(unsigned int page)
-{
-  switch(page)
-    {
-    case 0 : 
-      m_WizSegmentationPipeline->value(m_GrpSNAPStepPreprocess);
-      m_Activation->UpdateFlag(UIF_SNAP_PAGE_PREPROCESSING, true);
-      break;
-
-    case 1 :
-      m_WizSegmentationPipeline->value(m_GrpSNAPStepInitialize);
-      m_Activation->UpdateFlag(UIF_SNAP_PAGE_BUBBLES, true);
-      break;
-
-    case 2 :
-      m_WizSegmentationPipeline->value(m_GrpSNAPStepSegment);
-      m_Activation->UpdateFlag(UIF_SNAP_PAGE_SEGMENTATION, true);
-      break;
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnRestartInitializationAction()
-{
-  // Stop the segmentation if it's running
-  OnSnakeStopAction();
-  
-  // If the segmentation pipeline is active, deactivate it
-  if(m_Driver->GetSNAPImageData()->IsSegmentationActive())
-    {
-    // Tell the update loop to terminate
-    m_Driver->GetSNAPImageData()->TerminateSegmentation();
-    }
-
-  // Tell the UI to activate related widgets
-  m_Activation->UpdateFlag(UIF_SNAP_SNAKE_INITIALIZED, false);
-
-  m_GlobalState->SetSnakeActive(false);
-  m_BtnRestartInitialization->hide();
-  m_BtnAcceptInitialization->show();
-
-  m_SNAPWindowManager3D->ClearScreen(); // reset Mesh object in Window3D_s
-  m_SNAPWindowManager3D->ResetView();   // reset cursor
-  RedrawWindows();
-
-  // Flip to the second page
-  SetActiveSegmentationPipelinePage(1);
-}
-
-void
-UserInterfaceLogic
-::OnRestartPreprocessingAction()
-{
-  // Reset the active bubble (if there are any)
-  m_GlobalState->SetActiveBubble(
-    m_GlobalState->GetBubbleArray().size() > 0 ? 0 : -1);
-
-  // Flip to the first page
-  SetActiveSegmentationPipelinePage(0);
-
-  // Repaint the screen and the bubbles
-  UpdateBubbleUI();
-}
-
-void 
-UserInterfaceLogic
-::OnSnakeParametersAction()
-{
-  // Get the current parameters from the system
-  SnakeParameters pGlobal = m_GlobalState->GetSnakeParameters();
-  
-  // Send current parameter to the snake parameter setting UI
-  m_SnakeParametersUI->SetParameters(pGlobal);
-
-  // Chech whether we need to warn user about changing the solver in the 
-  // process of evolution
-  m_SnakeParametersUI->SetWarnOnSolverUpdate(
-    m_Driver->GetSNAPImageData()->GetElapsedSegmentationIterations() > 0);
-  
-  // Show the snake parameters window
-  CenterChildWindowInParentWindow(m_SnakeParametersUI->GetWindow(),m_WinMain);
-  m_SnakeParametersUI->DisplayWindow();
-  
-  // Wait until the window has been closed
-  while(m_SnakeParametersUI->GetWindow()->visible())
-    Fl::wait();
-    
-  // Have the parameters been accepted by the user?
-  if(m_SnakeParametersUI->GetUserAccepted())
-    {
-    // Get the new parameters
-    SnakeParameters pNew = m_SnakeParametersUI->GetParameters();
-    
-    // Have the parameters changed?
-    if(!(pGlobal == pNew))
-      {
-      // Update the system's parameters with new values
-      m_GlobalState->SetSnakeParameters(pNew);
-
-      // Update the running snake
-      if (m_Driver->GetSNAPImageData()->IsSegmentationActive()) 
-        {
-        m_Driver->GetSNAPImageData()->SetSegmentationParameters(pNew);
-        }
-      }
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnSnakeRewindAction()
-{
-  // Stop the snake if it's running
-  OnSnakeStopAction();
-
-  // Basically, we tell the level set driver that we want a restart
-  m_Driver->GetSNAPImageData()->RestartSegmentation();
-
-  // Update the display
-  OnSnakeUpdate();
-}
-
-void fnSnakeIdleFunction(void *userData)
-{
-  // Get the instance of the calling class
-  UserInterfaceLogic *uiLogic = (UserInterfaceLogic *) userData;
-
-  // Request that the desired number of iterations be executed
-  uiLogic->GetDriver()->GetSNAPImageData()->RunSegmentation(
-    uiLogic->m_SnakeStepSize);
-  
-  // Update the display
-  uiLogic->OnSnakeUpdate();
-}
-
-void 
-UserInterfaceLogic
-::OnSnakeStopAction()
-{
-  Fl::remove_idle(fnSnakeIdleFunction, this);
-  m_Activation->UpdateFlag(UIF_SNAP_SNAKE_EDITABLE, true);
-}
-
-void 
-UserInterfaceLogic
-::OnSnakePlayAction()
-{
-  m_Activation->UpdateFlag(UIF_SNAP_SNAKE_RUNNING, true);
-  Fl::add_idle(fnSnakeIdleFunction, this);
-}
-
-void 
-UserInterfaceLogic
-::OnSnakeUpdate()
-{
-  // Update the number of elapsed iterations
-  std::ostringstream oss;
-  oss << m_Driver->GetSNAPImageData()->GetElapsedSegmentationIterations();
-  m_OutCurrentIteration->value(oss.str().c_str());
-
-  // Update the mesh if necessary
-  if(m_ChkContinuousView3DUpdate->value())
-    m_SNAPWindowManager3D->UpdateMesh(m_ProgressCommand);
-  else
-    m_Activation->UpdateFlag(UIF_SNAP_MESH_DIRTY, true);
-
-  // Redraw the windows
-  RedrawWindows();
-}
-
-void 
-UserInterfaceLogic
-::OnSnakeStepAction()
-{
-  // Stop the snake if it's running
-  OnSnakeStopAction();
-
-  // Call the idle function directly
-  fnSnakeIdleFunction(this);
-}
-
-void 
-UserInterfaceLogic
-::OnSnakeStepSizeChange()
-{
-  // Save the step size
-  m_SnakeStepSize = atoi(m_InStepSize->text());
-}
-
-
-//--------------------------------------------
-//
-//
-// SWITCHING BETWEEN WINDOWS STUFF
-//
-//
-//--------------------------------------------
-
-void 
-UserInterfaceLogic
-::SyncSnakeToIRIS()
-{
-  m_InSNAPLabelOpacity->value(m_InIRISLabelOpacity->value());
-  // Contrast_slider_s->value(Contrast_slider->value());
-  // Brightness_slider_s->value(Brightness_slider->value());
-
-  switch (m_GlobalState->GetToolbarMode()) 
-    {
-  case(NAVIGATION_MODE):
-    m_BtnSNAPNavigation->setonly();
-    break;
-  default:
-    SetToolbarMode(CROSSHAIRS_MODE);
-    m_BtnSNAPCrosshairs->setonly();
-    break;
-    }
-}
-
-void 
-UserInterfaceLogic
-::SyncIRISToSnake()
-{
-  m_InIRISLabelOpacity->value(m_InSNAPLabelOpacity->value());
-  // Contrast_slider->value(Contrast_slider_s->value());
-  // Brightness_slider->value(Brightness_slider_s->value());
-
-  switch (m_GlobalState->GetToolbarMode()) 
-    {
-  case(NAVIGATION_MODE):
-    m_BtnNavigationMode->setonly();
-    break;
-  default:
-    SetToolbarMode(CROSSHAIRS_MODE);
-    m_BtnCrosshairsMode->setonly();
-    break;
-    }
-}
-
-void 
-UserInterfaceLogic
-::CloseSegmentationCommon()
-{
-  // This makes no sense if there is no SNAP
-  assert(m_Driver->GetSNAPImageData());
-
-  // Clean up SNAP image data
-  m_Driver->SetCurrentImageDataToIRIS();
-  m_Driver->ReleaseSNAPImageData();
-
-  // Update the Layer UI
-  OnLayerInspectorUpdate();
-
-  // Inform the global state that we're not in sNAP
-  m_GlobalState->SetSNAPActive(false);
-
-  // Speed image is no longer visible
-  m_GlobalState->SetSpeedValid(false);
-  m_GlobalState->SetShowSpeed(false);
-  m_GlobalState->SetSnakeActive(false);
-
-  // Updates some UI components (?)
-  SyncIRISToSnake();
-
-  // Reset the mesh display
-  m_IRISWindowManager3D->ClearScreen();
-  m_IRISWindowManager3D->ResetView();
-
-  // We are going to preserve the cursor position if it was in the ROI
-  Vector3ui newCursor, oldCursor = m_Driver->GetCursorPosition();
-
-  // Image geometry has changed. This method also resets the cursor 
-  // position, which is something we don't want.
-  OnImageGeometryUpdate();
-
-  // So we reset the cursor position manually here if the cursor was in the ROI
-  SNAPSegmentationROISettings roi = m_GlobalState->GetSegmentationROISettings();
-  roi.TransformROIVoxelToImageVoxel(oldCursor, newCursor);  
-  m_Driver->SetCursorPosition(newCursor);
-  OnCrosshairPositionUpdate();
-
-  // Clear the list of bubbles
-  m_GlobalState->SetBubbleArray(GlobalState::BubbleArray());
-  m_GlobalState->SetActiveBubble(-1);
-
-  // Activate/deactivate menu items
-  // TODO: build a better state machine
-  if(m_Activation->GetFlag(UIF_GRAY_LOADED))
-    m_Activation->UpdateFlag(UIF_IRIS_WITH_GRAY_LOADED, true);
-  else
-    m_Activation->UpdateFlag(UIF_IRIS_WITH_BASEIMG_LOADED, true);
-
-  // The segmentation has changed, so the mesh should be updatable
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_DIRTY, true);
-  
-  // Hide the color map window
-  m_WinColorMap->hide();
-
-  // Restore the SNAP view to four side-by-side windows
-  OnWindowFocus(-1);
-  
-  // Show IRIS window, Hide the snake window
-  ShowIRIS();
-
-  // Redraw the windows
-  RedrawWindows();
-}
-
-void 
-UserInterfaceLogic
-::OnAcceptSegmentationAction()
-{
-  // Stop the segmentation if it's running
-  OnSnakeStopAction();
-  
-  // Turn off segmentation if it's active
-  if(m_Driver->GetSNAPImageData()->IsSegmentationActive())
-    {
-    // Tell the update loop to terminate
-    m_Driver->GetSNAPImageData()->TerminateSegmentation();
-    }
-
-  // Get data from SNAP back into IRIS
-  m_Driver->UpdateIRISWithSnapImageData(m_ProgressCommand);
-
-  // This is a safeguard in case the progress events do not fire
-  m_WinProgress->hide();
-
-  // Create an undo point
-  StoreUndoPoint("Automatic segmentation");
-
-  // Close up SNAP
-  CloseSegmentationCommon();
-}
-
-void 
-UserInterfaceLogic
-::OnITKProgressEvent(itk::Object *source, const itk::EventObject &)
-{
-  static double last_progress = clock();
-  static const double delta = 0.25 * CLOCKS_PER_SEC;
-
-  // Get the elapsed progress
-  float progress = dynamic_cast<itk::ProcessObject *>(source)->GetProgress();
-
-  // Update the progress bar and value
-  m_OutProgressMeter->value(100 * progress);
-  m_OutProgressCounter->value(100 * progress);
-
-  // Show or hide progress bar if necessary
-  if(progress < 1.0f && !m_WinProgress->visible())
-    {
-    CenterChildWindowInMainWindow(m_WinProgress);
-    m_WinProgress->show();
-    }
-  else if (progress == 1.0f && m_WinProgress->visible())
-    m_WinProgress->hide();
-
-  // Only call Fl::check() if some time has passed
-  if(last_progress + delta < clock())
-    {
-    // Update the screen
-    Fl::check();
-
-    last_progress = clock();
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnCancelSegmentationAction()
-{
-  // Stop the segmentation if it's running
-  OnSnakeStopAction();
-  
-  // This callback has double functionality, depending on whether the 
-  // level set update loop is active or not
-  if(m_Driver->GetSNAPImageData()->IsSegmentationActive())
-    {
-    // Tell the update loop to terminate
-    m_Driver->GetSNAPImageData()->TerminateSegmentation();
-    }
-
-  // Clean up SNAP image data
-  CloseSegmentationCommon();
-}
-
-void 
-UserInterfaceLogic
-::OnMenuQuit()
-{
-  OnMainWindowCloseAction();
-}
-
-void 
-UserInterfaceLogic
-::OnMenuImageInfo()
-{
-  m_LayerUI->DisplayImageInfoTab();
-}
-
-void
-UserInterfaceLogic
-::OnMenuReorientImage()
-{
-  m_DlgReorientImage->ShowDialog();  
-}
-
-void 
-UserInterfaceLogic
-::OnMainWindowCloseAction()
-{
-  // Make sure the user doesn't lose any data
-  if(!PromptBeforeLosingChanges(REASON_QUIT)) return;
-
-  // We don't want to just exit when users press escape
-  if(Fl::event_key() == FL_Escape) return;
-
-  // Check if there have been unsaved changes to the segmentation
-  // TODO:
-
-  // Associate the current state with the current image
-  OnGreyImageUnload();
-
-  // Create an array of open windows
-  vector<Fl_Window *> openWindows;
-  openWindows.push_back(Fl::first_window());
-
-  // Add all the open windows to the list
-  while(true)
-    {
-    Fl_Window *win = Fl::next_window(openWindows.back());
-    if(win && win != openWindows.front())
-      openWindows.push_back(win);
-    else break;
-    }
-
-  // Close all the windows
-  for(unsigned int i=0;i<openWindows.size();i++)
-    openWindows[i]->hide();
-}
-
-void
-UserInterfaceLogic
-::GlobalOpenDocumentHandler(const char *fn_open)
-{
-  m_GlobalUI->OpenDraggedContent(fn_open, false);
-}
-
-void 
-UserInterfaceLogic
-::OnOpenDroppedAction(int selection)
-{
-  const char *fn_open = m_OutOpenDroppedFileName->label();
-
-  // 1: Load Main image
-  if(selection == 1)
-    {
-    try { NonInteractiveLoadMainImage(fn_open, false, false); }
-    catch(itk::ExceptionObject &exc)
-      {
-      fl_alert("Error opening main image: %s", exc.what());
-      this->RedrawWindows();
-      }
-    }
-  // 2: Load Segmentation
-  else if(selection == 2)
-    {
-    try 
-      { NonInteractiveLoadSegmentation(fn_open); }
-    catch(itk::ExceptionObject &exc)
-      {
-      fl_alert("Error opening segmentation image: %s", exc.what());
-      this->RedrawWindows();
-      }
-    }
-  // 3: Load Overlay
-  else if(selection == 3)
-    {
-    try 
-      { NonInteractiveLoadOverlayImage(fn_open, false, false); }
-    catch(itk::ExceptionObject &exc)
-      {
-      fl_alert("Error opening overlay image: %s", exc.what());
-      this->RedrawWindows();
-      }
-    }
-  // 4: Open in another SNAP
-  else if(selection == 4)
-    {
-    // Generate the command line for the new SNAP
-    std::list<std::string> args;
-    args.push_back("--main");
-    args.push_back(fn_open);
-    
-    if(!m_InOpenDroppedViewMode[0]->value())
-      {
-      args.push_back("--compact");
-      if(m_InOpenDroppedViewMode[1]->value()) args.push_back("a");
-      else if(m_InOpenDroppedViewMode[2]->value()) args.push_back("c");
-      else if(m_InOpenDroppedViewMode[3]->value()) args.push_back("s");
-      }
-
-    try
-      { m_SystemInterface->LaunchChildSNAP(args); }
-    catch(IRISException &exc)
-      {
-      fl_alert("Failed to open another ITK-SNAP instance. \nReason: %s", exc.what());
-      }
-    }
-  m_WinOpenDropped->hide();
-}
-
-void
-UserInterfaceLogic
-::OpenDraggedContent(const char *fn_open, bool interactive)
-{
-  static string win_label;
-
-  if(!m_Activation->GetFlag(UIF_BASEIMG_LOADED))
-    {
-    NonInteractiveLoadMainImage(fn_open, false, false);
-    }
-  else if(interactive)
-    {
-    // Set the label
-    win_label = fn_open;
-    m_OutOpenDroppedFileName->label(win_label.c_str());
-
-    // Display modal dialog
-    m_WinOpenDropped->show();
-    }
-  else
-    {
-    // Generate the command line for the new SNAP
-    std::list<std::string> args;
-    args.push_back("--main");
-    args.push_back(fn_open);
-
-    try
-      {
-      m_SystemInterface->LaunchChildSNAP(args);
-      }
-    catch(IRISException &exc)
-      {
-      fl_alert("Failed to open another ITK-SNAP instance. \nReason: %s", exc.what());
-      }
-    }
-}
-
-void 
-UserInterfaceLogic
-::GlobalIdleHandler(void *userData)
-{
-  // Need base image for all of this
-  if(m_GlobalUI->m_Activation->GetFlag(UIF_BASEIMG_LOADED))
-    {
-    // Read the IPC message
-    SystemInterface::IPCMessage ipcm;
-    if(m_GlobalUI->m_SystemInterface->IPCReadIfNew(ipcm))
-      {
-      // Update the cursor
-      if(m_GlobalUI->m_BtnSynchronizeCursor->value())
-        {
-        // Map the cursor position to the image coordinates
-        GenericImageData *id = m_GlobalUI->m_Driver->GetCurrentImageData();
-        Vector3d vox = 
-          id->GetMain()->TransformNIFTICoordinatesToVoxelIndex(ipcm.cursor);
-
-        // Round the cursor to integer value
-        itk::Index<3> pos; Vector3ui vpos; 
-        pos[0] = vpos[0] = (unsigned int) (vox[0] + 0.5);
-        pos[1] = vpos[1] = (unsigned int) (vox[1] + 0.5);
-        pos[2] = vpos[2] = (unsigned int) (vox[2] + 0.5);
-
-        // Check if the voxel position is inside the image region
-        if(vpos != m_GlobalUI->m_Driver->GetCursorPosition() 
-          && id->GetImageRegion().IsInside(pos))
-          {      
-          m_GlobalUI->m_Driver->SetCursorPosition(vpos);
-          m_GlobalUI->OnCrosshairPositionUpdate(false);
-          m_GlobalUI->RedrawWindows();
-          }
-        }
-
-      // Update the view positions
-      if(m_GlobalUI->m_ChkMultisessionPan->value()
-        && m_GlobalUI->m_Activation->GetFlag(UIF_IRIS_ACTIVE))
-        {
-        bool changed = false;
-        for(size_t i = 0; i < 3; i++)
-          {
-          // Get the relative position of the viewport to cursor
-          Vector2f vprel = m_GlobalUI->m_IRISWindowManager2D[i]->GetViewPositionRelativeToCursor();
-
-          // Get the relative position from the shared memory
-          Vector2f vprel_new = ipcm.viewPositionRelative[i];
-
-          // Check if they are different
-          if(vprel != vprel_new)
-            {
-            changed = true;
-            m_GlobalUI->m_IRISWindowManager2D[i]->SetViewPositionRelativeToCursor(vprel_new);
-            }
-          }
-
-        if(changed)
-          m_GlobalUI->RedrawWindows();
-        }
-
-      // Update the 3D trackball
-      if(m_GlobalUI->m_BtnSynchronizeCursor->value())
-        {
-        // Get the current 3D window object
-        Window3D *w3d = 
-          m_GlobalUI->m_GlobalState->GetSNAPActive() 
-          ? m_GlobalUI->m_SNAPWindowManager3D 
-          : m_GlobalUI->m_IRISWindowManager3D;
-
-        // Compare the two trackballs
-        Trackball tball = w3d->GetTrackball();
-        char *p1 = reinterpret_cast<char *>(&tball);
-        char *p2 = reinterpret_cast<char *>(&ipcm.trackball);
-        if(!std::equal(p1,p1+sizeof(Trackball),p2))
-          {
-          w3d->SetTrackball(ipcm.trackball);
-          m_GlobalUI->RedrawWindows();
-          }
-        }
-
-      // Update the zoom factor (IRIS mode only)
-      if(m_GlobalUI->m_ChkMultisessionZoom->value() 
-        && m_GlobalUI->m_Activation->GetFlag(UIF_IRIS_ACTIVE))
-        {
-        if(ipcm.zoom_level != m_GlobalUI->m_SliceCoordinator->GetCommonZoomLevel())
-          {
-          m_GlobalUI->m_SliceCoordinator->SetZoomLevelAllWindows(ipcm.zoom_level);
-          m_GlobalUI->OnZoomUpdate(false);
-          }
-        }
-      }
-    }
-
-  // This is a pretty bad hack, used as a workaround for FL_LEAVE events not being issued 
-  // when a GL window occupies the whole screen.
-  DisplayLayout dl = m_GlobalUI->GetDisplayLayout();
-  if(dl.show_panel_ui == false)
-    {
-    int x, y;
-    Fl::get_mouse(x,y);
-    Fl_Window *wm = m_GlobalUI->GetMainWindow();
-    Fl_Window *wp = m_GlobalUI->GetPopupToolbarWindow();
-    if(x >= wm->x() && y >= wm->y() && x < wm->x()+wm->w() && y < wm->y()+wm->h()+10+wp->h())
-      {
-      if(!wp->shown())
-        {
-        wp->show();
-        wm->show();
-        }
-      }
-    else
-      {
-      if(wp->shown())
-        wp->hide();
-      }
-    }
-
-    Fl::repeat_timeout(0.03, &UserInterfaceLogic::GlobalIdleHandler);
-}
-
-int 
-UserInterfaceLogic
-::GlobalEventHandler(int ev)
-{
-  return m_GlobalUI->OnGlobalEvent(ev);
-}
-
-#include "FL/Fl_Menu_Window.H"
-
-void
-UserInterfaceLogic
-::SetDisplayLayout(DisplayLayout dl)
-{
-  static int w = 0, h = 0, x = 0, y = 0;
-
-  // Check compatibility rules (some states are incompatible)
-  if(dl.size == HALF_SIZE && (dl.show_main_ui))
-    throw IRISException("Incorrect display layout");
-
-  // Handle full-screen toggle
-  if(m_DisplayLayout.full_screen && !dl.full_screen)
-    {
-    if(m_DisplayLayout.size == FULL_SIZE)
-      {
-      m_WinMain->fullscreen_off(x,y,w,h);
-      }
-    else
-      {
-      m_WinMain->fullscreen_off(x,y,w / 2, h / 2);
-      }
-    m_FullScreen = false;
-    }
-
-  else if(!m_DisplayLayout.full_screen && dl.full_screen)
-    {
-    if(m_DisplayLayout.size == FULL_SIZE)
-      {
-      w = m_WinMain->w(); h = m_WinMain->h();
-      x = m_WinMain->x(); y = m_WinMain->y();
-      }
-    m_WinMain->fullscreen();
-    m_FullScreen = true;
-    }
-
-  // Handle window size selection
-  if(m_DisplayLayout.size == FULL_SIZE && dl.size == HALF_SIZE)
-    {
-    w = m_WinMain->w(); h = m_WinMain->h();
-    x = m_WinMain->x(); y = m_WinMain->y();
-    m_WinMain->size(w / 2, h / 2);
-    }
-  else if(m_DisplayLayout.size == HALF_SIZE && dl.size == FULL_SIZE)
-    {
-    // Restore the saved dimensions
-    m_WinMain->size(w,h);
-    m_WinMain->position(x,y);
-    }
-
-  // Handle the slice window selection (1 vs 4 slices)
-  if(m_DisplayLayout.slice_config != dl.slice_config)
-    {
-    // The dimensions of the parent window
-    int x = m_GrpRightPane->x(), y = m_GrpRightPane->y();
-    int w = m_GrpRightPane->w(), h = m_GrpRightPane->h();
-
-    // Restore all panels to original configuration
-    m_WizSliceLayout[0]->resize(x, y, w >> 1, h >> 1);
-    m_WizSliceLayout[1]->resize(x + (w >> 1), y, w - (w >> 1), h >> 1);
-    m_WizSliceLayout[3]->resize(x, y + (h >> 1), w >> 1, h - (h >> 1));
-    m_WizSliceLayout[2]->resize(x + (w >> 1), y + (h >> 1), w - (w >> 1), h - (h >> 1));
-
-    // Make sure the resizable is set to self
-    m_GrpRightPane->resizable(m_GrpRightPane);
-
-    // Show everything
-    for(unsigned int j = 0; j < 4; j++)
-      {
-      m_GrpRightPane->add(m_WizSliceLayout[j]);
-      m_WizSliceLayout[j]->show();
-      m_SliceWindow[j]->show();
-      m_WizSliceLayout[j]->redraw();
-      }
-
-    if(dl.slice_config != FOUR_SLICE)
-      {
-      for(int j = 0; j < 4; j++)
-        {
-        // We resize all the panels so that the zoom behaves
-        // properly in linked zoom mode
-        if(dl.slice_config != AXIAL + j)
-          {
-          m_WizSliceLayout[j]->hide();
-          m_SliceWindow[j]->hide();
-          m_GrpRightPane->remove(m_WizSliceLayout[j]);
-          }
-        else
-          {
-          m_WizSliceLayout[j]->show();
-          m_SliceWindow[j]->show();
-          m_WizSliceLayout[j]->resize(
-            m_GrpRightPane->x(),m_GrpRightPane->y(),
-            m_GrpRightPane->w(),m_GrpRightPane->h());
-          m_GrpRightPane->resizable(m_WizSliceLayout[j]);
-          m_SliceWindow[j]->take_focus();
-          m_WizSliceLayout[j]->redraw();
-          }
-        }
-
-      }
-    }
-  
-  // Do we need to hide the main pane
-  if(m_DisplayLayout.show_main_ui && !dl.show_main_ui)
-    {
-    // Move the right pane over to the second part of the wizard
-    m_GrpRightPanePlaceholderNormal->remove(m_GrpRightPane);
-    m_GrpRightPanePlaceholderTight->insert(*m_GrpRightPane, 0);
-    m_GrpRightPane->resize(
-      m_GrpRightPanePlaceholderTight->x(),
-      m_GrpRightPanePlaceholderTight->y(),
-      m_GrpRightPanePlaceholderTight->w(),
-      m_GrpRightPanePlaceholderTight->h());
-    m_WizMainLayout->value(m_GrpMainLayoutTight);
-
-    // Shrink the main window
-    if(!m_FullScreen)
-      m_WinMain->size(m_WinMain->w()-145, m_WinMain->h()-25);
-    }
-
-  // Do we need to restore the main panel
-  if(!m_DisplayLayout.show_main_ui && dl.show_main_ui)
-    {
-    // Restore the control panel and toolbar
-    m_GrpRightPanePlaceholderTight->remove(m_GrpRightPane);
-    m_GrpRightPanePlaceholderNormal->insert(*m_GrpRightPane, 0);
-    m_GrpRightPane->resize(
-      m_GrpRightPanePlaceholderNormal->x(),
-      m_GrpRightPanePlaceholderNormal->y(),
-      m_GrpRightPanePlaceholderNormal->w(),
-      m_GrpRightPanePlaceholderNormal->h());
-    m_WizMainLayout->value(m_GrpMainLayoutNormal);
-
-    // Grow the main window (as long as we don't grow over max size)
-    if(!m_FullScreen) 
-      {
-      int sx, sy, sw, sh;
-      Fl::screen_xywh(sx, sy, sw, sh);
-      if(m_WinMain->w() <= sw - 145 && m_WinMain->h() <= sh - 25)
-        m_WinMain->size(m_WinMain->w()+145, m_WinMain->h()+25);
-      }
-
-    }
-
-  // Do we need to hide the mini-panels
-  if(m_DisplayLayout.show_panel_ui && !dl.show_panel_ui)
-    {
-    for(size_t i = 0; i < 4; i++)
-      {
-      // Move the slice window over to the second part of the wizard
-      m_GrpSlicePlaceholder[i]->remove(m_SliceWindow[i]);
-      m_GrpSliceLayoutTight[i]->insert(*m_SliceWindow[i], 0);
-      m_SliceWindow[i]->resize(
-        m_GrpSliceLayoutTight[i]->x(),m_GrpSliceLayoutTight[i]->y(),
-        m_GrpSliceLayoutTight[i]->w(),m_GrpSliceLayoutTight[i]->h());
-      m_WizSliceLayout[i]->value(m_GrpSliceLayoutTight[i]);
-      }
-
-    // Shrink the main window
-    if(!m_FullScreen)
-      m_WinMain->size(m_WinMain->w()-64, m_WinMain->h()-70);
-    }
-
-  // Do we need to restore the mini-panels
-  if(!m_DisplayLayout.show_panel_ui && dl.show_panel_ui)
-    {
-    // Restore the slice windows
-    for(size_t i = 0; i < 4; i++)
-      {
-      m_GrpSliceLayoutTight[i]->remove(m_SliceWindow[i]);
-      m_GrpSlicePlaceholder[i]->insert(*m_SliceWindow[i], 0);
-      m_SliceWindow[i]->resize(
-        m_GrpSlicePlaceholder[i]->x(),
-        m_GrpSlicePlaceholder[i]->y(),
-        m_GrpSlicePlaceholder[i]->w(),
-        m_GrpSlicePlaceholder[i]->h());
-      m_WizSliceLayout[i]->value(m_GrpSliceLayoutNormal[i]);
-      }
-
-    // Grow the main window (as long as we don't grow over max size)
-    if(!m_FullScreen) 
-      {
-      int sx, sy, sw, sh;
-      Fl::screen_xywh(sx, sy, sw, sh);
-      if(m_WinMain->w() <= sw - 64 && m_WinMain->h() <= sh - 70)
-        m_WinMain->size(m_WinMain->w()+64, m_WinMain->h()+70);
-      }
-    }
-
-  if(dl.size == HALF_SIZE && !dl.show_panel_ui)
-    {
-    // Create a popup window so the user can close
-    m_WinTestPop->position(
-      m_WinMain->x() + m_WinMain->w() - (5 + m_WinTestPop->w()),
-      m_WinMain->y() + m_WinMain->h() + 5);
-    m_WinTestPop->show();
-    }
-  else
-    {
-    m_WinTestPop->hide();
-    }
-
-  // Store the new display layout
-  m_DisplayLayout = dl;
-}
-
-void
-UserInterfaceLogic
-::OnCollapsedViewPopupMenu()
-{
-  // Show popup menu at the button location
-
-  // Dynamically create menu, pop it up
-  Fl_Menu_Button menu(Fl::event_x_root() - m_WinMain->x(), Fl::event_y_root() - m_WinMain->y(), 80, 1);
-  Fl_Menu_Bar *bar = this->GetMainMenuBar();
-  menu.copy(bar->menu());
-
-  // Put the menu so that it's as deep in the widget hierarchy as the main menubar
-  Fl_Group g1(0, 0, 80, 1);
-  Fl_Group g2(0, 0, 80, 1);
-  m_WinMain->add(g1);
-  g1.add(g2);
-  g2.add(menu);
-
-  // Disable idle during popup
-  Fl::remove_timeout(UserInterfaceLogic::GlobalIdleHandler);
-
-  // Popup
-  menu.popup();
-  m_WinMain->remove(g1);
-  g1.remove(g2);
-  g2.remove(menu);
-
-  Fl::add_timeout(0.03, &UserInterfaceLogic::GlobalIdleHandler);
-}
-
-void
-SNAPMainWindow
-::resize(int x, int y, int w, int h)
-{
-  // Call parent class
-  Fl_Double_Window::resize(x,y,w,h);
-
-  // Move popup window (make more efficient)
-  if(m_ParentUI)
-    {
-    DisplayLayout dl = m_ParentUI->GetDisplayLayout();
-    if(!dl.show_panel_ui)
-      {
-      Fl_Window *m = m_ParentUI->GetMainWindow();
-      Fl_Window *p = m_ParentUI->GetPopupToolbarWindow();
-      p->position( m->x() + m->w() - (5 + p->w()), m->y() + m->h() + 5 );
-      }
-    }
-}
-
-void
-UserInterfaceLogic
-::ToggleDisplayElements()
-{
-  // Cycle through 4 visibility modes
-  DisplayLayout dl = m_DisplayLayout;
-  if(dl.show_main_ui && dl.show_panel_ui)
-    {
-    dl.show_main_ui = false;
-    dl.show_panel_ui = true;
-    dl.size = FULL_SIZE;
-    }
-  else if(!dl.show_main_ui && dl.show_panel_ui)
-    {
-    dl.show_main_ui = false;
-    dl.show_panel_ui = false;
-    dl.size = FULL_SIZE;
-    }
-  else if(!dl.show_main_ui && !dl.show_panel_ui && dl.size == FULL_SIZE)
-    {
-    dl.show_main_ui = false;
-    dl.show_panel_ui = false;
-    dl.size = HALF_SIZE;
-    }
-  else 
-    {
-    dl.show_panel_ui = true;
-    dl.show_main_ui = true;
-    dl.size = FULL_SIZE;
-    }
-
-  SetDisplayLayout(dl);
-}
-
-/*
-void
-UserInterfaceLogic
-::ToggleDisplayElements()
-{
-  // First press: hide left pane and menubar
-  if(m_WizMainLayout->value() == m_GrpMainLayoutNormal)
-    {
-    // Move the right pane over to the second part of the wizard
-    m_GrpRightPanePlaceholderNormal->remove(m_GrpRightPane);
-    m_GrpRightPanePlaceholderTight->insert(*m_GrpRightPane, 0);
-    m_GrpRightPane->resize(
-      m_GrpRightPanePlaceholderTight->x(),
-      m_GrpRightPanePlaceholderTight->y(),
-      m_GrpRightPanePlaceholderTight->w(),
-      m_GrpRightPanePlaceholderTight->h());
-    m_WizMainLayout->value(m_GrpMainLayoutTight);
-
-    // Shrink the main window
-    if(!m_FullScreen)
-      m_WinMain->size(m_WinMain->w()-145, m_WinMain->h()-25);
-    }
-
-  // Second press: hide panels for each window
-  else if(m_WizSliceLayout[0]->value() == m_GrpSliceLayoutNormal[0])
-    {
-    for(size_t i = 0; i < 4; i++)
-      {
-      // Move the slice window over to the second part of the wizard
-      m_GrpSlicePlaceholder[i]->remove(m_SliceWindow[i]);
-      m_GrpSliceLayoutTight[i]->insert(*m_SliceWindow[i], 0);
-      m_SliceWindow[i]->resize(
-        m_GrpSliceLayoutTight[i]->x(),m_GrpSliceLayoutTight[i]->y(),
-        m_GrpSliceLayoutTight[i]->w(),m_GrpSliceLayoutTight[i]->h());
-      m_WizSliceLayout[i]->value(m_GrpSliceLayoutTight[i]);
-      }
-
-    // Shrink the main window
-    if(!m_FullScreen)
-      m_WinMain->size(m_WinMain->w()-64, m_WinMain->h()-70);
-    }
-
-  // Third press: restore everything
-  else
-    {
-    // Restore the slice windows
-    for(size_t i = 0; i < 4; i++)
-      {
-      m_GrpSliceLayoutTight[i]->remove(m_SliceWindow[i]);
-      m_GrpSlicePlaceholder[i]->insert(*m_SliceWindow[i], 0);
-      m_SliceWindow[i]->resize(
-        m_GrpSlicePlaceholder[i]->x(),
-        m_GrpSlicePlaceholder[i]->y(),
-        m_GrpSlicePlaceholder[i]->w(),
-        m_GrpSlicePlaceholder[i]->h());
-      m_WizSliceLayout[i]->value(m_GrpSliceLayoutNormal[i]);
-      }
-
-    // Restore the control panel and toolbar
-    m_GrpRightPanePlaceholderTight->remove(m_GrpRightPane);
-    m_GrpRightPanePlaceholderNormal->insert(*m_GrpRightPane, 0);
-    m_GrpRightPane->resize(
-      m_GrpRightPanePlaceholderNormal->x(),
-      m_GrpRightPanePlaceholderNormal->y(),
-      m_GrpRightPanePlaceholderNormal->w(),
-      m_GrpRightPanePlaceholderNormal->h());
-    m_WizMainLayout->value(m_GrpMainLayoutNormal);
-
-    // Grow the main window (as long as we don't grow over max size)
-    if(!m_FullScreen) 
-      {
-      int sx, sy, sw, sh;
-      Fl::screen_xywh(sx, sy, sw, sh);
-      if(m_WinMain->w() <= sw - 145 && m_WinMain->h() <= sh + 25)
-        m_WinMain->size(m_WinMain->w()+145+64, m_WinMain->h()+25+70);
-      }
-    }
-}
-*/
-
-/*
-void
-UserInterfaceLogic
-::ToggleFullScreen()
-{
-  static int w = 0, h = 0, x = 0, y = 0;
-
-  if(m_FullScreen)
-    {
-    m_WinMain->fullscreen_off(x,y,w,h);
-    m_FullScreen = false;
-    }
-  else
-    {
-    w = m_WinMain->w(); h = m_WinMain->h();
-    x = m_WinMain->x(); y = m_WinMain->y();
-    m_WinMain->fullscreen();
-    m_FullScreen = true;
-    }
-}
-*/
-
-void
-UserInterfaceLogic
-::ToggleFullScreen()
-{
-  DisplayLayout dl = m_DisplayLayout;
-  dl.full_screen = !dl.full_screen;
-  SetDisplayLayout(dl);
-}
-
-int 
-UserInterfaceLogic
-::OnGlobalEvent(int ev)
-{
-if(ev == FL_SHORTCUT)
-  {
-  // Opacity slider toggle/increase/decrease
-  if(m_Activation->GetFlag(UIF_IRIS_WITH_BASEIMG_LOADED))
-    {
-    if(Fl::test_shortcut('1'))
-      { 
-      this->SetToolbarMode(CROSSHAIRS_MODE); 
-      return 1; 
-      }
-    if(Fl::test_shortcut('2'))
-      { 
-      this->SetToolbarMode(NAVIGATION_MODE); 
-      return 1; 
-      }
-    if(Fl::test_shortcut('3'))
-      { 
-      this->SetToolbarMode(POLYGON_DRAWING_MODE); 
-      return 1; 
-      }
-    if(Fl::test_shortcut('4'))
-      { 
-      this->SetToolbarMode(ROI_MODE); 
-      return 1; 
-      }
-    if(Fl::test_shortcut('5'))
-      { 
-      this->SetToolbarMode(PAINTBRUSH_MODE); 
-      return 1; 
-      }
-    else if(Fl::test_shortcut('a'))
-      {
-      double opacity = m_InIRISLabelOpacity->value() - 8.0;
-      if(opacity >= 0.0)
-        m_InIRISLabelOpacity->value(opacity); 
-      OnIRISLabelOpacityChange();
-      return 1;
-      }
-    else if(Fl::test_shortcut('d'))
-      {
-      double opacity = m_InIRISLabelOpacity->value() + 8.0;
-      if(opacity <= 255.0)
-        m_InIRISLabelOpacity->value(opacity); 
-      OnIRISLabelOpacityChange();
-      return 1;
-      }
-    else if(Fl::test_shortcut('s'))
-      {
-      double opacity = m_InIRISLabelOpacity->value();
-      if(opacity > 0)
-        {
-        m_OpacityToggleValue = opacity;
-        m_InIRISLabelOpacity->value(0);
-        }
-      else
-        {
-        m_InIRISLabelOpacity->value(m_OpacityToggleValue);
-        m_OpacityToggleValue = 128;
-        }
-      OnIRISLabelOpacityChange(); 
-      return 1;
-      }
-
-    else if(Fl::test_shortcut('q'))
-      {
-      m_LayerUI->AdjustOverlayOpacity(-8.0);
-      return 1;
-      }
-
-    else if(Fl::test_shortcut('e'))
-      {
-      m_LayerUI->AdjustOverlayOpacity(+8.0);
-      return 1;
-      }
-
-    else if(Fl::test_shortcut('w'))
-      {
-      m_LayerUI->ToggleOverlayVisibility();
-      return 1;
-      }
-
-    else if(Fl::test_shortcut('z' | FL_COMMAND))
-      {
-      if(m_BtnIRISUndo->active())
-        this->OnUndoAction();
-      return 1;
-      }
-
-    else if(Fl::test_shortcut('y' | FL_COMMAND))
-      {
-      if(m_BtnIRISRedo->active())
-        this->OnRedoAction();
-      return 1;
-      }
-
-    // Cycle through available colormaps
-    else if(Fl::test_shortcut('k'))
-      {
-      m_LayerUI->SelectNextColorMap();
-      return 1;
-      }
-    
-    // Auto image contrast adjustment
-    else if(Fl::test_shortcut(FL_ALT | 'i'))
-      {
-      m_LayerUI->OnAutoFitWindow();
-      return 1;
-      }
-
-    // Toggle 4 views / slice views
-    else if(Fl::test_shortcut(FL_F + 2))
-      {
-      DisplayLayout dl = m_DisplayLayout;
-      switch(dl.slice_config)
-        {
-        case FOUR_SLICE : dl.slice_config = AXIAL; break;
-        case AXIAL : dl.slice_config = CORONAL; break;
-        case CORONAL : dl.slice_config = SAGITTAL; break;
-        case SAGITTAL : dl.slice_config = THREED; break;
-        case THREED : dl.slice_config = FOUR_SLICE; break;
-        }
-      SetDisplayLayout(dl);
-      return 1;
-      }
-
-    // Toggle various controls
-    else if(Fl::test_shortcut(FL_F + 3))
-      {
-      ToggleDisplayElements();
-      return 1;
-      }
-
-    // F4 - fullscreen toggle
-    else if(Fl::test_shortcut(FL_F + 4))
-      {
-      ToggleFullScreen();
-      return 1;
-      }
-
-    // Ctrl-F - fit all views
-    else if(Fl::test_shortcut(FL_COMMAND | 'f'))
-      {
-      this->OnResetAllViews2DAction();
-      return 1;
-      }
-
-    // center the 2D views (reset view positions)
-    else if(Fl::test_shortcut(FL_COMMAND | FL_SHIFT | 'f'))
-      {
-      m_IRISWindowManager2D[0]->ResetViewPosition();
-      m_IRISWindowManager2D[1]->ResetViewPosition();
-      m_IRISWindowManager2D[2]->ResetViewPosition();
-      OnViewPositionsUpdate();
-      return 1;
-      }
-    // selecting active drawing label
-    else if(Fl::test_shortcut(',') || Fl::test_shortcut('<'))
-      {
-      LabelType iDrawing = m_GlobalState->GetDrawingColorLabel();
-      for(size_t i = 0; i < static_cast<size_t>(m_InDrawingColor->size()); i++)
-        if(iDrawing == static_cast<LabelType>(reinterpret_cast<size_t>(m_InDrawingColor->menu()[i].user_data())) && i > 1)
-          {
-          m_InDrawingColor->value(i-1);
-          break;
-          }
-        OnDrawingLabelUpdate();
-        return 1;
-      }
-    else if(Fl::test_shortcut('.') || Fl::test_shortcut('>'))
-      {
-      LabelType iDrawing = m_GlobalState->GetDrawingColorLabel();
-      for(size_t i = 0; i < static_cast<size_t>(m_InDrawingColor->size()); i++)
-        if(iDrawing == static_cast<LabelType>(reinterpret_cast<size_t>(m_InDrawingColor->menu()[i].user_data())) && i < static_cast<size_t>(m_InDrawingColor->size()))
-          {
-          m_InDrawingColor->value(i+1);
-          break;
-          }
-        OnDrawingLabelUpdate();
-        return 1;
-      }
-    // selecting drawing over label
-    else if(Fl::test_shortcut(FL_COMMAND | ',') || Fl::test_shortcut(FL_COMMAND | '<'))
-      {
-      LabelType iDrawOver = m_GlobalState->GetOverWriteColorLabel();
-      if(m_GlobalState->GetCoverageMode() == PAINT_OVER_ALL)
-        return 1;
-      else if(m_GlobalState->GetCoverageMode() == PAINT_OVER_COLORS)
-        m_InDrawOverColor->value(0);
-      else for(size_t i = 0; i < static_cast<size_t>(m_InDrawingColor->size()); i++)
-        if(iDrawOver == static_cast<LabelType>(reinterpret_cast<size_t>(m_InDrawingColor->menu()[i].user_data())))
-          {
-          m_InDrawOverColor->value(i + 1);
-          break;
-          }
-        OnDrawOverLabelUpdate();
-        return 1;
-      }
-    else if(Fl::test_shortcut(FL_COMMAND | '.') || Fl::test_shortcut(FL_COMMAND | '>'))
-      {
-      LabelType iDrawOver = m_GlobalState->GetOverWriteColorLabel();
-      if(m_GlobalState->GetCoverageMode() == PAINT_OVER_ALL)
-        m_InDrawOverColor->value(1);
-      else if(m_GlobalState->GetCoverageMode() == PAINT_OVER_COLORS)
-        m_InDrawOverColor->value(2);
-      else for(size_t i = 0; i < static_cast<size_t>(m_InDrawingColor->size()); i++)
-        if(iDrawOver == static_cast<LabelType>(reinterpret_cast<size_t>(m_InDrawingColor->menu()[i].user_data())) 
-          && i < static_cast<size_t>(m_InDrawingColor->size()))
-          {
-          m_InDrawOverColor->value(i + 3);
-          break;
-          }
-        OnDrawOverLabelUpdate();
-        return 1;
-      }
-    // paintbrush size controls
-    if(m_GlobalState->GetToolbarMode() == PAINTBRUSH_MODE)
-      {
-      if(Fl::test_shortcut('_') || Fl::test_shortcut('-'))
-        {
-        double pbsize = m_InPaintbrushSize->value() - 1.0;
-        if(pbsize >= 1.0)
-          m_InPaintbrushSize->value(pbsize);
-        OnPaintbrushAttributesUpdate();
-        return 1;
-        }
-      else if(Fl::test_shortcut('=') || Fl::test_shortcut('+'))
-        {
-        double pbsize = m_InPaintbrushSize->value() + 1.0;
-        if(pbsize <= 100.0)
-          m_InPaintbrushSize->value(pbsize);
-        OnPaintbrushAttributesUpdate();
-        return 1;
-        }
-      }
-    } // if UIF_IRIS_WITH_BASEIMG_LOADED
-  else if(m_Activation->GetFlag(UIF_SNAP_ACTIVE))
-    {
-    // add/remove bubble controls
-    if(m_GrpSNAPStepInitialize->visible())
-      {
-      if(m_BtnRemoveBubble->active() && (Fl::test_shortcut('_') || Fl::test_shortcut('-')))
-        {
-        this->OnRemoveBubbleAction();
-        return 1;
-        }
-      else if(m_BtnAddBubble->active() && (Fl::test_shortcut('=') || Fl::test_shortcut('+')))
-        {
-        this->OnAddBubbleAction();
-        return 1;
-        }
-      if(m_InBubbleRadius->active() && (Fl::test_shortcut('{') || Fl::test_shortcut('[')))
-        {
-        double rad = m_InBubbleRadius->value();
-        if(rad >= 1)
-          m_InBubbleRadius->value(rad - 1);
-        this->OnBubbleRadiusChange();
-        return 1;
-        }
-      else if(m_InBubbleRadius->active() && (Fl::test_shortcut('}') || Fl::test_shortcut(']')))
-        {
-        double rad = m_InBubbleRadius->value();
-        if(rad >= 1)
-          m_InBubbleRadius->value(rad + 1);
-        this->OnBubbleRadiusChange();
-        return 1;
-        }
-      }
-    } // if UIF_SNAP_ACTIVE
-
-  // The following shortcuts are general
-  if(m_Activation->GetFlag(UIF_BASEIMG_LOADED))
-    {    
-    // toggle crosshairs display
-    if(Fl::test_shortcut(FL_SHIFT | 'x'))
-      {
-      SNAPAppearanceSettings::Element &e = 
-        m_AppearanceSettings->GetUIElement(SNAPAppearanceSettings::CROSSHAIRS);
-      e.Visible = !e.Visible;
-      m_DlgAppearance->OnOptionsExternalUpdate();
-      RedrawWindows();
-      return 1;
-      }
-    else if(Fl::test_shortcut('x'))
-      {
-      m_AppearanceSettings->SetOverallVisibility(
-        !m_AppearanceSettings->GetOverallVisibility());
-      m_DlgAppearance->OnOptionsExternalUpdate();
-      RedrawWindows();
-      return 1;
-      }
-    }
-  } // if shortcut
-return 0;
-}
-
-void
-UserInterfaceLogic
-::Launch()
-{
-  // Add the global event handler
-  UserInterfaceLogic::m_GlobalUI = this;
-  Fl::add_handler(&UserInterfaceLogic::GlobalEventHandler);
-
-  // Add the idle event handler
-  Fl::add_timeout(0.03, &UserInterfaceLogic::GlobalIdleHandler);
-
-  // Make sure the window is visible
-  m_WinMain->show();
-
-  // Show all of the GL boxes
-  for(unsigned int i = 0; i < 4; i++)
-    m_SliceWindow[i]->show();
-
-  // Show the IRIS interface
-}
-
-void 
-UserInterfaceLogic
-::ShowIRIS()
-{
-  // Show the right wizard page
-  m_WizControlPane->value(
-    m_Driver->GetCurrentImageData()->IsMainLoaded() ? 
-    m_GrpToolbarPage : m_GrpWelcomePage);
-
-  // Show the right toolbar page under the render window
-  m_WizRenderingToolbar->value(m_GrpRenderingIRISPage);
-
-  // Assign the right window managers to the slice windows
-  for(unsigned int i = 0; i < 3; i++)
-    m_SliceWindow[i]->SetSingleInteractionMode(m_IRISWindowManager2D[i]);
-  m_SliceWindow[3]->SetSingleInteractionMode(m_IRISWindowManager3D);
-
-  // Clear the 3D window and reset the view
-  m_IRISWindowManager3D->ClearScreen();
-  m_IRISWindowManager3D->ResetView();
-
-  // Change what's shown in the layer inspector
-  OnLayerInspectorUpdate();
-
-  // Force a global redraw
-  RedrawWindows();
-}
-
-void 
-UserInterfaceLogic
-::ShowSNAP()
-{
-  // Restore the IRIS view to four side-by-side windows
-  OnWindowFocus(-1);
-
-  // Swap the left-side panels
-  m_WizControlPane->value(m_GrpSNAPPage);
-
-  // Show the right toolbar page under the render window
-  m_WizRenderingToolbar->value(m_GrpRenderingSNAPPage);
-
-  // Assign the right window managers to the slice windows
-  for(unsigned int i = 0; i < 3; i++)
-    m_SliceWindow[i]->SetSingleInteractionMode(m_SNAPWindowManager2D[i]);
-  m_SliceWindow[3]->SetSingleInteractionMode(m_SNAPWindowManager3D);
-
-  // Clear the snap window and reset the view
-  m_SNAPWindowManager3D->ClearScreen();
-  m_SNAPWindowManager3D->ResetView();
-
-  // Indicate that preprocessing is not done
-  m_Activation->UpdateFlag(UIF_SNAP_ACTIVE, true);
-  m_Activation->UpdateFlag(UIF_SNAP_PREPROCESSING_DONE, false);
-
-  // Go to the first page in the SNAP wizard
-  SetActiveSegmentationPipelinePage( 0 );
-
-  // Change what's shown in the layer inspector
-  OnLayerInspectorUpdate();
-
-  // Repaint everything
-  RedrawWindows();
-}
-
-void 
-UserInterfaceLogic
-::InitializeUI()
-{
-  // Make the menu bar global
-  m_MenubarMain->global();
-
-  // Set the version text in the welcome page
-  m_InWelcomePageVersion->label(SNAPUISoftVersion);
-  m_InAboutPageVersion->label(SNAPUISoftVersion);
-
-  // Sync global state to GUI
-  m_BtnCrosshairsMode->setonly();
-  // SetToolbarMode(CROSSHAIRS_MODE);
-
-  m_GlobalState->SetSegmentationAlpha(128);
-  m_InIRISLabelOpacity->Fl_Valuator::value(128);
-
-  // Initialize the color map for the first time
-  UpdateColorLabelMenu();
-
-  // Window title
-  UpdateMainLabel();
-
-  m_GlobalState->SetShowSpeed(false);
-
-  m_InSNAPLabelOpacity->Fl_Valuator::value(128);
-
-  //this should probably go into the .h, a #define or something
-  m_InStepSize->add("1");
-  m_InStepSize->add("2");
-  m_InStepSize->add("5");
-  m_InStepSize->add("10");
-
-  // Initialize the toolbar at the bottom of 3D window
-  m_ToolbarRenderWindow->spacing(5);
-
-  // Apply the special appearance settings that determine startup behavior
-  if(m_AppearanceSettings->GetFlagLinkedZoomByDefault())
-    {
-    m_ChkLinkedZoom->value(1);    
-    OnLinkedZoomChange();
-    }
-
-  if(m_AppearanceSettings->GetFlagMultisessionZoomByDefault())
-    {
-    m_ChkMultisessionZoom->value(1);
-    OnZoomUpdate();
-    }
-
-  if(m_AppearanceSettings->GetFlagMultisessionPanByDefault())
-    {
-    m_ChkMultisessionPan->value(1);
-    OnViewPositionsUpdate();
-    }
-
-  // Initialize the paintbrush panel
-  UpdatePaintbrushAttributes();
-
-  // Set the anatomy to display transforms for each of the windows  
-  string rai1, rai2, rai3;
-  m_AppearanceSettings->GetAnatomyToDisplayTransforms(rai1, rai2, rai3);
-
-  // Update the user interface
-  m_Driver->SetDisplayToAnatomyRAI(rai1.c_str(), rai2.c_str(), rai3.c_str());
-  OnImageGeometryUpdate();
-  
-  // Initialize hidden feature usage option
-  OnHiddenFeaturesToggleAction();
-
-  // Register the open document callback
-  fl_open_callback(&UserInterfaceLogic::GlobalOpenDocumentHandler);
-
-  // On Apple, we also want to register that handler with 'open contents'
-#ifdef __APPLE__
-
-  AEEventHandlerUPP handler;
-  SRefCon refcon;
-  AEGetEventHandler(kCoreEventClass, kAEOpenDocuments, &handler, &refcon, false);
-  AEInstallEventHandler(kCoreEventClass, kAEOpenContents, handler, refcon, false);
-
-#endif 
-
-  m_WinMain->SetParentUI(this);
-
-  DisplayTips();
-}
-
-void 
-UserInterfaceLogic
-::UpdateColorLabelSelection()
-{
-  // Set the current drawing label
-  LabelType iDrawing = m_GlobalState->GetDrawingColorLabel();
-  LabelType iDrawOver = m_GlobalState->GetOverWriteColorLabel();
-
-  // Select the drawing label
-  for(size_t i = 0; i < static_cast<size_t>(m_InDrawingColor->size()); i++)
-    if(iDrawing == static_cast<LabelType>(reinterpret_cast<size_t>(m_InDrawingColor->menu()[i].user_data())))
-      m_InDrawingColor->value(i);
-
-  // Set the draw over label
-  if(m_GlobalState->GetCoverageMode() == PAINT_OVER_ALL)
-    m_InDrawOverColor->value(0);
-  else if (m_GlobalState->GetCoverageMode() == PAINT_OVER_COLORS)
-    m_InDrawOverColor->value(1);
-  else for(size_t j = 0; j < static_cast<size_t>(m_InDrawingColor->size()); j++)
-    if(iDrawOver == static_cast<LabelType>(reinterpret_cast<size_t>(m_InDrawingColor->menu()[j].user_data())))
-      m_InDrawOverColor->value(j + 2);
-}
-
-void
-UserInterfaceLogic
-::DeleteColorLabelMenu(Fl_Menu_Item *menu)
-{
-  if(menu) 
-    {
-    for(Fl_Menu_Item *mi = menu; mi->text != NULL; ++mi)
-      delete mi->text;
-    delete menu;
-    }
-}
-
-void InitMenuItem(Fl_Menu_Item *p, const ColorLabel &cl, LabelType id)
-{
-  char *strcopy = (char *) calloc(strlen(cl.GetLabel()) + 10, sizeof(char));
-  sprintf(strcopy, "%08x %s", 
-    fl_rgb_color(cl.GetRGB(0),cl.GetRGB(1),cl.GetRGB(2)),
-    cl.GetLabel()); 
-  p->label(COLORBAR_LABEL, strcopy);
-  p->shortcut(0);
-  p->callback((Fl_Callback *) 0);
-  p->user_data((void *) (size_t) id);
-  p->flags = 0;     
-  p->labelcolor(FL_BLACK);
-  p->labelfont(0);
-  p->labelsize(0);
-}
-
-void InitMenuItem(Fl_Menu_Item *p, const char *text)
-{
-  char *strcopy = (char *) calloc(strlen(text) + 1, sizeof(char));
-  strcpy(strcopy, text); 
-  p->label(FL_NORMAL_LABEL, strcopy);
-  p->shortcut(0);
-  p->callback((Fl_Callback *) 0);
-  p->user_data(0);
-  p->flags = 0;     
-  p->labelcolor(FL_BLACK);
-  p->labelfont(0);
-  p->labelsize(0);
-}
-
-
-Fl_Menu_Item *
-UserInterfaceLogic
-::GenerateColorLabelMenu(bool all, bool visible, bool clear) 
-{
-  // Compute the number of labels
-  ColorLabelTable *clt = m_Driver->GetColorLabelTable();
-  size_t n = clt->GetNumberOfValidLabels() - 1;
-  if(all) n++;
-  if(visible) n++;
-  if(clear) n++;
-
-  // Create the new menu and a pointer
-  Fl_Menu_Item *menu = new Fl_Menu_Item[n+1], *p = menu;
-
-  // Add the all labels item
-  if(all)
-    InitMenuItem(p++, "All labels");
-  if(visible)
-    InitMenuItem(p++, "Visible labels");
-  if(clear)
-    InitMenuItem(p++, clt->GetColorLabel(0), 0);
-  for (size_t i = 1; i < MAX_COLOR_LABELS; i++) 
-    {
-    const ColorLabel &cl = clt->GetColorLabel(i);
-    if (cl.IsValid()) 
-      InitMenuItem(p++, cl, i);
-    }
-
-  // Last item is NULL
-  p->text = NULL;
-
-  // Return the menu
-  return menu;
-}
-
-void 
-UserInterfaceLogic
-::UpdateColorLabelMenu() 
-{  
-  // Set up the paint-over menu
-  m_InDrawOverColor->clear();
-  DeleteColorLabelMenu(m_MenuDrawOverLabels);
-  m_MenuDrawOverLabels = GenerateColorLabelMenu(true, true, true);
-  m_InDrawOverColor->menu(m_MenuDrawOverLabels);
-
-  // Set up the draw color menu
-  m_InDrawingColor->clear();
-  DeleteColorLabelMenu(m_MenuDrawingLabels);
-  m_MenuDrawingLabels = GenerateColorLabelMenu(false, false, true);
-  m_InDrawingColor->menu(m_MenuDrawingLabels);
-  
-  // Update the color label that is currently selected
-  UpdateColorLabelSelection();
-}
-
-void 
-UserInterfaceLogic
-::RedrawWindows() 
-{
-  // Redraw the OpenGL windows
-  m_SliceWindow[0]->redraw();
-  m_SliceWindow[1]->redraw();
-  m_SliceWindow[2]->redraw();
-  m_SliceWindow[3]->redraw();
-
-  // TODO: Do we really need this?
-  // Redraw the current color swath (?)
-  if(m_GrpSNAPCurrentColor->visible())
-    m_GrpSNAPCurrentColor->redraw();
-}
-
-void 
-UserInterfaceLogic
-::ResetScrollbars() 
-{
-  // Get the cursor position in image coordinated
-  Vector3d cursor = to_double(m_Driver->GetCursorPosition());
-
-  // Update the correct scroll bars
-  for (unsigned int dim=0; dim<3; dim++)
-    {
-    // What image axis does dim correspond to?
-    unsigned int imageAxis = GetImageAxisForDisplayWindow(dim);
-    m_InSliceSlider[dim]->Fl_Valuator::value( -cursor[imageAxis] );
-
-    // Update the little display box at the bottom of the scroll bar
-    UpdatePositionDisplay(dim);
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnCrosshairPositionUpdate(bool flagBroadcastUpdate)
-{
-  ResetScrollbars();
-  UpdateImageProbe();
-
-  // When the crosshair position is updated, we send the information 
-  // to the inter-process communications system
-  if(flagBroadcastUpdate 
-    && m_GlobalUI->m_Activation->GetFlag(UIF_BASEIMG_LOADED)
-    && m_GlobalUI->m_BtnSynchronizeCursor->value())
-    {
-    // Map the cursor to NIFTI coordinates
-    Vector3d cursor = 
-      m_Driver->GetCurrentImageData()->GetMain()->
-        TransformVoxelIndexToNIFTICoordinates(
-          to_double(m_Driver->GetCursorPosition()));
-
-    // Write the NIFTI cursor to shared memory
-    m_Driver->GetSystemInterface()->IPCBroadcastCursor(cursor);
-
-    // Also trigger update in view positions b/c they are tied to the cursor
-    this->OnViewPositionsUpdate(true);
-    }
-}
-
-void
-UserInterfaceLogic
-::OnMultisessionPanChange()
-{
-  // Make sure we broadcast the current zoom level
-  OnViewPositionsUpdate();
-}
-
-void
-UserInterfaceLogic
-::OnViewPositionsUpdate(bool flagBroadcastUpdate)
-{
-  if(flagBroadcastUpdate 
-    && m_Activation->GetFlag(UIF_IRIS_ACTIVE)
-    && m_ChkMultisessionPan->value())
-    {
-    // For each slice, get the view position
-    Vector2f vprel[3];
-    for(size_t i = 0; i < 3; i++)
-      {
-      // Get the view position in image coordinates
-      vprel[i] = m_IRISWindowManager2D[i]->GetViewPositionRelativeToCursor();
-      }
-
-    // Broadcast this view position
-    m_SystemInterface->IPCBroadcastViewPosition(vprel);
-    }
-
-  this->RedrawWindows();
-}
-
-void
-UserInterfaceLogic
-::OnTrackballUpdate(bool flagBroadcastUpdate)
-{
-  if(flagBroadcastUpdate
-    && m_GlobalUI->m_Activation->GetFlag(UIF_BASEIMG_LOADED)
-    && m_GlobalUI->m_BtnSynchronizeCursor->value())
-    {
-    Trackball tball = 
-      m_GlobalState->GetSNAPActive() ? 
-      m_SNAPWindowManager3D->GetTrackball() : 
-      m_IRISWindowManager3D->GetTrackball();
-    m_Driver->GetSystemInterface()->IPCBroadcastTrackball(tball);
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnDrawingLabelUpdate()
-{
-  // Get the drawing label that was selected
-  LabelType iLabel = (LabelType) (size_t) 
-    m_InDrawingColor->mvalue()->user_data();
-  
-  // Set the global state
-  m_GlobalState->SetDrawingColorLabel((LabelType) iLabel);
-}
-
-void 
-UserInterfaceLogic
-::OnDrawOverLabelUpdate()
-{
-  // See what the user selected
-  if(m_InDrawOverColor->value() == 0)
-    // The first menu item is 'paint over all'
-    m_GlobalState->SetCoverageMode(PAINT_OVER_ALL);
-  else if(m_InDrawOverColor->value() == 1)
-    // The first menu item is 'paint over visible'
-    m_GlobalState->SetCoverageMode(PAINT_OVER_COLORS);
-  else
-    {
-    LabelType iLabel = (LabelType) (size_t) 
-      m_InDrawOverColor->mvalue()->user_data();
-    m_GlobalState->SetCoverageMode(PAINT_OVER_ONE);
-    m_GlobalState->SetOverWriteColorLabel(iLabel);
-    }
-}
-
-void 
-UserInterfaceLogic
-::UpdateImageProbe() 
-{
-  // Code common to SNAP and IRIS
-  Vector3ui crosshairs = m_Driver->GetCursorPosition();
-    
-  // String streams for different labels
-  IRISOStringStream sGrey,sSegmentation,sSpeed;
-
-  // Get the grey intensity
-  GenericImageData *id = m_Driver->GetCurrentImageData();
-  if (m_Driver->GetCurrentImageData()->IsGreyLoaded())
-    {
-    sGrey << id->GetGrey()->GetVoxelMappedToNative(crosshairs);
-    }
-
-  // Get the segmentation lavel intensity
-  int iSegmentation = (int) id->GetSegmentation()->GetVoxel(crosshairs);
-  sSegmentation << iSegmentation;
-
-  // Update the cursor position in the image info window
-  m_LayerUI->UpdateImageProbe();
-
-  // The rest depends on the current mode
-  if(m_GlobalState->GetSNAPActive())
-    {
-    // Fill the grey and label outputs
-    m_OutSNAPProbe->value(sGrey.str().c_str());
-    m_OutSNAPLabelProbe->value(sSegmentation.str().c_str());
-
-    // Get a pointer to the speed image wrapper
-    SNAPImageData *snap = m_Driver->GetSNAPImageData();
-
-    // Get the speed value (if possible)
-    if(m_GlobalState->GetSpeedPreviewValid())
-      {
-      // Speed preview is being shown.  Get a preview pixel
-      sSpeed << std::setprecision(4) << 
-        snap->GetSpeed()->GetPreviewVoxel(crosshairs);
-      }
-    else if(m_GlobalState->GetSpeedValid())
-      {
-      // Speed image is valid, i.e., has been properly computed
-      sSpeed << std::setprecision(4) << 
-        snap->GetSpeed()->GetVoxel(crosshairs);
-      }
-    else 
-      {
-      sSpeed << "N/A";
-      }
-
-    // Display the speed string
-    m_OutSNAPSpeedProbe->value(sSpeed.str().c_str());
-    }
-  else
-    {
-    m_OutGreyProbe->value(sGrey.str().c_str());
-    m_OutLabelProbe->value(sSegmentation.str().c_str());
-
-    // Get the label description
-    ColorLabel cl = 
-      m_Driver->GetColorLabelTable()->GetColorLabel(iSegmentation);
-    m_OutLabelProbeText->value(cl.GetLabel());      
-    }
-}
-
-void 
-UserInterfaceLogic
-::UpdateMainLabel() 
-{
-  // Get the main image name
-  string fnMain = "";
-  if(m_Activation->GetFlag(UIF_GRAY_LOADED))
-    fnMain = m_GlobalState->GetGreyFileName();
-  else if(m_Activation->GetFlag(UIF_RGB_LOADED))
-    fnMain = m_GlobalState->GetRGBFileName();
-  // Truncate the main image file    
-  if(fnMain.length())
-    fnMain = itksys::SystemTools::GetFilenameName(fnMain);
-  else
-    fnMain = "[No Image]";
-
-  // Get the segmentation file name
-  string fnSeg = m_GlobalState->GetSegmentationFileName();
-  if(fnSeg.length())
-    fnSeg = itksys::SystemTools::GetFilenameName(fnSeg);
-  else
-    fnSeg = "[New Segmentation]";
-
-  // Build up the label
-  std::ostringstream oss;
-
-  // Print the main image
-  oss << fnMain;
-  
-  // TODO: print if the main image is dirty
-
-  // Print the segmentation image
-  if(fnMain != "[No Image]")
-    {
-    oss << " - " << fnSeg;
-
-    // Print the * if image is dirty
-    if(m_Activation->GetFlag(UIF_UNSAVED_CHANGES))
-      oss << "*";
-    }
-
-  // Print program name and version
-  oss << " - " << SNAPSoftVersion;
-
-  // Store the label
-  m_MainWindowLabel = oss.str();
-
-  // Apply to the window
-  m_WinMain->label(m_MainWindowLabel.c_str());
-
-  return;
-}
-
-void 
-UserInterfaceLogic
-::OnEditLabelsAction()
-{
-  // Get the currently selected color index
-  LabelType iLabel = (LabelType) (size_t) 
-    m_InDrawingColor->mvalue()->user_data();
-  m_LabelEditorUI->OnLabelListUpdate(iLabel);
-
-  // Display the label editor
-  m_LabelEditorUI->DisplayWindow();
-}
-
-void 
-UserInterfaceLogic
-::UpdateEditLabelWindow() 
-{
-  /** 
-  // Get properties from VoxData
-  int index = m_ColorMap[m_InDrawingColor->value()];
-
-  // Get the color label
-  ColorLabel cl = m_Driver->GetCurrentImageData()->GetColorLabel(index);
-  assert(cl.IsValid());
-
-  // Set widgets in EditLabel window
-  m_InEditLabelName->value(cl.GetLabel());
-  m_InEditLabelAlpha->value(cl.GetAlpha() / 255.0);
-  m_InEditLabelVisibility->value(!cl.IsVisible());
-  m_InEditLabelMesh->value(!cl.IsVisibleIn3D());
-  m_BtnEditLabelChange->setonly();
-
-  // convert from uchar [0,255] to double [0.0,1.0]
-  m_GrpEditLabelColorChooser->rgb( cl.GetRGB(0)/255.0, cl.GetRGB(1)/255.0, cl.GetRGB(2)/255.0 );
-
-  // If this is clear label, assume we're going to add a label
-  if (index == 0) 
-    {
-    m_BtnEditLabelAdd->setonly();
-    m_InEditLabelName->value("New Label");
-    m_InEditLabelAlpha->value(1.0);
-    m_InEditLabelVisibility->clear();
-    m_InEditLabelMesh->clear();
-    }
-
-  char title[100];
-  sprintf(title, "Label No. %d", index);
-  m_WinEditLabel->label(title);
-  */
-  
-  
-}
-
-/*
-void 
-UserInterfaceLogic
-::ChangeLabelsCallback() 
-{
-  // Check the new label name
-  const char* new_name = m_InEditLabelName->value();
-  if (strlen(new_name) == 0) 
-    {
-    m_OutMessage->value("You must enter a non-null name");
-    return;
-    }
-
-  // Update the label Choice widgets
-  int offset;
-  if (m_BtnEditLabelAdd->value() == 1) 
-    {  // add a new label
-    offset = m_InDrawingColor->add(new_name);
-    m_InDrawOverColor->add(new_name);   
-    }
-  else 
-    {  // Replace an old label
-    offset = m_InDrawingColor->value();
-    if (!offset) 
-      {
-      m_OutMessage->value("You cannot recolor the clear color");
-      return;
-      }
-    m_InDrawingColor->replace(offset, new_name);
-    m_InDrawOverColor->replace(offset+2, new_name);
-    }
-  m_InDrawingColor->value(offset);
-  m_InDrawingColor->set_changed();
-
-  // Search for a place to put this new label
-  if (m_ColorMap[offset] <0) 
-    {
-    int i;
-    for (i=1; i<256 && m_Driver->GetCurrentImageData()->GetColorLabel(i).IsValid(); i++) 
-      {
-      }
-
-    m_ColorMap[offset] = i;
-    }
-
-  unsigned char rgb[3];
-  rgb[0] = (uchar) ( 255*m_GrpEditLabelColorChooser->r() );
-  rgb[1] = (uchar) ( 255*m_GrpEditLabelColorChooser->g() );
-  rgb[2] = (uchar) ( 255*m_GrpEditLabelColorChooser->b() );
-
-  // Send changes to the Voxel Data Structure
-  ColorLabel cl = m_Driver->GetCurrentImageData()->GetColorLabel(m_ColorMap[offset]);
-  cl.SetRGBVector(rgb);
-  cl.SetAlpha(static_cast<unsigned char>(255 * m_InEditLabelAlpha->value()));
-  cl.SetVisible(!m_InEditLabelVisibility->value());
-  cl.SetVisibleIn3D(!m_InEditLabelMesh->value());
-  cl.SetLabel(new_name);
-  cl.SetValid(true);
-
-  // Make sure that the display windows get the updated color labels
-  m_Driver->GetCurrentImageData()->SetColorLabel(m_ColorMap[offset],cl);
-
-  // Set the new current color in the GUI
-  m_GrpCurrentColor->color(fl_rgb_color(rgb[0], rgb[1], rgb[2]));
-
-  m_GlobalState->SetDrawingColorLabel((unsigned char) m_ColorMap[offset]);
-
-  // The segmentation has become dirty
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_DIRTY, true);
-
-  // Redraw the windows 
-  RedrawWindows();
-  m_WinMain->redraw();
-}
-*/
-
-/** 
- * This method is executed when the labels have been changed by the label editor
- * or by loading them from file
- */
-void
-UserInterfaceLogic
-::OnLabelListUpdate()
-{
-  // Update the drop down box of labels to reflect the current settings
-  UpdateColorLabelMenu();
-
-  // The label wrappers depend on color maps
-  m_Driver->GetCurrentImageData()->GetSegmentation()->UpdateColorMappingCache();
-  
-  // Repaint the windows
-  RedrawWindows();
-}
-
-void 
-UserInterfaceLogic
-::OnSliceSliderChange(int id) 
-{
-  // Get the new value depending on the current state
-  unsigned int value = (unsigned int) ( - m_InSliceSlider[id]->value());
-  
-  // Get the cursor position
-  Vector3ui cursor = m_Driver->GetCursorPosition();
-
-  // Determine which image axis the display window 'id' corresponds to
-  unsigned int imageAxis = GetImageAxisForDisplayWindow(id);
-
-  // Update the cursor
-  cursor[imageAxis] = value;
-  m_Driver->SetCursorPosition(cursor);
-  OnCrosshairPositionUpdate();
-
-  // Update the little display box under the scroll bar
-  UpdatePositionDisplay(id);
-
-  // Update the probe values
-  UpdateImageProbe();
-
-  // Repaint the windows
-  RedrawWindows();
-}
-
-void 
-UserInterfaceLogic
-::UpdatePositionDisplay(int id) 
-{
-  // Dump out the slice index of the given window
-  IRISOStringStream sIndex;
-  sIndex << std::setw(4) << (1 - m_InSliceSlider[id]->value());
-  sIndex << " of ";
-  sIndex << (1 - m_InSliceSlider[id]->minimum());
-  m_OutSliceIndex[id]->value(sIndex.str().c_str());
-}
-
-void 
-UserInterfaceLogic
-::OnClosePolygonAction(unsigned int window)
-{
-  m_IRISWindowManager2D[window]->GetPolygonDrawing()->ClosePolygon();  
-  OnPolygonStateUpdate(window);
-}
-
-void 
-UserInterfaceLogic
-::OnUndoPointPolygonAction(unsigned int window)
-{
-  m_IRISWindowManager2D[window]->GetPolygonDrawing()->DropLastPoint();  
-  OnPolygonStateUpdate(window);
-}
-
-void 
-UserInterfaceLogic
-::OnClearPolygonAction(unsigned int window)
-{
-  m_IRISWindowManager2D[window]->GetPolygonDrawing()->Reset();  
-  OnPolygonStateUpdate(window);
-}
-
-void 
-UserInterfaceLogic
-::OnAcceptPolygonAction(unsigned int window)
-{
-  if(m_IRISWindowManager2D[window]->AcceptPolygon())
-    {
-    // The polygon update was successful
-    OnPolygonStateUpdate(window);
-
-    // The segmentation has been dirtied
-    m_Activation->UpdateFlag(UIF_IRIS_MESH_DIRTY, true);
-
-    // Set the undo point
-    StoreUndoPoint("Polygon drawing");
-    }
-  else
-    {
-    // Probably, the draw-over-label is set incorrectly!
-    fl_message(
-      "The segmentation was not updated. Most likely, the 'Draw Over' label \n"
-      "is set incorrectly. Change it to 'All Labels' or 'Clear Label'.");
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnInsertIntoPolygonSelectedAction(unsigned int window)
-{
-  m_IRISWindowManager2D[window]->InsertPolygonPoints();  
-  OnPolygonStateUpdate(window);
-}
-
-void 
-UserInterfaceLogic
-::OnDeletePolygonSelectedAction(unsigned int window)
-{
-  m_IRISWindowManager2D[window]->DeleteSelectedPolygonPoints();
-  OnPolygonStateUpdate(window);
-}
-
-void 
-UserInterfaceLogic
-::OnPastePolygonAction(unsigned int window)
-{
-  m_IRISWindowManager2D[window]->PastePolygon();
-  OnPolygonStateUpdate(window);
-}
-
-void
-UserInterfaceLogic
-::OnIRISFreehandFittingRateUpdate()
-{
-  if(m_InIRISFreehandContinuous->value())
-    {
-    m_InIRISFreehandFittingRate->deactivate();
-    for(size_t i = 0; i < 3; i++)
-      {
-      m_IRISWindowManager2D[i]->SetFreehandFittingRate(0);  
-      }
-    }
-  else
-    {
-    m_InIRISFreehandFittingRate->activate();
-    for(size_t i = 0; i < 3; i++)
-      {
-      m_IRISWindowManager2D[i]->SetFreehandFittingRate(
-        m_InIRISFreehandFittingRate->value());
-      }
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnPolygonStateUpdate(unsigned int id)
-{
-  // Get the drawing object
-  PolygonDrawing *draw = m_IRISWindowManager2D[id]->GetPolygonDrawing();
-
-  if (draw->GetState() == PolygonDrawing::INACTIVE_STATE) 
-    {
-    // Point to the appropriate page
-    m_WizPolygon[id]->value(m_GrpPolygonInit[id]);
-
-    // Set the activation status of paste button
-    if(draw->GetCachedPolygon()) 
-      m_BtnPolygonPaste[id]->activate();
-    else
-      m_BtnPolygonPaste[id]->deactivate();      
-    }
-
-  else if(draw->GetState() == PolygonDrawing::DRAWING_STATE)
-    {
-    // Point to the appropriate page
-    m_WizPolygon[id]->value(m_GrpPolygonDraw[id]);
-
-    // Activate buttons based on status
-    if(draw->CanClosePolygon())
-      m_BtnPolygonClose[id]->activate();
-    else
-      m_BtnPolygonClose[id]->deactivate();
-
-    if(draw->CanDropLastPoint())
-      m_BtnPolygonUndoPoint[id]->activate();
-    else
-      m_BtnPolygonUndoPoint[id]->deactivate();
-
-    if(draw->CanDropLastPoint())
-      m_BtnPolygonClearDrawing[id]->activate();
-    else
-      m_BtnPolygonClearDrawing[id]->deactivate();
-    }
-  else
-    {
-    // Point to the appropriate page
-    m_WizPolygon[id]->value(m_GrpPolygonEdit[id]);
-
-    m_BtnPolygonAccept[id]->activate();
-    m_BtnPolygonClearEditing[id]->activate();
-
-    if(draw->GetSelectedVertices())
-      m_BtnPolygonDelete[id]->activate();
-    else
-      m_BtnPolygonDelete[id]->deactivate();
-
-    if(draw->CanInsertVertices())
-      m_BtnPolygonInsert[id]->activate();
-    else
-      m_BtnPolygonInsert[id]->deactivate();
-    }
-
-  // Redraw the windows
-  RedrawWindows();
-}
-
-void 
-UserInterfaceLogic
-::UpdatePaintbrushAttributes()
-{
-  PaintbrushSettings pbs = m_GlobalState->GetPaintbrushSettings();
-
-  // Get the mode (not nice C, but so be it)
-  int mode = (int) pbs.mode;
-  m_InPaintbrushShape->value(m_ChoicePaintbrush[mode]);
-  m_WizPaintbrushParameters->value(m_GrpPaintbrushParameters[mode]);
-
-  // Set the size
-  m_InPaintbrushSize->value(pbs.radius * 2.0);
-  
-  // Set the other parameters
-  m_BtnPaintbrushIsotropic->value(pbs.isotropic ? 1 : 0);
-  m_BtnPaintbrushChaseMode->value(pbs.chase ? 1 : 0);
-  m_BtnPaintbrush3D->value(pbs.flat ? 0 : 1);
-  m_InPaintbrushSmoothing->value(pbs.watershed.smooth_iterations);
-  m_InPaintbrushGranularity->value(pbs.watershed.level);  
-}
-
-// Change the settings of the paintbrush tool
-void
-UserInterfaceLogic
-::OnPaintbrushAttributesUpdate()
-{
-  // Get the current paintbrush settings
-  PaintbrushSettings pbs = m_GlobalState->GetPaintbrushSettings();
-
-  // Update the settings from the GUI
-  pbs.radius = 0.5 * m_InPaintbrushSize->value();
-  pbs.flat = m_BtnPaintbrush3D->value() ? false : true;
-  pbs.isotropic = m_BtnPaintbrushIsotropic->value() ? true : false;
-  pbs.chase = m_BtnPaintbrushChaseMode->value() ? true : false;
-
-  pbs.watershed.level = m_InPaintbrushGranularity->value();
-  pbs.watershed.smooth_iterations = (unsigned int) m_InPaintbrushSmoothing->value();
-
-  // Set the mode
-  pbs.mode = (PaintbrushMode) (m_InPaintbrushShape->value());
-
-  // Update the wizard
-  m_WizPaintbrushParameters->value(
-    m_GrpPaintbrushParameters[m_InPaintbrushShape->value()]);
-
-  // Set the paintbrush attributes
-  m_GlobalState->SetPaintbrushSettings(pbs);
-
-  // Update the windows
-  RedrawWindows();
-}
-
-void
-UserInterfaceLogic
-::OnAnnotationAttributesUpdate()
-{
-  // Get the current annotation settings
-  AnnotationSettings as = m_GlobalState->GetAnnotationSettings();
-
-  // Update the settings from the GUI
-  as.shownOnAllSlices = m_BtnAnnotationShownOnAllSlices->value() ? true : false;
-
-  // Set the annotation settings
-  m_GlobalState->SetAnnotationSettings(as);
-
-  // Update the windows
-  RedrawWindows();
-}
-
-void
-UserInterfaceLogic
-::OnPaintbrushPaint()
-{
-  // The user painted something. We should make it possible to modifu the mesh
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_DIRTY, true);
-}
-
-void 
-UserInterfaceLogic
-::OnMenuShowDisplayOptions()
-{
-  m_DlgAppearance->ShowDialog();
-}
-
-void 
-UserInterfaceLogic
-::OnMenuShowLayerInspector()
-{
-  // Make sure some image is loaded
-  assert(m_Driver->GetCurrentImageData()->IsMainLoaded());
-  m_LayerUI->DisplayWindow();
-}
-
-void
-UserInterfaceLogic
-::OnLayerInspectorUpdate()
-{
-  m_LayerUI->SetImageWrappers();
-  if (m_LayerUI->Shown())
-    {
-    m_LayerUI->RedrawWindow();
-    }
-}
-
-void
-UserInterfaceLogic
-::UpdateWindowFocus(Fl_Group *parent, Fl_Group **panels, Fl_Gl_Window **boxes, int iWindow)
-{
-  /*
-  // The dimensions of the parent window
-  int x = parent->x(), y = parent->y();
-  int w = parent->w(), h = parent->h();
-
-  // Check if this is an expansion or a collapse operation
-  if( iWindow < 0 || panels[iWindow]->w() == w )
-    {
-    // Restore all panels to original configuration
-    panels[0]->resize(x, y, w >> 1, h >> 1);
-    panels[1]->resize(x + (w >> 1), y, w - (w >> 1), h >> 1);
-    panels[3]->resize(x, y + (h >> 1), w >> 1, h - (h >> 1));
-    panels[2]->resize(x + (w >> 1), y + (h >> 1), w - (w >> 1), h - (h >> 1));
-
-    // Make the resizable is set to self
-    parent->resizable(parent);
-
-    // Show everything
-    for(unsigned int j = 0; j < 4; j++)
-      {
-      parent->add(panels[j]);
-      panels[j]->show();
-      boxes[j]->show();
-      panels[j]->redraw();
-      }
-
-    }
-  else 
-    {
-    for(int j = 0; j < 4; j++)
-      {
-      // We resize all the panels so that the zoom behaves
-      // properly in linked zoom mode
-      if(iWindow != j)
-        {
-        panels[j]->hide();
-        boxes[j]->hide();
-        parent->remove(panels[j]);
-        }
-      }
-      panels[iWindow]->resize(
-        parent->x(),parent->y(),
-        parent->w(),parent->h());
-      parent->resizable(panels[iWindow]);
-      panels[iWindow]->redraw();
-    }
-    */
-}
-
-void
-UserInterfaceLogic
-::OnWindowCollapse(int iWindow)
-{
-  // Make only one window visible
-  DisplayLayout dl = m_DisplayLayout;
-  dl.slice_config = (SliceViewConfiguration) (AXIAL + iWindow);
-  SetDisplayLayout(dl);
-
-  // Hide the interface
-  dl = m_DisplayLayout;
-  dl.show_main_ui = false; 
-  dl.show_panel_ui = false;
-  SetDisplayLayout(dl);
-
-  // Change the layout to half-size
-  dl = m_DisplayLayout;
-  dl.size = HALF_SIZE;
-  SetDisplayLayout(dl);
-
-  // Lastly, get rid of unused space
-  Vector2i optsize = m_SliceCoordinator->GetWindow(iWindow)->GetOptimalCanvasSize();
-  int w = std::min(optsize[0], m_WinMain->w());
-  int h = std::min(optsize[1], m_WinMain->h());
-  int x = m_WinMain->x() + (m_WinMain->w() - w) / 2;
-  int y = m_WinMain->y() + (m_WinMain->h() - h) / 2;
-  m_WinMain->resize(x, y, w, h);
-}
-
-void
-UserInterfaceLogic
-::OnWindowFocus(int iWindow)
-{
-  DisplayLayout dl = m_DisplayLayout;
-
-  // If <0, enter four-slice 
-  if(iWindow < 0)
-    dl.slice_config = FOUR_SLICE;
-
-  // If 0-4, act as a toggle
-  else if(dl.slice_config == AXIAL + iWindow)
-    dl.slice_config = FOUR_SLICE;
-
-  else 
-    dl.slice_config = (SliceViewConfiguration) (AXIAL + iWindow);
-
-  // Update layout
-  SetDisplayLayout(dl);
-}
-
-void
-UserInterfaceLogic
-::OnImageGeometryUpdate()
-{
-  if(!m_Driver->GetCurrentImageData()->IsMainLoaded())
-    return;
-
-  // Set the crosshairs to the center of the image
-  Vector3ui size = m_Driver->GetCurrentImageData()->GetVolumeExtents();
-  Vector3ui xCross = size / ((unsigned int) 2);
-  m_Driver->SetCursorPosition(xCross);
-
-  // Update the source for slice windows as well as scroll bars
-  for (unsigned int i=0; i<3; i++) 
-    {
-    if(m_GlobalState->GetSNAPActive())
-      m_SNAPWindowManager2D[i]->InitializeSlice(m_Driver->GetCurrentImageData());
-    else
-      {
-      m_IRISWindowManager2D[i]->InitializeSlice(m_Driver->GetCurrentImageData());
-	    }
-
-    // Get the image axis that corresponds to the display window i
-    unsigned int imageAxis = GetImageAxisForDisplayWindow(i);
-
-    // Notice the sliders have a negative range!  That's so that the 1 position 
-    // is at the bottom.  We need to always negate the slider values
-    m_InSliceSlider[i]->range( 1.0 - size[imageAxis], 0.0 );
-    m_InSliceSlider[i]->slider_size( 1.0/ size[imageAxis] );
-    m_InSliceSlider[i]->linesize(1);
-    }
-
-  // Reset the view in 2D windows to fit
-  m_SliceCoordinator->ResetViewToFitInAllWindows();
-
-  // Update the crosshairs display
-  OnCrosshairPositionUpdate();
-
-  // Update view positions
-  if(!m_GlobalState->GetSNAPActive())
-    OnViewPositionsUpdate();
-
-  // Fire zoom update event
-  OnZoomUpdate();
-}
-
-void 
-UserInterfaceLogic
-::OnMeshResetViewAction()
-{
-  if(m_GlobalState->GetSNAPActive())
-    m_SNAPWindowManager3D->ResetView();
-  else
-    m_IRISWindowManager3D->ResetView();
-  m_SliceWindow[3]->redraw();
-}
-
-void 
-UserInterfaceLogic
-::OnIRISMeshAcceptAction()
-{
-  m_IRISWindowManager3D->Accept();
-  RedrawWindows();
-  StoreUndoPoint("3D operation");
-  
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_ACTION_PENDING, false);
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_DIRTY, true);
-}
-
-void 
-UserInterfaceLogic
-::OnIRISMeshUpdateAction()
-{
-  // Update the mesh and redraw the window
-  m_IRISWindowManager3D->UpdateMesh(m_ProgressCommand);
-  m_SliceWindow[3]->redraw();
-
-  // This is a safeguard in case the progress events do not fire
-  m_WinProgress->hide();
-  
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_DIRTY, false);
-}
-
-void
-UserInterfaceLogic
-::OnIRISMeshEditingAction()
-{
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_ACTION_PENDING, true);
-}
-
-void
-UserInterfaceLogic
-::OnIRISMeshDisplaySettingsUpdate()
-{
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_DIRTY, true);
-}
-
-void
-UserInterfaceLogic
-::OnSNAPMeshUpdateAction()
-{
-  m_SNAPWindowManager3D->UpdateMesh(m_ProgressCommand);
-  m_SliceWindow[3]->redraw();
-
-  // This is a safeguard in case the progress events do not fire
-  m_WinProgress->hide();
-
-  m_Activation->UpdateFlag(UIF_SNAP_MESH_DIRTY, false);
-}
-
-void 
-UserInterfaceLogic
-::OnSNAPMeshContinuousUpdateAction()
-{
-  if (m_ChkContinuousView3DUpdate->value()) 
-    {
-    m_SNAPWindowManager3D->UpdateMesh(m_ProgressCommand);
-    m_Activation->UpdateFlag(UIF_SNAP_MESH_CONTINUOUS_UPDATE, true);
-    }
-  else 
-    {
-    m_Activation->UpdateFlag(UIF_SNAP_MESH_CONTINUOUS_UPDATE, false);
-    }
-}
-
-void 
-UserInterfaceLogic
-::SetToolbarMode(ToolbarModeType mode)
-{
-  // There must be an active image before we do this stuff
-  assert(m_Driver->GetCurrentImageData()->IsMainLoaded());
-
-  // Set the mode on the toolbar
-  m_GlobalState->SetToolbarMode(mode);
-
-  // Set the mode of each window
-  for(unsigned int i=0;i<3;i++)
-    {
-    switch(mode) 
-      {
-    case CROSSHAIRS_MODE:
-      m_IRISWindowManager2D[i]->EnterCrosshairsMode();
-      m_SNAPWindowManager2D[i]->EnterCrosshairsMode();
-      m_TabsToolOptions->value(m_GrpToolOptionCrosshairs);
-      m_BtnCrosshairsMode->setonly();
-      m_BtnSNAPCrosshairs->setonly();
-      break;
-
-    case NAVIGATION_MODE:
-      m_IRISWindowManager2D[i]->EnterZoomPanMode();
-      m_SNAPWindowManager2D[i]->EnterZoomPanMode();
-      m_TabsToolOptions->value(m_GrpToolOptionZoomPan);
-      m_BtnNavigationMode->setonly();
-      m_BtnSNAPNavigation->setonly();
-      break;
-
-    case POLYGON_DRAWING_MODE:
-      m_IRISWindowManager2D[i]->EnterPolygonMode();
-      m_TabsToolOptions->value(m_GrpToolOptionPolygon);
-      m_BtnPolygonMode->setonly();
-      break;
-
-    case PAINTBRUSH_MODE:
-      m_IRISWindowManager2D[i]->EnterPaintbrushMode();
-      m_TabsToolOptions->value(m_GrpToolOptionBrush);
-      m_BtnPaintbrushMode->setonly();
-      break;
-
-    case ANNOTATION_MODE:
-      m_IRISWindowManager2D[i]->EnterAnnotationMode();
-      m_TabsToolOptions->value(m_GrpToolOptionAnnotation);
-      m_BtnAnnotationMode->setonly();
-      break;
-
-    case ROI_MODE:
-      m_IRISWindowManager2D[i]->EnterRegionMode();
-      m_TabsToolOptions->value(m_GrpToolOptionSNAP);
-      m_BtnSNAPMode->setonly();
-      break;
-
-    default:
-      break;  
-      }
-
-    // Enable the polygon editing windows
-    if(mode == POLYGON_DRAWING_MODE)
-      m_WizPolygon[i]->show();
-    else
-      m_WizPolygon[i]->hide();
-
-    }
-
-  // Redraw the windows
-  RedrawWindows();
-}
-
-void 
-UserInterfaceLogic
-::SetToolbarMode3D(ToolbarMode3DType mode)
-{
-  switch (mode)
-    {
-    case TRACKBALL_MODE:
-      m_IRISWindowManager3D->EnterTrackballMode();
-      m_SNAPWindowManager3D->EnterTrackballMode();
-      m_BtnTrackballMode->setonly();
-      m_BtnSNAPTrackballMode3D->setonly();
-      break;
-
-    case CROSSHAIRS_3D_MODE:
-      m_IRISWindowManager3D->EnterCrosshairsMode();
-      m_SNAPWindowManager3D->EnterCrosshairsMode();
-      m_BtnCrosshair3DMode->setonly();
-      m_BtnSNAPCrosshairsMode3D->setonly();
-      break;
-
-    case SPRAYPAINT_MODE:
-      m_IRISWindowManager3D->EnterSpraypaintMode();
-      m_BtnSpraypaintMode->setonly();
-      break;
-
-    case SCALPEL_MODE:
-      m_IRISWindowManager3D->EnterScalpelMode();
-      m_BtnScalpelMode->setonly();
-      break;
-
-    default:
-      break;  
-    }
-
-  // Redraw the 3D windows
-  m_SliceWindow[3]->redraw();
-}
-
-void 
-UserInterfaceLogic
-::OnMenuShowVolumes() 
-{
-  // Display the load labels dialog
-  m_WinStatistics->show();
-  this->OnStatisticsUpdateAction();
-}
-
-void
-UserInterfaceLogic
-::OnStatisticsUpdateAction()
-{
-  SegmentationStatistics stats;
-  stats.Compute(m_Driver->GetCurrentImageData());
-  m_TableStatistics->SetSegmentationStatistics(stats, *m_Driver->GetColorLabelTable());
-  m_TableStatistics->redraw();
-}
-  
-void 
-UserInterfaceLogic
-::OnStatisticsExportAction()
-{
-  // Display the load labels dialog
-  m_DlgVoxelCountsIO->SetTitle("Save Volume Statistics");
-  m_DlgVoxelCountsIO->DisplaySaveDialog(
-    m_SystemInterface->GetHistory("VolumeStatistics"));
-}
-
-void 
-UserInterfaceLogic
-::OnStatisticsCopyAction()
-{
-  // Get the selection
-  string sel = m_TableStatistics->CopySelection();
-  Fl::copy(sel.c_str(), sel.length(), 1);
-}
-
-void 
-UserInterfaceLogic
-::OnMenuWriteVoxelCounts() 
-{
-  // Display the load labels dialog
-  m_DlgVoxelCountsIO->SetTitle("Save Volume Statistics");
-  m_DlgVoxelCountsIO->DisplaySaveDialog(
-    m_SystemInterface->GetHistory("VolumeStatistics"));
-}
-
-void 
-UserInterfaceLogic
-::OnWriteVoxelCountsAction() 
-{
-  // Get the selected file name
-  const char *file = m_DlgVoxelCountsIO->GetFileName();
-
-  // Try writing
-  try 
-    {
-    // Compute the statistics and write them to file
-    m_Driver->ExportSegmentationStatistics(file);
-    
-    // Update the history
-    m_SystemInterface->UpdateHistory("VolumeStatistics",file);
-    }
-  catch (itk::ExceptionObject &exc) 
-    {
-    // Alert the user to the failure
-    fl_alert("Error writing volume statistics:\n%s",exc.GetDescription());
-
-    // Rethrow the exception
-    throw;
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnGreyImageUnload()
-{
-  // This method is called when a grey image gets unloaded.  It saves the 
-  // current settings and associates them with the grey image file
-  if (!m_Driver->GetCurrentImageData()->IsGreyLoaded())
-    return;
-
-  // Make sure there is actually an image
-  string fnGrey = m_GlobalState->GetGreyFileName();
-  if(fnGrey.length())
-    m_SystemInterface->AssociateCurrentSettingsWithCurrentImageFile(
-      fnGrey.c_str(),m_Driver);
-}
-
-void
-UserInterfaceLogic
-::UnloadAllImages()
-{
-  // Close layer inspector if open
-  if (m_LayerUI->Shown())
-    m_LayerUI->OnCloseAction();
-
-  // Close reorient image dialog if open
-  if (m_DlgReorientImage->Shown())
-    m_DlgReorientImage->OnCloseAction();
-
-  // Close volumes and statistics if open
-  if(m_WinStatistics->shown())
-    m_WinStatistics->hide();
-
-  // Clear the memory and reset the flags
-  m_Driver->GetCurrentImageData()->UnloadMainImage();
-
-  if (m_GlobalState->GetSNAPActive())
-    {
-    m_SNAPWindowManager2D[0]->InitializeSlice(m_Driver->GetCurrentImageData());
-    m_SNAPWindowManager2D[1]->InitializeSlice(m_Driver->GetCurrentImageData());
-    m_SNAPWindowManager2D[2]->InitializeSlice(m_Driver->GetCurrentImageData());
-
-    m_SNAPWindowManager3D->ClearScreen();
-    m_SNAPWindowManager3D->ResetView();
-    } 
-  else
-    { 
-    m_IRISWindowManager2D[0]->InitializeSlice(m_Driver->GetCurrentImageData());
-    m_IRISWindowManager2D[1]->InitializeSlice(m_Driver->GetCurrentImageData());
-    m_IRISWindowManager2D[2]->InitializeSlice(m_Driver->GetCurrentImageData());
-    
-    m_IRISWindowManager3D->ClearScreen();
-    m_IRISWindowManager3D->ResetView();
-    }
-
-  m_Activation->UpdateFlag(UIF_OVERLAY_LOADED, false);
-  m_Activation->UpdateFlag(UIF_BASEIMG_LOADED, false);
-}
-
-void
-UserInterfaceLogic
-::OnMainImageUpdate()
-{
-  // Update the list of recently open files
-  GenerateRecentFilesMenu();
-
-  // Blank the screen - useful on a load of new grey data when there is 
-  // already a segmentation file present
-  m_IRISWindowManager3D->ClearScreen();
-
-  // Flip over to the toolbar page
-  m_WizControlPane->value(m_GrpToolbarPage);
-
-  // Enable some menu items
-  m_Activation->UpdateFlag(UIF_IRIS_WITH_BASEIMG_LOADED, true);
-
-  // Disable undo and redo 
-  m_Activation->UpdateFlag(UIF_UNDO_POSSIBLE, m_Driver->IsUndoPossible());
-  m_Activation->UpdateFlag(UIF_REDO_POSSIBLE, m_Driver->IsRedoPossible());
-
-  // There are now no unsaved changes
-  m_Activation->UpdateFlag(UIF_UNSAVED_CHANGES, false);
-
-  // Update the layer inspector
-  OnLayerInspectorUpdate();
-
-  // Image geometry has changed
-  OnImageGeometryUpdate();
-
-  m_InDrawingColor->set_changed();
-  m_InDrawOverColor->set_changed();
-
-  // Update the label of the UI
-  UpdateMainLabel();
-
-  m_GlobalState->SetSegmentationFileName("");
-
-  // Get the largest image region
-  GlobalState::RegionType roi = m_Driver->GetIRISImageData()->GetImageRegion();
-  
-  // Check if the region is real
-  if (roi.GetNumberOfPixels() == 0) 
-    {
-    m_Activation->UpdateFlag( UIF_IRIS_ROI_VALID, false );
-    m_GlobalState->SetIsValidROI(false);
-    } 
-  else 
-    {
-    m_Activation->UpdateFlag( UIF_IRIS_ROI_VALID, true );
-    m_GlobalState->SetSegmentationROI(roi);
-    m_GlobalState->SetIsValidROI(true);
-    }   
-
-  // Update the polygon buttons
-  OnPolygonStateUpdate(0);
-  OnPolygonStateUpdate(1);
-  OnPolygonStateUpdate(2);
-
-  // Now that we've loaded the image, check if there are any settings 
-  // associated with it.  If there are, give the user an option to restore 
-  // these settings
-  Registry associated;
-  if(m_SystemInterface->FindRegistryAssociatedWithFile(
-    m_GlobalState->GetGreyFileName(),associated)) // CHECK!!!
-    {
-    // Load the settings using RegistryIO
-    SNAPRegistryIO rio;
-    rio.ReadImageAssociatedSettings(associated,m_Driver,true,true,true,true);
-
-    // Update the opacity slider
-    m_InIRISLabelOpacity->value(m_GlobalState->GetSegmentationAlpha());
-
-    // Update the polygon inversion state
-    m_ChkInvertPolygon->value(m_GlobalState->GetPolygonInvert() ? 1 : 0);
-    }
-    
-  // Redraw the crosshairs in the 3D window  
-  m_IRISWindowManager3D->ResetView(); 
-
-  // Update the list of labels
-  OnLabelListUpdate();
-
-  // Redraw the user interface
-  RedrawWindows();
-  m_WinMain->redraw();
-}
-
-void 
-UserInterfaceLogic
-::OnGreyImageUpdate()
-{
-  // Disable/Enable some menu items
-  m_Activation->UpdateFlag(UIF_IRIS_WITH_GRAY_LOADED, true);
-
-  // Common user interface updates
-  OnMainImageUpdate();
-
-  // Warn if the image has been scaled
-  GreyTypeToNativeFunctor native = 
-    m_Driver->GetCurrentImageData()->GetGrey()->GetNativeMapping();
-  if(m_AppearanceSettings->GetFlagFloatingPointWarningByDefault() == 1 
-    && (native.scale != 1.0 || native.shift != 0.0))
-    {
-    m_WinPrecisionWarning->show();
-    if(m_ChkPrecisionWarningDisable->value())
-      m_AppearanceSettings->SetFlagFloatingPointWarningByDefault(false);
-    }
-}
-
-void
-UserInterfaceLogic
-::OnRGBImageUpdate()
-{
-  // Common user interface updates
-  OnMainImageUpdate();
-
-  // Disable/Enable some menu items
-  m_Activation->UpdateFlag(UIF_GRAY_LOADED, false);
-  m_Activation->UpdateFlag(UIF_RGB_LOADED, true);
-}
-
-void
-UserInterfaceLogic
-::UpdateOverlaySlice()
-{
-  // Update the source for slice windows
-  if (m_GlobalState->GetSNAPActive())
-    {
-    for (unsigned int i=0; i<3; i++)
-      m_SNAPWindowManager2D[i]->InitializeOverlaySlice(m_Driver->GetCurrentImageData());
-    }
-  else
-    {
-    for (unsigned int i=0; i<3; i++)
-      m_IRISWindowManager2D[i]->InitializeOverlaySlice(m_Driver->GetCurrentImageData());
-    }
-
-  if (!m_Driver->GetCurrentImageData()->IsOverlayLoaded())
-    m_Activation->UpdateFlag(UIF_OVERLAY_LOADED, false);
-}
-
-void 
-UserInterfaceLogic
-::OnOverlayImageUpdate()
-{
-  // a main image has to be loaded
-  assert(m_Driver->GetCurrentImageData()->IsMainLoaded());
-
-  // Update the source for slice windows
-  UpdateOverlaySlice();
-
-  // Update the layer inspector
-  OnLayerInspectorUpdate();
-
-  // Redraw the user interface
-  RedrawWindows();
-  m_WinMain->redraw();
-}
-
-void 
-UserInterfaceLogic
-::OnSegmentationImageUpdate(bool reloaded)
-{
-  // Certain things required only if image is reloaded
-  if(reloaded)
-    {
-    // When an image is reloaded, we clear the previous undo points
-    m_Driver->ClearUndoPoints();
-
-    // The list of labels may have changed
-    OnLabelListUpdate();
-
-    // The 3D window needs to be reset
-    // m_IRISWindowManager3D->ResetView();
-    }
-
-  // Toggle the undo/redo flags
-  m_Activation->UpdateFlag(UIF_UNDO_POSSIBLE, m_Driver->IsUndoPossible());
-  m_Activation->UpdateFlag(UIF_REDO_POSSIBLE, m_Driver->IsRedoPossible());
-
-  // The mesh is now dirty
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_DIRTY, true);
-
-  // Disable undo and redo 
-  RedrawWindows();
-  m_WinMain->redraw();
-}
-
-/* 
-void 
-UserInterfaceLogic
-::OnSegmentationLabelsUpdate(bool resetCurrentAndDrawOverLabels)
-{
-  InitColorMap(resetCurrentAndDrawOverLabels);
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_DIRTY, true);
-  
-  m_WinMain->redraw();          
-  m_OutMessage->value("Loading Label file successful");
-}
-*/
-
-void 
-UserInterfaceLogic
-::OnSpeedImageUpdate()
-{
-  if(m_GlobalState->GetSpeedValid())
-    {
-    // Set UI state
-    m_Activation->UpdateFlag(UIF_SNAP_SPEED_AVAILABLE, true);
-
-    // Choose to view the preprocessed image
-    m_ChoiceSNAPView->value(m_MenuSNAPViewPreprocessed);
-    // m_RadioSNAPViewPreprocessed->setonly();
-
-    // Run the callback associated with that change
-    OnViewPreprocessedSelect();
-    }
-  else
-    {
-    // Set UI state
-    m_Activation->UpdateFlag(UIF_SNAP_SPEED_AVAILABLE, false);
-
-    // Choose to view the grey image
-    m_ChoiceSNAPView->value(m_MenuSNAPViewOriginal);
-    // m_RadioSNAPViewOriginal->setonly();
-
-    // Run the callback associated with that change
-    OnSNAPViewOriginalSelect();
-    }
-
-  // Make sure color mapping is correct
-  UpdateSpeedColorMap();
-}
-
-// This method should be called whenever the UI starts and every time that
-// the history is updated.
-void 
-UserInterfaceLogic
-::GenerateRecentFilesMenu()
-{
-  // Load the list of recent files from the history file
-  const SystemInterface::HistoryListType &history = 
-    m_SystemInterface->GetHistory("MainImage");
-
-  // Take the five most recent items and create menu items
-  for(unsigned int i = 0; i < 5; i++)
-    {
-    // Get a pointer to the corresponding menu item
-    Fl_Menu_Item *item = m_MenuLoadPreviousFirst + i;
-
-    // Update it
-    if( i < history.size()) 
-      {
-      // Populate each of the menu items
-      m_RecentFileNames[i] = history[history.size() - (i+1)];
-      item->label(m_RecentFileNames[i].c_str());
-      item->activate();
-      }
-    else
-      {
-      m_RecentFileNames[i] = "Not Available";
-      item->label(m_RecentFileNames[i].c_str());
-      item->activate();
-      }
-    }
-
-  // Enable / disable the overall menu
-  if(history.size())
-    m_MenuLoadPrevious->activate();
-  else
-    m_MenuLoadPrevious->deactivate();
-}
-
-void
-UserInterfaceLogic
-::OnLoadRecentAction(unsigned int iRecent)
-{
-  // Make sure the user doesn't lose any data
-  if(!PromptBeforeLosingChanges(REASON_LOAD_MAIN)) return;
-
-  // Get the history of grayscale images. Here we must be careful that every time
-  // the history is updated, we also remember to update the recent files menu!!!
-  const SystemInterface::HistoryListType &history = 
-    m_SystemInterface->GetHistory("MainImage");
-
-  // Check that the history is OK
-  if(history.size() <= iRecent)
-    {
-    fl_alert("Unable to load recent file due to internal error!");
-    return;
-    }
-
-  // Get the recent file name
-  string fnRecent = m_RecentFileNames[iRecent];
-
-  // Determine if the file is a grey or a RGB image
-  bool isGrey = false;
-  const SystemInterface::HistoryListType &greyHistory = 
-    m_SystemInterface->GetHistory("GreyImage");
-  for (unsigned int i = 0; i < greyHistory.size(); ++i)
-    if (fnRecent == greyHistory[i])
-      isGrey = true;
-
-  // Show a wait cursor
-  m_WinMain->cursor(FL_CURSOR_WAIT, FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-
-  // TODO: At some point, we have to prompt the user that there are unsaved changes...
-  try
-    {
-    // Load the file non-interactively
-    if (isGrey)
-      NonInteractiveLoadGrey(fnRecent.c_str());
-    else
-      NonInteractiveLoadRGB(fnRecent.c_str());
-
-    // Restore the cursor
-    m_WinMain->cursor(FL_CURSOR_DEFAULT, FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-    }
-  catch(itk::ExceptionObject &exc) 
-    {
-    // Restore the cursor
-    m_WinMain->cursor(FL_CURSOR_DEFAULT, FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-
-    // Alert the user to the failure
-    fl_alert("Error loading image:\n%s",exc.GetDescription());
-    this->RedrawWindows();
-    }
-}
-
-bool
-UserInterfaceLogic
-::PromptBeforeLosingChanges(PromptReason reason)
-{
-  // If there are unsaved changes, ask the user if they want to quit
-  if(m_Activation->GetFlag(UIF_UNSAVED_CHANGES))
-    {
-    // Show the dialog
-    m_WinConfirmDiscard->show();
-    while(m_WinConfirmDiscard->shown())
-      Fl::wait();
-
-    // Check the value
-    return m_ChkHiddenDiscardChanges->value() == 1;
-    }
-  else
-    {
-    return true;
-    }
-}
-
-void
-UserInterfaceLogic
-::NonInteractiveLoadMainImage(const char *fname, bool force_grey, bool force_rgb)
-{
-  // Can't force both!
-  assert(!force_grey || !force_rgb);
-
-  // Perform the clean-up tasks before loading the image
-  OnGreyImageUnload();
-
-  // Remember the current toolbar mode
-  ToolbarModeType mode = m_GlobalState->GetToolbarMode();
- 
-  // Unload all image data
-  UnloadAllImages();
-
-  // Tell the driver to load the main image
-  IRISApplication::MainImageType intype = 
-    force_grey ? IRISApplication::MAIN_SCALAR : 
-    (force_rgb ? IRISApplication::MAIN_RGB : IRISApplication::MAIN_ANY);
-  IRISApplication::MainImageType type = m_Driver->LoadMainImage(fname, intype);
-
-  if(type == IRISApplication::MAIN_SCALAR)
-    {
-    // Update the system's history list
-    m_SystemInterface->UpdateHistory("GreyImage", 
-      itksys::SystemTools::CollapseFullPath(fname).c_str());
-
-    // Save the filename
-    m_GlobalState->SetGreyFileName(fname);
-    m_GlobalState->SetGreyExtension(fname);
-
-    // Update the user interface accordingly
-    OnGreyImageUpdate();
-    }
-  else
-    {
-    // Add the filename to the history
-    m_SystemInterface->UpdateHistory("RGBImage",  
-      itksys::SystemTools::CollapseFullPath(fname).c_str());
-
-    // Save the filename
-    m_GlobalState->SetRGBFileName(fname);
-
-    // Update the user interface accordingly
-    OnRGBImageUpdate();
-    }
-
-  // Recover the toolbar mode
-  SetToolbarMode(mode);
-
-  // Update the history for the main image
-  m_SystemInterface->UpdateHistory("MainImage", 
-    itksys::SystemTools::CollapseFullPath(fname).c_str());
-}
-
-void 
-UserInterfaceLogic
-::NonInteractiveLoadGrey(const char *fname)
-{
-  // Perform the clean-up tasks before loading the image
-  OnGreyImageUnload();
-
-  // Remember the current toolbar mode
-  ToolbarModeType mode = m_GlobalState->GetToolbarMode();
- 
-  // Unload all image data
-  UnloadAllImages();
-
-  // Load the image on the logical side
-  m_Driver->LoadMainImage(fname, IRISApplication::MAIN_SCALAR);
-
-  // Update the system's history list
-  m_SystemInterface->UpdateHistory("GreyImage", 
-    itksys::SystemTools::CollapseFullPath(fname).c_str());
-  m_SystemInterface->UpdateHistory("MainImage", 
-    itksys::SystemTools::CollapseFullPath(fname).c_str());
-
-  // Save the filename
-  m_GlobalState->SetGreyFileName(fname);
-  m_GlobalState->SetGreyExtension(fname);
-
-  // Update the user interface accordingly
-  OnGreyImageUpdate();
-
-  // Recover the toolbar mode
-  SetToolbarMode(mode);
-}
-
-void 
-UserInterfaceLogic
-::OnMenuLoadGrey() 
-{
-  // Make sure the user doesn't lose any data
-  if(!PromptBeforeLosingChanges(REASON_LOAD_MAIN)) return;
-
-  // Set the history for the input wizard
-  m_WizGreyIO->SetHistory(m_SystemInterface->GetHistory("GreyImage"));
-
-  // Show the input wizard with no file selected
-  m_WizGreyIO->DisplayInputWizard("", "Greyscale");
-
-  // If the load operation was successful, populate the data and GUI with the
-  // new image
-  if(m_WizGreyIO->IsImageLoaded())
-    {
-    // Perform the clean-up tasks before loading the image
-    OnGreyImageUnload();
-
-    // Remember the current toolbar mode
-    ToolbarModeType mode = m_GlobalState->GetToolbarMode();
- 
-    // Unload all image data
-    UnloadAllImages();
-
-    // Send the image and RAI to the IRIS application driver
-    m_Driver->UpdateIRISMainImage(
-      m_WizGreyIO->GetNativeImageIO(), IRISApplication::MAIN_SCALAR);
-    m_WizGreyIO->ReleaseImage();
-
-    // Update the system's history list
-    m_SystemInterface->UpdateHistory("GreyImage", m_WizGreyIO->GetFileName());
-    m_SystemInterface->UpdateHistory("MainImage", m_WizGreyIO->GetFileName());
-
-    // Save the filename
-    m_GlobalState->SetGreyFileName(m_WizGreyIO->GetFileName());
-    m_GlobalState->SetGreyExtension((char *)m_WizGreyIO->GetFileName());
-
-    // Update the user interface accordingly
-    OnGreyImageUpdate();
-
-    // Recover the toolbar mode
-    SetToolbarMode(mode);
-    }
-}
-
-void 
-UserInterfaceLogic
-::NonInteractiveLoadRGB(const char *fname)
-{
-  // Remember the current toolbar mode
-  ToolbarModeType mode = m_GlobalState->GetToolbarMode();
- 
-  // Unload all image data
-  UnloadAllImages();
-
-  // Perform the loading on the Logic side
-  m_Driver->LoadMainImage(fname, IRISApplication::MAIN_RGB);
-
-  // Add the filename to the history
-  m_SystemInterface->UpdateHistory("RGBImage",  
-    itksys::SystemTools::CollapseFullPath(fname).c_str());
-  m_SystemInterface->UpdateHistory("MainImage",  
-    itksys::SystemTools::CollapseFullPath(fname).c_str());
-
-  // Save the filename
-  m_GlobalState->SetRGBFileName(fname);
-
-  // Update the user interface accordingly
-  OnRGBImageUpdate();
-
-  // Recover the toolbar mode
-  SetToolbarMode(mode);
-}
-
-void 
-UserInterfaceLogic
-::NonInteractiveLoadOverlayImage(const char *fname, bool force_grey, bool force_rgb)
-{
-  // Can't force both
-  assert(!force_grey || !force_rgb);
-
-  // Load using the right type
-  IRISApplication::MainImageType intype = 
-    force_grey ? IRISApplication::MAIN_SCALAR : 
-    (force_rgb ? IRISApplication::MAIN_RGB : IRISApplication::MAIN_ANY);
-  IRISApplication::MainImageType type = m_Driver->LoadOverlayImage(fname, intype);
-
-  // Update the system's history list
-  if(type == IRISApplication::MAIN_SCALAR)
-    {
-    m_SystemInterface->UpdateHistory("GreyOverlay",
-      itksys::SystemTools::CollapseFullPath(fname).c_str());
-    }
-  else
-    {
-    m_SystemInterface->UpdateHistory("RGBOverlay",
-      itksys::SystemTools::CollapseFullPath(fname).c_str());
-    }
-
-  // Update the overall overlay history
-  m_SystemInterface->UpdateHistory("OverlayImage",
-    itksys::SystemTools::CollapseFullPath(fname).c_str());
-
-  // Set the state
-  m_Activation->UpdateFlag(UIF_OVERLAY_LOADED, true);
-
-  // Update the user interface accordingly
-  OnOverlayImageUpdate();
-}
-
-void 
-UserInterfaceLogic
-::OnMenuLoadRGB() 
-{
-  // Make sure the user doesn't lose any data
-  if(!PromptBeforeLosingChanges(REASON_LOAD_MAIN)) return;
-
-  // Create the wizard
-  RestrictedImageIOWizardLogic wizRGBIO;
-  wizRGBIO.MakeWindow();
-
-  // Allow only 3 components
-  wizRGBIO.SetNumberOfComponentsRestriction(3);
-
-  // Set the history for the input wizard
-  wizRGBIO.SetHistory(m_SystemInterface->GetHistory("RGBImage"));
-
-  // Show the input wizard with no file selected
-  wizRGBIO.DisplayInputWizard("", "RGB");
-
-  // If the load operation was successful, populate the data and GUI with the
-  // new image
-  if(wizRGBIO.IsImageLoaded())
-    {
-    // Unload all image data
-    UnloadAllImages();
-
-    // Remember the current toolbar mode
-    ToolbarModeType mode = m_GlobalState->GetToolbarMode();
- 
-    // Send the image and RAI to the IRIS application driver
-    m_Driver->UpdateIRISMainImage(
-      wizRGBIO.GetNativeImageIO(), IRISApplication::MAIN_RGB);
-
-    // Update the system's history list
-    m_SystemInterface->UpdateHistory("RGBImage",wizRGBIO.GetFileName());
-    m_SystemInterface->UpdateHistory("MainImage",wizRGBIO.GetFileName());
-
-    // Save the filename
-    m_GlobalState->SetRGBFileName(wizRGBIO.GetFileName());
-
-    // Update the user interface accordingly
-    OnRGBImageUpdate();
-
-    // Recover the toolbar mode
-    SetToolbarMode(mode);
-    }
-}
-
-void
-UserInterfaceLogic
-::OnMenuLoadGreyOverlay()
-{
-  // a main image should be loaded
-  assert(m_Driver->GetCurrentImageData()->IsMainLoaded());
-
-  // Should not be in SNAP mode
-  assert(!m_GlobalState->GetSNAPActive());
-
-  // Create the wizard
-  RestrictedImageIOWizardLogic wizGreyOverlayIO;
-  wizGreyOverlayIO.MakeWindow();
-
-  // Set up the input wizard with the main image
-  wizGreyOverlayIO.SetMainImage(
-    m_Driver->GetCurrentImageData()->GetMain()->GetImageBase());
-
-  // Set the history for the input wizard
-  wizGreyOverlayIO.SetHistory(
-    m_SystemInterface->GetHistory("GreyOverlay"));
-
-  // Show the input wizard
-  wizGreyOverlayIO.DisplayInputWizard(
-    m_GlobalState->GetGreyOverlayFileName(), "Greyscale overlay");
-
-  // If the load operation was successful, populate the data and GUI with the
-  // new image
-  if(wizGreyOverlayIO.IsImageLoaded())
-    {
-    // Send the image and RAI to the IRIS application driver
-    m_Driver->AddIRISOverlayImage(
-      wizGreyOverlayIO.GetNativeImageIO(), IRISApplication::MAIN_SCALAR);
-
-    // Update the system's history list
-    m_SystemInterface->UpdateHistory("GreyOverlay", wizGreyOverlayIO.GetFileName());
-    m_SystemInterface->UpdateHistory("OverlayImage", wizGreyOverlayIO.GetFileName());
-
-    // Save the filename
-    m_GlobalState->SetGreyOverlayFileName(wizGreyOverlayIO.GetFileName());
-
-    // Set the state
-    m_Activation->UpdateFlag(UIF_OVERLAY_LOADED, true);
-
-    // Update the user interface accordingly
-    OnOverlayImageUpdate();
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnMenuLoadRGBOverlay() 
-{
-  // Grey image should be loaded
-  assert(m_Driver->GetCurrentImageData()->IsMainLoaded());
-
-  // Should not be in SNAP mode
-  assert(!m_GlobalState->GetSNAPActive());
-
-  // Create the wizard
-  RestrictedImageIOWizardLogic wizRGBOverlayIO;
-  wizRGBOverlayIO.MakeWindow();
-
-  // Allow only 3 components
-  wizRGBOverlayIO.SetNumberOfComponentsRestriction(3);
-
-  // Set up the input wizard with the main image
-  wizRGBOverlayIO.SetMainImage(
-    m_Driver->GetCurrentImageData()->GetMain()->GetImageBase());
-
-  // Set the history for the input wizard
-  wizRGBOverlayIO.SetHistory(
-    m_SystemInterface->GetHistory("RGBOverlay"));
-
-  // Show the input wizard
-  wizRGBOverlayIO.DisplayInputWizard(
-    m_GlobalState->GetRGBOverlayFileName(), "RGB overlay");
-
-  // If the load operation was successful, populate the data and GUI with the
-  // new image
-  if (wizRGBOverlayIO.IsImageLoaded()) 
-    {
-    // Update the system's history list
-    m_SystemInterface->UpdateHistory("RGBOverlay",wizRGBOverlayIO.GetFileName());
-    m_SystemInterface->UpdateHistory("OverlayImage",wizRGBOverlayIO.GetFileName());
-
-    // Send the image and RAI to the IRIS application driver
-    m_Driver->AddIRISOverlayImage(
-      wizRGBOverlayIO.GetNativeImageIO(), IRISApplication::MAIN_RGB);
-
-    // Release memory
-    wizRGBOverlayIO.ReleaseImage();
-
-    // Save the filename
-    m_GlobalState->SetRGBOverlayFileName(wizRGBOverlayIO.GetFileName());
-
-    // Update the user interface accordingly
-    OnOverlayImageUpdate();
- 
-    // Set the state
-    m_Activation->UpdateFlag(UIF_OVERLAY_LOADED, true);
-    }
-}
-
-void
-UserInterfaceLogic
-::OnMenuUnloadOverlayLast()
-{
-  if (m_Driver->GetCurrentImageData()->IsOverlayLoaded())
-    m_Driver->UnloadOverlayLast();
-
-  // Update the state if necessary
-  if (!m_Driver->GetCurrentImageData()->IsOverlayLoaded())
-    m_Activation->UpdateFlag(UIF_OVERLAY_LOADED, false);
-
-  OnOverlayImageUpdate();
-}
-
-void
-UserInterfaceLogic
-::OnMenuUnloadOverlays()
-{
-  if (m_Driver->GetCurrentImageData()->IsOverlayLoaded())
-    m_Driver->UnloadOverlays();
-  
-  // Update the state
-  m_Activation->UpdateFlag(UIF_OVERLAY_LOADED, false);
-
-  OnOverlayImageUpdate();
-}
-
-void
-UserInterfaceLogic
-::NonInteractiveLoadLabels(const char *file)
-{
-  // Read the labels from file
-  m_Driver->GetColorLabelTable()->LoadFromFile(file);
-
-  // Reset the current drawing and overlay labels
-  m_GlobalState->SetDrawingColorLabel(
-    m_Driver->GetColorLabelTable()->GetFirstValidLabel());
-  m_GlobalState->SetOverWriteColorLabel(0);
-  
-  // Update the label editor window
-  m_LabelEditorUI->OnLabelListUpdate(
-    m_GlobalState->GetDrawingColorLabel());
-
-  // Update the user interface in response
-  OnLabelListUpdate();
-
-  // Update the history
-  m_SystemInterface->UpdateHistory("LabelDescriptions", 
-    itksys::SystemTools::CollapseFullPath(file).c_str());  
-}
-
-
-void 
-UserInterfaceLogic
-::OnLoadLabelsAction() 
-{
-  // Try reading the file
-  try 
-    {
-    // Read the labels from file
-    NonInteractiveLoadLabels(m_DlgLabelsIO->GetFileName());
-    }
-  catch (itk::ExceptionObject &exc) 
-    {
-    // Alert the user to the failure
-    fl_alert("Error loading labels:\n%s", exc.GetDescription());
-
-    // Rethrow the exception
-    throw;
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnSaveLabelsAction()
-{
-  // Get the selected file name
-  const char *file = m_DlgLabelsIO->GetFileName();
-
-  // Try writing
-  try 
-    {
-    // Write labels to the file
-    m_Driver->GetColorLabelTable()->SaveToFile(file);
-    
-    // Update the history
-    m_SystemInterface->UpdateHistory("LabelDescriptions",file);
-    }
-  catch (itk::ExceptionObject &exc) 
-    {
-    // Alert the user to the failure
-    fl_alert("Error writing labels:\n%s",exc.GetDescription());
-
-    // Rethrow the exception
-    throw;
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnMenuLoadLabels() 
-{
-  // Display the load labels dialog
-  m_DlgLabelsIO->SetTitle("Load Labels");
-  m_DlgLabelsIO->DisplayLoadDialog(
-    m_SystemInterface->GetHistory("LabelDescriptions"));
-}
-
-void UserInterfaceLogic
-::OnMenuSaveLabels() 
-{
-  // Display the save labels dialog
-  m_DlgLabelsIO->SetTitle("Save Labels");
-  m_DlgLabelsIO->DisplaySaveDialog(
-    m_SystemInterface->GetHistory("LabelDescriptions"));
-}
-
-void
-UserInterfaceLogic
-::OnActiveWindowSaveSnapshot(unsigned int window)
-{
-  // Generate a filename for the screenshot
-  std::string finput = GenerateScreenShotFilename();
-  
-  // Create a file chooser
-  std::string file = itksys::SystemTools::GetFilenameName(finput);
-  std::string path = itksys::SystemTools::GetFilenamePath(finput);
-
-  // Store the current directory
-  std::string dir = itksys::SystemTools::GetCurrentWorkingDirectory();
-  if (path.size())
-    {
-    itksys::SystemTools::ChangeDirectory(path.c_str());
-    }
-
-  // We need to get a filename for the export
-  Fl_Native_File_Chooser chooser;
-  chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
-  chooser.title("Save PNG Snapshot");
-  chooser.filter("PNG Files\t*.png");
-  if (path.size())
-    {
-    chooser.directory(path.c_str());
-    }
-  chooser.preset_file(file.c_str());
-  const char *fChosen = NULL;
-  if (chooser.show() == 0)
-    {
-    fChosen = chooser.filename();
-    }
-  
-  // Restore the current directory
-  itksys::SystemTools::ChangeDirectory(dir.c_str());
-
-  if(!fChosen || !strlen(fChosen))
-    return;
-
-  // Store the filename for incrementing numerical names
-  m_LastSnapshotFileName = fChosen;
-
-  // Check if the user omitted the extension
-  if(itksys::SystemTools::GetFilenameExtension(m_LastSnapshotFileName) == "")
-    m_LastSnapshotFileName = m_LastSnapshotFileName + ".png";
-
-  // Choose which window to save with
-  if(window < 4)
-    m_SliceWindow[window]->SaveAsPNG(m_LastSnapshotFileName.c_str());
-}
-
-void UserInterfaceLogic
-::OnMenuSaveScreenshot(unsigned int iSlice)
-{
-  size_t iWindow = 
-    m_Driver->GetDisplayWindowForAnatomicalDirection(
-      (AnatomicalDirection) iSlice);
-  OnActiveWindowSaveSnapshot(iWindow);
-}
-
-void 
-UserInterfaceLogic
-::OnMenuSaveScreenshotSeries(unsigned int iSlice)
-{
-  // iSlice needs to be between 0 and 2
-  assert (iSlice >= 0 && iSlice <= 2);
-
-  // iSlice refers to which anatomical direction the user wants to
-  // animate along (0 = axial, 1 = sagittal, 2 = coronal). We need
-  // to know which window that corresponds to, as well as what image
-  // dimension
-
-  // Find the display window corresponding to this anatomical direction
-  size_t iWindow = 
-    m_Driver->GetDisplayWindowForAnatomicalDirection(
-      (AnatomicalDirection) iSlice);
-
-  // Get the image slicing direction
-  size_t iImageDir = 
-    m_Driver->GetImageDirectionForAnatomicalDirection(
-      (AnatomicalDirection) iSlice);
-
-  // let the user pick the directory for saving the screenshots
-  Fl_Native_File_Chooser chooser;
-  chooser.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY);
-  chooser.title("Select the directory to save the screenshots");
-  const char *path = NULL;
-  if (chooser.show() == 0)
-    {
-    path = chooser.filename();
-    }
-  // set up the 1st snapshot name
-  std::string fname;
-  if (path && strlen(path))
-    {
-    fname = path;
-    }
-  else
-    {
-    return;
-    }
-  
-  switch (iSlice)
-  {
-    default:
-    case 0: fname += "axial0001.png";
-		  break;
-    case 1: fname += "sagittal0001.png";
-		  break;
-    case 2: fname += "coronal0001.png";
-		  break;
-  }
-  
-  // back up cursor location
-  Vector3ui xCrossImageOld = m_Driver->GetCursorPosition();
-  Vector3ui xCrossImage = xCrossImageOld;
-  Vector3ui xSize = m_Driver->GetCurrentImageData()->GetVolumeExtents();
-  xCrossImage[iImageDir] = 0;
-  
-  // turn sync off temporarily
-  unsigned int syncValue = m_BtnSynchronizeCursor->value();
-  m_BtnSynchronizeCursor->value(0);
-
-  for (size_t i = 0; i < xSize[iImageDir]; ++i)
-  {
-    m_Driver->SetCursorPosition(xCrossImage);
-    OnCrosshairPositionUpdate();
-    RedrawWindows();
-    m_SliceWindow[iWindow]->SaveAsPNG(fname.c_str());
-    xCrossImage[iImageDir]++;
-    m_LastSnapshotFileName = fname;
-    fname = GenerateScreenShotFilename();
-  }
-  
-  // recover the original cursor position
-  m_Driver->SetCursorPosition(xCrossImageOld);
-  OnCrosshairPositionUpdate();
-  RedrawWindows();  
-  
-  // turn sync back on
-  m_BtnSynchronizeCursor->value(syncValue);
-}
-
-void UserInterfaceLogic
-::OnMenuExportSlice(unsigned int iSlice)
-{
-  // Generate a default filename for this slice
-  static const char *defpref[3] = {"axial", "sagittal", "coronal"};
-  char deffn[40];
-
-  // Figure out what slice it is
-  size_t iSliceImg = 
-    m_Driver->GetImageDirectionForAnatomicalDirection((AnatomicalDirection) iSlice);
-
-  sprintf(deffn,"%s_slice_%04d.png", defpref[iSlice], 
-    m_Driver->GetCursorPosition()[iSliceImg] + 1);
-
-  // We need to get a filename for the export
-  Fl_Native_File_Chooser chooser;
-  chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
-  chooser.title("Export Slice As");
-  chooser.filter("Image Files\t*.{png,jpg,gif,tiff}");
-  chooser.preset_file(deffn);
-
-  if (chooser.show() == 0)
-    {
-    const char *fName = chooser.filename();
-    if (fName && strlen(fName))
-	    {
-      m_Driver->ExportSlice((AnatomicalDirection) iSlice, fName);
-	    }
-    }
-}
-
-void UserInterfaceLogic
-::OnSynchronizeCursorAction()
-{
-  if(m_BtnSynchronizeCursor->value())
-    {
-    // Send the cursor position to the rest of the world
-    OnCrosshairPositionUpdate();
-    }
-}
-
-void UserInterfaceLogic
-::OnMenuNewSegmentation()
-{
-  // Grey image should be loaded
-  assert(m_Driver->GetCurrentImageData()->IsMainLoaded());
-
-  // Should not be in SNAP mode
-  assert(!m_GlobalState->GetSNAPActive());
-
-  // Prompt to save changes
-  if(!PromptBeforeLosingChanges(REASON_LOAD_SEGMENTATION)) return;
-
-  // Get the driver to clear the image
-  m_Driver->ClearIRISSegmentationImage();
-
-  // There are now no unsaved changes
-  m_Activation->UpdateFlag(UIF_UNSAVED_CHANGES, false);
-
-  // Clear the segmentation file name
-  m_GlobalState->SetSegmentationFileName("");
-
-  // Update the main window label
-  UpdateMainLabel();
-
-  // Save the state of the Undo manager at the time the image was updated
-  m_UndoStateAtLastIO = m_Driver->GetUndoManager().GetState();
-
-  // Update the user interface
-  OnSegmentationImageUpdate(true);
-}
-
-void UserInterfaceLogic
-::LoadSegmentation(const bool noninteractive, const char *fname)
-{
-  // Grey image should be loaded
-  assert(m_Driver->GetCurrentImageData()->IsMainLoaded());
-
-  // Should not be in SNAP mode
-  assert(!m_GlobalState->GetSNAPActive());
-
-  // Set the history for the input wizard
-  m_WizSegmentationIO->SetHistory(m_SystemInterface->GetHistory("SegmentationImage"));
-
-  // Set up the input wizard with the grey image
-  m_WizSegmentationIO->SetMainImage(
-    m_Driver->GetCurrentImageData()->GetMain()->GetImageBase());
-
-  if(noninteractive)
-    {
-    m_WizSegmentationIO->NonInteractiveInputWizard(fname);
-    }
-  else
-    {
-    // Show the input wizard
-    m_WizSegmentationIO->DisplayInputWizard(
-      m_GlobalState->GetLastAssociatedSegmentationFileName(), "segmentation");
-    }
-
-  // If the load operation was successful, populate the data and GUI with the
-  // new image
-  if(m_WizSegmentationIO->IsImageLoaded()) 
-    {
-    // Update the system's history list
-    m_SystemInterface->UpdateHistory(
-      "SegmentationImage",m_WizSegmentationIO->GetFileName());
-
-    // Send the image and RAI to the IRIS application driver
-    try
-      {
-      m_Driver->UpdateIRISSegmentationImage(m_WizSegmentationIO->GetNativeImageIO());
-      }
-    catch(IRISException &exc)
-      {
-      fl_alert("Loading segmentation failed.\nReason: %s", exc.what());
-      }
-
-    // Discard all image data in the wizard
-    m_WizSegmentationIO->ReleaseImage();
-
-    // Save the segmentation file name
-    m_GlobalState->SetSegmentationFileName(m_WizSegmentationIO->GetFileName());
-    m_GlobalState->SetLastAssociatedSegmentationFileName(m_WizSegmentationIO->GetFileName());   
-
-    // There are now no unsaved changes
-    m_Activation->UpdateFlag(UIF_UNSAVED_CHANGES, false);
-
-    // Update the label of the main window
-    UpdateMainLabel();
-
-    // Save the state of the Undo manager at the time the image was updated
-    m_UndoStateAtLastIO = m_Driver->GetUndoManager().GetState();
-
-    // Segmentation has been updated
-    OnSegmentationImageUpdate(true);
-    }
-
-  // Disconnect the input wizard from the grey image
-  m_WizSegmentationIO->SetMainImage(NULL);
-
-}
-
-void UserInterfaceLogic
-::NonInteractiveLoadSegmentation(const char *fname)
-{
-  LoadSegmentation(true, fname);
-}
-
-void UserInterfaceLogic
-::OnMenuLoadSegmentation() 
-{
-  // Prompt to save changes
-  if(!PromptBeforeLosingChanges(REASON_LOAD_SEGMENTATION)) return;
-
-  LoadSegmentation(false);
-
-}
-
-void UserInterfaceLogic
-::OnMenuSaveGrey()
-{
-  // Set the history for the wizard
-  m_WizGreyIO->SetHistory(m_SystemInterface->GetHistory("GreyImage"));
-
-  // Save the segmentation
-  if(m_WizGreyIO->DisplaySaveWizard(
-    m_Driver->GetIRISImageData()->GetGrey()->GetImage(),
-    NULL, "Greyscale"))
-    {
-    // Update the history for the wizard
-    m_SystemInterface->UpdateHistory(
-      "GreyImage", m_WizGreyIO->GetSaveFileName());
-    }
-}
-
-void UserInterfaceLogic
-::OnMenuSaveGreyROI() 
-{
-  // Better be in snap
-  assert(m_GlobalState->GetSNAPActive());
-
-  // Set the history for the wizard
-  m_WizGreyIO->SetHistory(m_SystemInterface->GetHistory("GreyImage"));
-
-  // Save the segmentation
-  if(m_WizGreyIO->DisplaySaveWizard(
-    m_Driver->GetCurrentImageData()->GetGrey()->GetImage(),
-    NULL, "Greyscale"))
-    {
-    // Update the history for the wizard
-    m_SystemInterface->UpdateHistory(
-      "GreyImage",m_WizGreyIO->GetSaveFileName());
-    }
-}
-
-void UserInterfaceLogic
-::OnMenuSaveSegmentation() 
-{
-  // Better have a segmentation image
-  assert(m_Driver->GetIRISImageData()->IsSegmentationLoaded());
-
-  // Set the history for the wizard
-  m_WizSegmentationIO->SetHistory(
-    m_SystemInterface->GetHistory("SegmentationImage"));
-
-  // Save the segmentation
-  if(m_WizSegmentationIO->DisplaySaveWizard(
-    m_Driver->GetIRISImageData()->GetSegmentation()->GetImage(),
-    m_GlobalState->GetLastAssociatedSegmentationFileName(),
-    "segmentation"))
-    {
-    // Update the history for the wizard
-    m_SystemInterface->UpdateHistory(
-      "SegmentationImage",m_WizSegmentationIO->GetSaveFileName());
-
-    // Store the new filename
-    m_GlobalState->SetSegmentationFileName(
-      m_WizSegmentationIO->GetSaveFileName());
-    m_GlobalState->SetLastAssociatedSegmentationFileName(
-      m_WizSegmentationIO->GetSaveFileName());
-
-    // Save the state of the undo manager
-    m_UndoStateAtLastIO = m_Driver->GetUndoManager().GetState();
-
-    // The segmentation is no longer dirty
-    m_Activation->UpdateFlag(UIF_UNSAVED_CHANGES, false);
-
-    }
-}
-
-void UserInterfaceLogic
-::OnMenuSaveSegmentationMesh() 
-{
-  // Better have a segmentation image
-  assert(m_Driver->GetIRISImageData()->IsSegmentationLoaded() 
-    || m_Driver->GetSNAPImageData()->IsSnakeLoaded());
-
-  // Send the history information to the wizard
-  m_WizMeshExport->SetHistory(
-    m_SystemInterface->GetHistory("SegmentationMesh"));
-
-  // Display the segmentation wizard
-  if(m_WizMeshExport->DisplayWizard(m_Driver, m_GlobalState->GetSNAPActive()))
-    {
-    // Get the save settings
-    MeshExportSettings sets = m_WizMeshExport->GetExportSettings();
-
-    // Use the settings to save the mesh
-    m_Driver->ExportSegmentationMesh(sets, m_ProgressCommand);
-
-    // Update the history
-    m_SystemInterface->UpdateHistory("SegmentationMesh", sets.GetMeshFileName().c_str());
-    }
-}
-
-void
-UserInterfaceLogic
-::OnMenuLoadAdvection()
-{
-  typedef itk::OrientedImage<float, 3> AdvectionImage;
-  AdvectionImage::Pointer imgAdvection[3];
-  
-  // Preprocessing image can only be loaded in SNAP mode
-  assert(m_GlobalState->GetSNAPActive());
-  
-  // Set up the input wizard with the grey image
-  m_WizPreprocessingIO->SetMainImage(
-    m_Driver->GetCurrentImageData()->GetMain()->GetImageBase());
-
-  // Load the three advection images as floating point
-  bool flagLoadCompleted = true;
-  for(unsigned int i=0;i<3;i++)
-    {
-    // Set the history for the input wizard
-    m_WizPreprocessingIO->SetHistory(
-      m_SystemInterface->GetHistory("AdvectionImage"));
-
-    // Show the input wizard
-    m_WizPreprocessingIO->DisplayInputWizard(
-      m_GlobalState->GetAdvectionFileName(i), "ITK-SNAP preprocessing");
-
-    // If the load operation was successful, populate the data and GUI with the
-    // new image
-    if(m_WizPreprocessingIO->IsImageLoaded()) 
-      {
-      // Update the system's history list
-      m_SystemInterface->UpdateHistory(
-        "AdvectionImage",m_WizPreprocessingIO->GetFileName());
-
-      // Update the application with the new speed image
-      CastNativeImageToScalar<float> caster;
-      imgAdvection[i] = caster(m_WizPreprocessingIO->GetNativeImageIO());
-      m_WizPreprocessingIO->ReleaseImage();
-
-      // Save the segmentation file name
-      m_GlobalState->SetAdvectionFileName(i, m_WizPreprocessingIO->GetFileName());
-      }
-    else
-      {
-      flagLoadCompleted = false;
-      break;
-      }
-    }
-  
-  // Disconnect the input wizard from the grey image
-  m_WizPreprocessingIO->SetMainImage(NULL);
-
-  // Add the advection image to SNAP
-  if(flagLoadCompleted)
-    m_Driver->GetSNAPImageData()->SetExternalAdvectionField(
-      imgAdvection[0],imgAdvection[1],imgAdvection[2]);
-}
-
-void 
-UserInterfaceLogic
-::OnLoadPreprocessedImageAction() 
-{
-  // Preprocessing image can only be loaded in SNAP mode
-  assert(m_GlobalState->GetSNAPActive());
-  
-  // Set up the input wizard with the grey image
-  m_WizPreprocessingIO->SetMainImage(
-    m_Driver->GetCurrentImageData()->GetMain()->GetImageBase());
-
-  // Set the history for the input wizard
-  m_WizPreprocessingIO->SetHistory(
-    m_SystemInterface->GetHistory("PreprocessingImage"));
-
-  // Show the input wizard
-  m_WizPreprocessingIO->DisplayInputWizard(
-    m_GlobalState->GetLastAssociatedPreprocessingFileName(), "ITK-SNAP preprocessing");
-
-  // If the load operation was successful, populate the data and GUI with the
-  // new image
-  if(m_WizPreprocessingIO->IsImageLoaded()) 
-    {
-    // Update the system's history list
-    m_SystemInterface->UpdateHistory(
-      "PreprocessingImage",m_WizPreprocessingIO->GetFileName());
-
-    // Cast image to float
-    CastNativeImageToScalar<float> caster;
-    IRISApplication::SpeedImageType::Pointer imgSpeed = 
-      caster(m_WizPreprocessingIO->GetNativeImageIO());
-    m_WizPreprocessingIO->ReleaseImage();
-
-    // Update the application with the new speed image
-    m_Driver->UpdateSNAPSpeedImage(imgSpeed,
-      m_RadSnakeEdge->value() ? EDGE_SNAKE : IN_OUT_SNAKE);
-    
-    // Save the segmentation file name
-    m_GlobalState->SetPreprocessingFileName(m_WizPreprocessingIO->GetFileName());
-    m_GlobalState->SetLastAssociatedPreprocessingFileName(m_WizPreprocessingIO->GetFileName());
-
-    // Update the UI flag
-    m_Activation->UpdateFlag(UIF_SNAP_PREPROCESSING_DONE, true);
-
-    // Update the user interface accordingly
-    OnSpeedImageUpdate();
-    }
-
-  // Disconnect the input wizard from the grey image
-  m_WizPreprocessingIO->SetMainImage(NULL);
-}
-
-void 
-UserInterfaceLogic
-::OnMenuSavePreprocessed() 
-{
-  // Better have a speed image to save
-  assert(m_GlobalState->GetSpeedValid());
-
-  // Set the history for the wizard
-  m_WizPreprocessingIO->SetHistory(
-    m_SystemInterface->GetHistory("PreprocessingImage"));
-
-  // Save the speed
-  if(m_WizPreprocessingIO->DisplaySaveWizard(
-    m_Driver->GetSNAPImageData()->GetSpeed()->GetImage(),
-    m_GlobalState->GetLastAssociatedPreprocessingFileName(),
-    "ITK-SNAP preprocessing"))
-    {
-    // Update the history for the wizard
-    m_SystemInterface->UpdateHistory(
-      "PreprocessingImage",m_WizPreprocessingIO->GetSaveFileName());
-    
-    // Store the new filename
-    m_GlobalState->SetPreprocessingFileName(
-      m_WizPreprocessingIO->GetSaveFileName());
-    m_GlobalState->SetLastAssociatedPreprocessingFileName(
-      m_WizPreprocessingIO->GetSaveFileName());
-    }
-}
-
-void 
-UserInterfaceLogic
-::OnMenuSaveLevelSet() 
-{
-  // Better have a snake image to save
-  assert(m_Driver->GetSNAPImageData()->IsSnakeLoaded());
-
-  // Set the history for the wizard
-  m_WizLevelSetIO->SetHistory(
-    m_SystemInterface->GetHistory("LevelSetImage"));
-
-  // Save the speed
-  if(m_WizLevelSetIO->DisplaySaveWizard(
-    m_Driver->GetSNAPImageData()->GetSnake()->GetImage(),
-    m_GlobalState->GetLevelSetFileName(),
-    "ITK-SNAP levelset"))
-    {
-    // Update the history for the wizard
-    m_SystemInterface->UpdateHistory(
-      "LevelSetImage", m_WizLevelSetIO->GetSaveFileName());
-    
-    // Store the new filename
-    m_GlobalState->SetLevelSetFileName(
-      m_WizPreprocessingIO->GetSaveFileName());
-    }
-}
-
-void UserInterfaceLogic
-::OnMenuIntensityCurve() 
-{
-  // The image should be loaded before bringing up the curve
-  assert(m_Driver->GetCurrentImageData()->IsGreyLoaded());
-
-  // Show the window
-  m_LayerUI->DisplayImageContrastTab();
-}
-
-void UserInterfaceLogic
-::OnMenuColorMap() 
-{
-  // The image should be loaded before bringing up the color map
-  assert(m_Driver->GetCurrentImageData()->IsGreyLoaded());
-
-  // Show the window
-  m_LayerUI->DisplayColorMapTab();
-}
-
-void
-UserInterfaceLogic
-::OnIRISLabelOpacityChange()
-{
-  m_GlobalState->SetSegmentationAlpha( (unsigned char) m_InIRISLabelOpacity->value());  
-  RedrawWindows();
-}
-
-void
-UserInterfaceLogic
-::OnSNAPLabelOpacityChange()
-{
-  m_GlobalState->SetSegmentationAlpha( (unsigned char) m_InSNAPLabelOpacity->value());  
-  RedrawWindows();
-}
-
-void
-UserInterfaceLogic
-::OnLaunchTutorialAction()
-{
-  // Find the tutorial file name
-  ShowHTMLPage("Tutorial.html");
-}
-
-void
-UserInterfaceLogic
-::ShowHTMLPage(const char *link)
-{
-  // Get the path to the file name
-  string completeLink = string("HTMLHelp/") +  link;
-  string file = 
-    m_SystemInterface->GetFileInRootDirectory(completeLink.c_str());
-
-  // Show the help window
-  m_HelpUI->ShowHelp(file.c_str());  
-}
-
-void 
-UserInterfaceLogic
-::OnMenuCheckForUpdate()
-{
-  // Show a wait cursor
-  m_WinMain->cursor(FL_CURSOR_WAIT, FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-
-  // Check for updates using new socket code
-  std::string nver;
-  SystemInterface::UpdateStatus us = 
-    m_SystemInterface->CheckUpdate(nver, 1, 0, true);
-  std::string message;
-  int response = 0;
-  if(us == SystemInterface::US_UP_TO_DATE)
-    {
-    fl_message("Your version of ITK-SNAP is up to date");
-    }
-  else if(us == SystemInterface::US_OUT_OF_DATE)
-    {
-    response = fl_choice(
-      "A newer ITK-SNAP version %s is available!",
-      "Download Later", "Download Now", NULL, nver.c_str());
-    if (response)
-      {
-      fl_open_uri("http://www.itksnap.org/pmwiki/pmwiki.php?n=Main.Downloads");
-      }
-    }
-  else if(us == SystemInterface::US_CONNECTION_FAILED)
-    {
-    response = fl_choice(
-      "Could not connect to server.\n"
-      "Visit itksnap.org to see if a new version is available",
-      "Later", "Take me there now", NULL);
-    if (response)
-      {
-      fl_open_uri("http://www.itksnap.org/pmwiki/pmwiki.php?n=Main.Downloads");
-      }
-    }
-
-  // Show a wait cursor
-  m_WinMain->cursor(FL_CURSOR_DEFAULT, FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-}
-
-void 
-UserInterfaceLogic
-::OnCheckForUpdate()
-{
-  // Show a wait cursor
-  m_WinMain->cursor(FL_CURSOR_WAIT, FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-
-  // Check for updates using new socket code
-  std::string nver;
-  SystemInterface::UpdateStatus us = 
-    m_SystemInterface->CheckUpdate(nver, 1, 0);
-  std::string message;
-  int response = 0;
-  if (us == SystemInterface::US_OUT_OF_DATE)
-    {
-    message = "A newer ITK-SNAP version " + nver + " is available!";
-    response = fl_choice(
-      "A newer ITK-SNAP version %s is available!",
-      "Download Later", "Download Now", NULL, nver.c_str());
-    if (response)
-      {
-      fl_open_uri("http://www.itksnap.org/pmwiki/pmwiki.php?n=Main.Downloads");
-      }
-    }
-
-  // Show a wait cursor
-  m_WinMain->cursor(FL_CURSOR_DEFAULT, FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-}
-
-void
-UserInterfaceLogic
-::ShowSplashScreen()
-{
-  // Place the window in the center of display
-  CenterChildWindowInMainWindow(m_WinSplash);
-
-  // Show the splash screen
-  m_WinSplash->show();
-
-  // Show a wait cursor
-  m_WinSplash->cursor(FL_CURSOR_WAIT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-  m_WinMain->cursor(FL_CURSOR_WAIT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-
-  // Make FL update the screen
-  Fl::check();
-
-  // Save the time of the splash screen
-  m_SplashScreenStartTime = clock();
-}
-
-void
-UserInterfaceLogic
-::HideSplashScreen()
-{
-  // Wait a second with the splash screen
-  while(clock() - m_SplashScreenStartTime < CLOCKS_PER_SEC) {}
-
-  // Clear the cursor
-  m_WinMain->cursor(FL_CURSOR_DEFAULT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-  m_WinSplash->cursor(FL_CURSOR_DEFAULT,FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR);
-  
-  // Hide the screen 
-  m_WinSplash->hide();
-
-  // Check for available update
-  int response = 0;
-  if (m_AppearanceSettings->GetFlagEnableAutoCheckForUpdateByDefault() == -1)
-    {
-    response = fl_choice("ITK-SNAP can check for software update automatically. Do you want to enable this feature?", "No Thanks", "Yes, please", NULL);
-    if (response)
-      {
-      m_AppearanceSettings->SetFlagEnableAutoCheckForUpdateByDefault(1);
-	 OnCheckForUpdate();
-	 }
-    else
-      m_AppearanceSettings->SetFlagEnableAutoCheckForUpdateByDefault(0);
-    m_AppearanceSettings->SaveToRegistry(m_SystemInterface->Folder("UserInterface.AppearanceSettings"));
-    }
-  else if (m_AppearanceSettings->GetFlagEnableAutoCheckForUpdateByDefault())
-    OnCheckForUpdate();
-}
-
-void
-UserInterfaceLogic
-::UpdateSplashScreen(const char *message)
-{
-  m_OutSplashMessage->label(message);
-  Fl::check();
-
-  // Save the time of the splash screen
-  m_SplashScreenStartTime = clock();
-}
-
-void
-UserInterfaceLogic
-::CenterChildWindowInParentWindow(Fl_Window *childWindow,
-                                  Fl_Window *parentWindow)
-{
-  int px = parentWindow->x() + (parentWindow->w() - childWindow->w()) / 2;
-  int py = parentWindow->y() + (parentWindow->h() - childWindow->h()) / 2;
-  childWindow->resize(px,py,childWindow->w(),childWindow->h());
-}
-
-void 
-UserInterfaceLogic
-::CenterChildWindowInMainWindow(Fl_Window *childWindow)
-{
-  CenterChildWindowInParentWindow(childWindow,m_WinMain);
-}
-
-void
-UserInterfaceLogic
-::OnResetView2DAction(unsigned int window)
-{
-  // Resets to optimal fit
-  m_SliceCoordinator->ResetViewToFitInOneWindow(window);
-
-  // Update the zoom level display
-  OnZoomUpdate();
-
-  // Update the view position
-  OnViewPositionsUpdate();
-}
-
-void
-UserInterfaceLogic
-::OnResetAllViews2DAction()
-{
-  m_SliceCoordinator->ResetViewToFitInAllWindows();
-
-  // Update the zoom level display
-  OnZoomUpdate();
-
-  // Update the view position
-  OnViewPositionsUpdate();
-}
-
-void
-UserInterfaceLogic
-::OnLinkedZoomChange()
-{
-  if(m_ChkLinkedZoom->value() > 0)
-    {
-    m_SliceCoordinator->SetLinkedZoom(true);
-    m_Activation->UpdateFlag(UIF_LINKED_ZOOM, true);
-    }
-  else
-    {
-    m_ChkMultisessionZoom->value(0);
-    m_ChkMultisessionPan->value(0);
-    m_SliceCoordinator->SetLinkedZoom(false);
-    m_Activation->UpdateFlag(UIF_LINKED_ZOOM, false);
-    }
-  
-  // Update the zoom level display
-  OnZoomUpdate();
-}
-
-void
-UserInterfaceLogic
-::OnMultisessionZoomChange()
-{
-  // Make sure we broadcast the current zoom level
-  OnZoomUpdate();
-}
-
-void
-UserInterfaceLogic
-::SetZoomLevelAllWindows(float zoom)
-{
-  m_InZoomLevel->value(zoom);
-  this->OnZoomLevelChange();
-}
-
-void
-UserInterfaceLogic
-::OnZoomLevelChange()
-{
-  float zoom = m_InZoomLevel->value();
-  m_SliceCoordinator->SetZoomLevelAllWindows(zoom);
-  OnZoomUpdate();
-}
-
-void 
-UserInterfaceLogic
-::OnZoomUpdate(bool flagBroadcast)
-{
-  // This method should be called whenever the zoom changes
-  if(m_SliceCoordinator->GetLinkedZoom())
-    {
-    // Get the zoom from the first window and display it on the screen
-    m_InZoomLevel->value(m_SliceCoordinator->GetCommonZoomLevel());
-
-    // Broadcast the zoom level to other sessions
-    if(flagBroadcast 
-      && m_ChkMultisessionZoom->value()
-      && m_Activation->GetFlag(UIF_IRIS_ACTIVE))
-      {
-      m_SystemInterface->IPCBroadcastZoomLevel(
-        m_SliceCoordinator->GetCommonZoomLevel());
-      }
-    }
-  else
-    {
-    // Otherwise, clear the display
-    m_InZoomLevel->value(0);
-    }
-}
-
-
-// Get the window under mouse focus or -1 if none
-int 
-UserInterfaceLogic
-::GetWindowUnderFocus(void)
-{
-  for(int i = 0; i < 3; i++)
-    if(m_SliceCoordinator->GetWindow(i)->GetCanvas()->GetFocus())
-      return i;
-  return -1;
-}
-
-std::string
-UserInterfaceLogic
-::GenerateScreenShotFilename()
-{
-  // Get the last screen shot filename used
-  std::string last = m_LastSnapshotFileName;
-  if(last.length() == 0)
-    return "snapshot0001.png";
-
-  // Count how many digits there are at the end of the filename
-  std::string noext = 
-    itksys::SystemTools::GetFilenameWithoutExtension(m_LastSnapshotFileName);
-  unsigned int digits = 0;
-  for(int i = noext.length() - 1; i >= 0; i--)
-    if(isdigit(noext[i])) digits++; else break;
-
-  // If there are no digits, return the filename
-  if(digits == 0) return m_LastSnapshotFileName;
-
-  // Get the number at the end of the string
-  std::string snum = noext.substr(noext.length() - digits);
-  std::istringstream iss(snum);
-  unsigned long num = 0;
-  iss >> num;
-
-  // Increment the number by one and convert to another string, padding with zeros
-  std::ostringstream oss;
-  oss << itksys::SystemTools::GetFilenamePath(last);
-  oss << "/";
-  oss << noext.substr(0, noext.length() - digits);
-  oss << std::setw(digits) << std::setfill('0') << (num + 1);
-  oss << itksys::SystemTools::GetFilenameExtension(m_LastSnapshotFileName);
-  return oss.str();
-}
-
-
-
-void
-UserInterfaceLogic
-::OnUndoAction()
-{
-  m_Driver->Undo();
-
-  // Update the flags in the UI
-  m_Activation->UpdateFlag(UIF_UNDO_POSSIBLE, m_Driver->IsUndoPossible());
-  m_Activation->UpdateFlag(UIF_REDO_POSSIBLE, m_Driver->IsRedoPossible());
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_DIRTY, true);
-
-  // Update the saved changes flag (now true, unless equal to saved image)
-  m_Activation->UpdateFlag(UIF_UNSAVED_CHANGES, 
-    m_UndoStateAtLastIO != m_Driver->GetUndoManager().GetState());
-
-  RedrawWindows();
-}
-
-void
-UserInterfaceLogic
-::OnRedoAction()
-{
-  m_Driver->Redo();
-
-  // Update the flags in the UI
-  m_Activation->UpdateFlag(UIF_UNDO_POSSIBLE, m_Driver->IsUndoPossible());
-  m_Activation->UpdateFlag(UIF_REDO_POSSIBLE, m_Driver->IsRedoPossible());
-  m_Activation->UpdateFlag(UIF_IRIS_MESH_DIRTY, true);
-
-  // Update the saved changes flag (now true, unless equal to saved image)
-  m_Activation->UpdateFlag(UIF_UNSAVED_CHANGES, 
-    m_UndoStateAtLastIO != m_Driver->GetUndoManager().GetState());
-
-  RedrawWindows();
-}
-
-void
-UserInterfaceLogic
-::StoreUndoPoint(const char *text)
-{
-  // the actual undo point is handled in IRISApplication
-  m_Driver->StoreUndoPoint(text);
-
-  // Update the flags in the UI
-  m_Activation->UpdateFlag(UIF_UNDO_POSSIBLE, m_Driver->IsUndoPossible());
-  m_Activation->UpdateFlag(UIF_REDO_POSSIBLE, m_Driver->IsRedoPossible());
-
-  // Update the saved changes flag (now true, unless equal to saved image)
-  m_Activation->UpdateFlag(UIF_UNSAVED_CHANGES, 
-    m_UndoStateAtLastIO != m_Driver->GetUndoManager().GetState());
-}
-
-void
-UserInterfaceLogic
-::ClearUndoPoints()
-{
-  m_Driver->ClearUndoPoints();
-
-  // Update the flags in the UI
-  m_Activation->UpdateFlag(UIF_UNDO_POSSIBLE, m_Driver->IsUndoPossible());
-  m_Activation->UpdateFlag(UIF_REDO_POSSIBLE, m_Driver->IsRedoPossible());
-
-  // Update the saved changes flag (now true, unless equal to saved image)
-  m_Activation->UpdateFlag(UIF_UNSAVED_CHANGES, 
-    m_UndoStateAtLastIO != m_Driver->GetUndoManager().GetState());
-}
-
-void 
-UserInterfaceLogic
-::OnUnsavedChangesStateChange(UIStateFlags flag, bool value)
-{
-  UpdateMainLabel();
-}
-
-void
-UserInterfaceLogic
-::OnMeshAvailabilityStateChange(UIStateFlags flag, bool value)
-{
-  // UIF_MESH_SAVEABLE is available either in IRIS or SNAP modes
-  m_Activation->UpdateFlag(UIF_MESH_SAVEABLE,
-    m_Activation->GetFlag(UIF_IRIS_WITH_BASEIMG_LOADED) | 
-    m_Activation->GetFlag(UIF_SNAP_SNAKE_INITIALIZED));
-}
-
-void
-UserInterfaceLogic
-::OnHiddenFeaturesToggleAction()
-{
-  if(m_AppearanceSettings->GetFlagEnableHiddenFeaturesByDefault())
-    {
-    m_BtnAnnotationMode->show();
-    m_MenuAnnotationMode->show();
-    }
-  else
-    {
-    m_BtnAnnotationMode->hide();
-    m_MenuAnnotationMode->hide();
-    }
-}
-
-const char *tip_link_cb(Fl_Widget *w, const char *uri)
-{
-  fl_open_uri(uri);
-  return NULL;
-}
-
-const char *snap_tips[] = {
-  "There are many resources on our website, <p></p>"
-  "<BLOCKQUOTE><a href='http://itksnap.org'>itksnap.org</a></BLOCKQUOTE>,"
-  "<p></p>"
-  "including tutorials, mailing lists, bug reports, and much more!",
-
-  "ITK-SNAP reports the cursor location in NIfTI coordinates."
-  "<p>x runs left to right; y runs posterior to anterior; and x runs inferior to superior</p>",
-
-  "You can run several ITK-SNAP sessions at once. "
-  "<p>The cursor will be linked between these sessions, always pointing to the same patient coordinate.</p>",
-
-  "Did you know that ITK-SNAP can display color (RGB) images?"
-  "<p>Supported formats are NIfTI and MetaImage.</p>",
-
-  "<b>Convert3D</b> is a companion tool to ITK-SNAP. It lets you perform complex image processing operations with "
-  "a simple command-line interface.<p> Get it from</p> <p><a href='http://itksnap.org/c3d'>itksnap.org/c3d</a></p>",
-
-  "Did you know that the <b>F3</b> key can be used to hide user interface panels in ITK-SNAP?",
-
-  "Did you know that the <b>F4</b> key toggles full-screen mode?",
-
-  "Please remember to cite our 2006 Neuroimage paper when you publish results produced with ITK-SNAP!",
-
-  "ITK-SNAP supports multiple image layers. Each layer has its own contrast settings, opacity, and color map."
-  "Load layers using the 'Overlay' menu. Edit them using the Layer Inspector, under 'Tools'.",
-
-  "There are many keyboard shortcuts to make your work faster. Look them up under 'Help'",
-
-  "Since version 2.0, you can zoom (right mouse button) and pan (middle button) in crosshairs mode. "
-  "There is also an automatic paning feature when you zoom into an image.",
-
-  "The paintbrush mode includes an adaptive paintbrush that can be used to automate manual labeling."
-  "<p>It labels voxels of similar intensity</p>",
-
-  "All changes to the segmentation can be undone and redone. But you should still save your work often!",
-
-  "The little '+' icon next to each slice window is used to expand that window and hide other windows.",
-
-  "You can change the appearance of the crosshairs, zoom thumbnail, ruler, and all other overlays in slice windows."
-  "<p>Select 'Display Options' under 'Tools'",
-
-  NULL};
-
-static int ntips = 15, current_tip = -1;
-
-void
-UserInterfaceLogic
-::DisplayTips()
-{
-  if(current_tip < 0)
-    {
-    // Today's date
-    time_t ctm;    
-    time(&ctm);
-    struct tm *tinfo = localtime(&ctm);
-    current_tip = tinfo->tm_yday % ntips;
-    }
-
-  m_OutTips->value(snap_tips[current_tip]);
-  m_OutTips->link(&tip_link_cb);
-  current_tip++;
-  if(snap_tips[current_tip] == NULL)
-    current_tip = 0;
-}
-
-/*
- *$Log: UserInterfaceLogic.cxx,v $
- *Revision 1.124  2011/05/04 15:25:42  pyushkevich
- *Fixes to build with fltk 1.3.0rc3
- *
- *Revision 1.123  2011/05/03 20:11:12  pyushkevich
- *version number changed to 2.2
- *
- *Revision 1.122  2011/04/18 17:57:08  pyushkevich
- *Fixed bug 3172058, a typo in 'sagittal'
- *
- *Revision 1.121  2011/04/18 17:55:20  pyushkevich
- *Fixed bug 3243462. We can now save the mesh in SNAP (level set) mode
- *
- *Revision 1.120  2011/04/18 17:35:30  pyushkevich
- *Fixed bug 3288963, problems with bubble initialization
- *
- *Revision 1.119  2011/04/18 15:06:07  pyushkevich
- *Added keystroke for changing colormaps
- *
- *Revision 1.118  2010/10/19 21:31:05  pyushkevich
- *Fixed the toolbar for collapse mode; Added menu items for the tools
- *
- *Revision 1.117  2010/10/19 19:16:30  pyushkevich
- *Fixed slowdowns due to progress bars in preprocessing, mesh generation
- *
- *Revision 1.116  2010/10/13 16:59:25  pyushkevich
- *Fixing warnings
- *
- *Revision 1.115  2010/10/13 16:52:04  pyushkevich
- *Improved the precision warning system
- *
- *Revision 1.114  2010/10/12 17:57:11  pyushkevich
- *Collapsed windows auto-shrink; changed zoom to fit behavior
- *
- *Revision 1.113  2010/10/12 16:02:05  pyushkevich
- *Improved handling of collapsed windows
- *
- *Revision 1.112  2010/07/01 21:40:24  pyushkevich
- *Increased max number of labels to 65535
- *
- *Revision 1.111  2010/06/28 18:45:08  pyushkevich
- *Patch from Michael Hanke to allow ITK 3.18 builds
- *
- *Revision 1.110  2010/05/31 19:52:37  pyushkevich
- *Added volumes and statistics window
- *
- *Revision 1.109  2010/05/27 11:16:22  pyushkevich
- *Further improved polygon drawing interface
- *
- *Revision 1.108  2010/05/27 07:29:36  pyushkevich
- *New popup menu for polygon drawing, other improvements to polygon tool
- *
- *Revision 1.107  2010/04/16 05:14:38  pyushkevich
- *FIX: touched up previous checkin
- *
- *Revision 1.106  2010/04/16 04:02:35  pyushkevich
- *ENH: implemented drag and drop, OSX events, new command-line interface
- *
- *Revision 1.105  2010/04/14 10:06:23  pyushkevich
- *Added option to launch external SNAP
- *
- *Revision 1.104  2010/03/23 21:23:13  pyushkevich
- *Added display halving capability,
- *command line switches --zoom, --help, --compact
- *
- *Revision 1.103  2009/11/16 20:29:28  garyhuizhang
- *BUGFIX: a fix for messed up display on mac when switching between different panel zoom mode
- *ENH: added color map menu item
- *
- *Revision 1.102  2009/11/13 13:45:26  pyushkevich
- *undo bad checkin
- *
- *Revision 1.100  2009/11/13 00:59:47  pyushkevich
- *ENH: improved shortcuts
- *
- *Revision 1.99  2009/10/30 16:48:24  garyhuizhang
- *ENH: allow interacting with the main window when the reorient image dialog is open
- *
- *Revision 1.98  2009/10/30 13:49:48  pyushkevich
- *FIX: improved behavior of synchronized pan. it now broadcasts viewport center rel. to cursor posn.
- *FIX: improved IPC. only 'new' messages are now acted on.
- *
- *Revision 1.97  2009/10/28 08:05:36  pyushkevich
- *FIX: Multisession pan causing continuous screen updates
- *
- *Revision 1.96  2009/10/26 16:00:56  pyushkevich
- *ENH: improved/fixed cursor movement in all modes. added menu items for F3/F4
- *
- *Revision 1.95  2009/10/26 08:37:31  pyushkevich
- *FIX(2872319): Ctrl-Z no longer steals focus from slice window
- *
- *Revision 1.94  2009/10/26 08:17:58  pyushkevich
- *FIX(2821319): Made intensity curve and colormap work in snake mode
- *
- *Revision 1.93  2009/10/26 07:34:10  pyushkevich
- *ENH: substantially reduced memory footprint when loading float NIFTI images
- *
- *Revision 1.92  2009/10/25 13:17:05  pyushkevich
- *FIX: bugs in SF.net, crash on mesh update in large images, bad vols/stats output
- *
- *Revision 1.91  2009/10/17 20:39:50  pyushkevich
- *ENH: added tip of the day
- *
- *Revision 1.90  2009/09/21 21:55:19  pyushkevich
- *FIX:various snow leopard warnings'
- *
- *Revision 1.89  2009/09/14 19:04:52  garyhuizhang
- *ENH: layer inspector support for curor position input
- *
- *Revision 1.88  2009/09/14 04:41:38  garyhuizhang
- *ENH: layer inspector with partial image info support
- *
- *Revision 1.87  2009/09/13 22:11:51  garyhuizhang
- *ENH: add layer inspector support for multiple layers
- *
- *Revision 1.86  2009/09/12 23:27:01  garyhuizhang
- *ENH: layer inspector now with color map support
- *
- *Revision 1.85  2009/09/10 22:42:32  garyhuizhang
- *ENH: handle overlays in layer inspector
- *
- *Revision 1.84  2009/09/10 21:25:24  garyhuizhang
- *ENH: Layer inspector now supports contrast adjustment of main image
- *
- *Revision 1.83  2009/08/29 23:17:02  garyhuizhang
- *BUGFIX: fix a memory leak
- *
- *Revision 1.82  2009/08/28 20:35:15  garyhuizhang
- *ENH: remove OverlayUI (replaced by LayerInspectorUI)
- *
- *Revision 1.81  2009/08/28 16:57:05  pyushkevich
- *FIX: Fixed scrollbar crash
- *
- *Revision 1.80  2009/08/28 16:33:03  garyhuizhang
- *ENH: rename LayerEditor as LayerInspector
- *
- *Revision 1.79  2009/08/28 16:05:43  pyushkevich
- *Enabled toggling of UI components with 'F3' key and fullscreen mode with 'F4' key
- *
- *Revision 1.78  2009/08/26 21:49:55  pyushkevich
- *Improvements to the color map widget
- *
- *Revision 1.77  2009/08/26 01:10:20  garyhuizhang
- *ENH: merge grey and RGB overlays into one wrapper list and modify the associated GUI codes
- *
- *Revision 1.75  2009/08/24 19:24:33  garyhuizhang
- *BUGFIX: menu item activation rules changed
- *1) m_MenuImageInfo and m_MenuSave imply UIF_BASEIMG_LOADED
- *2) UIF_SNAP_PREPROCESSING_DONE no longer implies UIF_SNAP_ACTIVE
- *
- *Revision 1.74  2009/07/22 21:06:24  pyushkevich
- *Changed the IO system and wizards, removed templating
- *
- *Revision 1.73  2009/07/15 21:35:44  pyushkevich
- *Fixed bug with export image slice saving wrong anatomical direction
- *
- *Revision 1.72  2009/07/13 17:26:24  pyushkevich
- *Fixed crash on Win32
- *
- *Revision 1.71  2009/07/01 22:21:50  garyhuizhang
- *BUGFIX: main window title label not being updated!
- *
- *Revision 1.70  2009/07/01 20:15:27  garyhuizhang
- *BUGFIX: native file chooser bugs
- *
- *Revision 1.69  2009/06/24 00:13:55  garyhuizhang
- *ENH: improved auto update management
- *
- *Revision 1.68  2009/06/18 18:11:24  garyhuizhang
- *ENH: multisession pan ui support
- *BUGFIX: single session pan working again
- *
- *Revision 1.67  2009/06/16 05:57:00  garyhuizhang
- *ENH: initial UI for layer manager, which replacing the old RGB overlay UI
- *
- *Revision 1.66  2009/06/16 04:55:45  garyhuizhang
- *ENH: per overlay opacity adjustment
- *
- *Revision 1.65  2009/06/15 23:41:09  garyhuizhang
- *BUGFIX: make sure the 3D view does not get reset when loading/unloading overlay and segmentation images.
- *
- *Revision 1.64  2009/06/15 01:54:10  garyhuizhang
- *BUGFIX: linked zoom misbehaving with overlay
- *
- *Revision 1.63  2009/06/14 20:43:17  garyhuizhang
- *ENH: multiple RGB overlay support
- *
- *Revision 1.62  2009/06/14 06:13:20  garyhuizhang
- *ENH: menu item association for grey overlay unload
- *
- *Revision 1.61  2009/06/13 05:02:00  garyhuizhang
- *ENH: improved implementation of recent file lists that combines both grey and RGB main images
- *
- *Revision 1.60  2009/06/13 03:29:40  garyhuizhang
- *ENH: checking for available software update
- *
- *Revision 1.59  2009/06/12 05:11:08  garyhuizhang
- *ENH: reorganized user interface
- *
- *Revision 1.58  2009/06/10 02:52:46  garyhuizhang
- *ENH: multiple grey overlay images support
- *
- *Revision 1.57  2009/06/09 05:46:38  garyhuizhang
- *ENH: main image support & grey overlay support
- *
- *Revision 1.56  2009/05/25 17:09:44  garyhuizhang
- *ENH: switch from Fl_File_Chooser to Fl_Native_File_Chooser which requires the fltk to be patched with Fl_Native_File_Chooser add-on.
- *
- *Revision 1.55  2009/05/25 16:35:49  garyhuizhang
- *bug fix: history not activated when loading segmentation files
- *
- *Revision 1.54  2009/05/04 20:15:57  garyhuizhang
- *multisession panning support added
- *
- *Revision 1.53  2009/04/18 05:28:09  garyhuizhang
- *added key stroke to reset the view center to image center
- *
- *Revision 1.52  2009/02/18 01:19:13  garyhuizhang
- *ENH: added keyboard shortcut 'c' for toggling the visibility of crosshairs
- *
- *Revision 1.51  2009/02/18 01:14:52  garyhuizhang
- *ENH: support adjusting the default behavior of linked zoom and multi-session zoom
- *
- *Revision 1.50  2009/02/10 00:10:12  garyhuizhang
- *ENH: Support two drawing options in the Annotation mode: 1) each line shown only on the slice level it is drawn; 2) each line is shown on all slice levels
- *
- *Revision 1.49  2009/02/09 17:07:47  garyhuizhang
- *FIX: code refactoring -- command line and GUI loading of segmentation now shares the same code.  this enables the validity checking of segmentation image on command line originally implemented for GUI.
- *
- *Revision 1.48  2009/02/06 18:56:04  garyhuizhang
- *ENH: add image type specific information to image load/save wizard
- *
- *Revision 1.47  2009/02/05 23:03:40  garyhuizhang
- *ENH: support for saving the hidden feature flag
- *
- *Revision 1.46  2009/02/05 16:21:14  pyushkevich
- *ENH: added hidden features button
- *
- *Revision 1.45  2009/02/05 14:58:29  pyushkevich
- *FIX: save slice layout appearance settings to registry; ENH: added linear interpolation option for grey images
- *
- *Revision 1.44  2009/02/03 19:51:50  pyushkevich
- *fixes
- *
- *Revision 1.43  2009/02/03 19:12:35  pyushkevich
- *ENH: added support for checking version via internet
- *
- *Revision 1.42  2009/01/30 23:44:15  garyhuizhang
- *FIX: clean up the remaining minor compiler warnings
- *
- *Revision 1.41  2009/01/30 23:08:21  garyhuizhang
- *ENH: better implementation of the keyboard shortcuts that do not require the SHIFT key
- *
- *Revision 1.40  2009/01/30 22:41:27  garyhuizhang
- *ENH: new keyboard shortcuts for adjusting paintbrush size, changing active/drawover labels
- *
- *Revision 1.39  2009/01/23 21:48:59  pyushkevich
- *ENH: Added hidden annotation mode (very bad code)
- *
- *Revision 1.38  2009/01/23 20:09:38  pyushkevich
- *FIX: 3D rendering now takes place in Nifti(RAS) world coordinates, rather than the VTK (x spacing + origin) coordinates. As part of this, itk::OrientedImage is now used for 3D images in SNAP. Still have to fix cut plane code in Window3D
- *
- *Revision 1.37  2009/01/23 05:04:33  garyhuizhang
- *Bug fix: floating point values are now correctly displayed in image
- *contrast dialog and image info dialog
- *
- *Revision 1.36  2009/01/22 23:14:10  garyhuizhang
- *1) Add an option under Options -> Display Options -> General for toggling on/off the warning when loading floating point images.
- *2) The warning message is modified to include the instruction for turning it off.
- *
- *Revision 1.35  2009/01/17 10:40:28  pyushkevich
- *Added synchronization to 3D window viewpoint
- *
- *Revision 1.34  2009/01/16 21:31:41  pyushkevich
- *Fixed issues with loading and creating new segmentation images; namely undo/redo bugs and update mesh button not being available.
- *
- *Revision 1.33  2008/12/02 21:43:24  pyushkevich
- *Reorganization of the watershed code
- *
- *Revision 1.32  2008/12/02 05:14:19  pyushkevich
- *New feature: watershed-based adaptive paint brush. Based on the similar tool in ITK-Grey (which was derived from ITK-SNAP).
- *
- *Revision 1.31  2008/11/20 04:24:00  pyushkevich
- *Bugfixes
- *
- *Revision 1.30  2008/11/20 02:41:03  pyushkevich
- *Now when non-native format is loaded, the intensity is mapped to original values
- *
- *Revision 1.29  2008/11/17 19:47:41  pyushkevich
- *Get linux to compile
- *
- *Revision 1.28  2008/11/17 19:38:23  pyushkevich
- *Added tools dialog to label editor window
- *
- *Revision 1.26  2008/11/01 11:32:00  pyushkevich
- *Compatibility with ITK 3.8 support for reading oriented images
- *Command line loading of RGB images
- *Improved load-image commands in UserInterfaceLogic
- *
- *Revision 1.25  2008/04/16 13:48:01  pyushkevich
- *Major bug fix: cursor was not working in automatic segmentation mode
- *
- *Revision 1.24  2008/04/01 14:25:27  pyushkevich
- *Minor bug fix: alt-i to do automatic intensity adjustment
- *
- *Revision 1.23  2008/03/25 19:31:31  pyushkevich
- *Bug fixes for release 1.6.0
- *
- *Revision 1.22  2008/02/27 04:34:46  garyhuizhang
- *1) rename OnMenuSaveScreenshots to OnMenuSaveScreenshotSeries
- *2) support menu access to both save single screenshot and screenshot series
- *
- *Revision 1.21  2008/02/26 21:28:29  garyhuizhang
- *improve the behavior of savescreenshot series
- *1) restore the cursor location before the call
- *2) handle the situation when user did not provide a directory for screenshots
- *
- *Revision 1.20  2008/02/23 23:41:12  garyhuizhang
- *add support for saving screenshots of the whole image volume
- *
- *Revision 1.19  2008/02/16 22:38:34  pyushkevich
- *Bug fix with bubbles
- *
- *Revision 1.18  2008/02/15 19:55:31  pyushkevich
- *fixed 100% cpu usage bug (from idle function)
- *
- *Revision 1.17  2008/02/15 18:34:16  pyushkevich
- *scrolling bug fix; packaging includes date in filename
- *
- *Revision 1.16  2008/02/11 17:49:20  pyushkevich
- *Touchups
- *
- *Revision 1.15  2008/02/11 12:59:40  pyushkevich
- *bug fix with shared cursor on Linux
- *
- *Revision 1.14  2008/02/10 23:55:22  pyushkevich
- *Added "Auto" button to the intensity curve window; Added prompt before quitting on unsaved data; Fixed issues with undo on segmentation image load; Added synchronization between SNAP sessions.
- *
- *Revision 1.13  2008/01/08 20:34:52  pyushkevich
- *Implement toggle for opacity slider
- *
- *Revision 1.12  2007/12/30 04:05:18  pyushkevich
- *GPL License
- *
- *Revision 1.11  2007/12/25 15:46:23  pyushkevich
- *Added undo/redo functionality to itk-snap
- *
- *Revision 1.10  2007/09/18 18:42:40  pyushkevich
- *Added tablet drawing to polygon mode
- *
- *Revision 1.9  2007/09/15 15:59:20  pyushkevich
- *Improved the paintbrush mode, allowed more variety of brush sizes
- *
- *Revision 1.8  2007/09/04 16:56:13  pyushkevich
- *tablet support 1
- *
- *Revision 1.7  2007/06/07 00:49:16  pyushkevich
- *Debugged RGB changes
- *
- *Revision 1.6  2007/06/06 22:27:22  garyhuizhang
- *Added support for RGB images in SNAP
- *
- *Revision 1.5  2007/05/10 20:19:50  pyushkevich
- *Added VTK mesh export code and GUI
- *
- *Revision 1.4  2006/12/06 14:36:18  pyushkevich
- *Fixes for VC6
- *
- *Revision 1.3  2006/12/06 13:27:46  pyushkevich
- *Followup checking for 1.4.1
- *
- *Revision 1.2  2006/12/06 01:26:07  pyushkevich
- *Preparing for 1.4.1. Seems to be stable in Windows but some bugs might be still there
- *
- *Revision 1.1  2006/12/02 04:22:23  pyushkevich
- *Initial sf checkin
- *
- *Revision 1.1.1.1  2006/09/26 23:56:18  pauly2
- *Import
- *
- *Revision 1.59  2006/02/02 01:23:10  pauly
- *BUG: Fixed SNAP bugs in the last checkin
- *
- *Revision 1.58  2006/02/01 21:41:42  pauly
- *ENH: SNAP: bubble radius changed to floating point
- *
- *Revision 1.57  2006/02/01 20:21:26  pauly
- *ENH: An improvement to the main SNAP UI structure: one set of GL windows is used to support SNAP and IRIS modes
- *
- *Revision 1.56  2006/01/06 18:45:35  pauly
- *BUG: Progress bar in SNAP not disappearing at times
- *
- *Revision 1.55  2006/01/05 23:19:45  pauly
- *BUG: SNAP label file was not being written correctly
- *
- *Revision 1.54  2006/01/05 18:25:05  pauly
- *BUG: Fixed cursor bug in lInux
- *
- *Revision 1.53  2006/01/05 00:02:41  pauly
- *ENH: Now SNAP keeps cursor position whether you enter or exit auto mode
- *
- *Revision 1.52  2006/01/04 23:25:42  pauly
- *ENH: SNAP will keep crosshairs position when entering automatic segmentation
- *
- *Revision 1.51  2005/12/21 17:07:22  pauly
- *STYLE: New SNAP logo, about window
- *
- *Revision 1.50  2005/12/19 03:43:12  pauly
- *ENH: SNAP enhancements and bug fixes for 1.4 release
- *
- *Revision 1.49  2005/12/16 23:46:51  pauly
- *BUG: Silly mistake in PNG screenshot saver
- *
- *Revision 1.48  2005/12/12 13:11:39  pauly
- *BUG: Filename problem with talking snapshots in SNAP fixed
- *
- *Revision 1.47  2005/12/12 00:27:44  pauly
- *ENH: Preparing SNAP for 1.4 release. Snapshot functionality
- *
- *Revision 1.46  2005/12/08 21:15:58  pauly
- *COMP: SNAP not linking because whoever did previous fix did not check in SNAPCommon.cxx
- *
- *Revision 1.45  2005/12/08 18:20:46  hjohnson
- *COMP:  Removed compiler warnings from SGI/linux/MacOSX compilers.
- *
- *Revision 1.44  2005/11/23 14:32:15  ibanez
- *BUG: 2404. Patch provided by Paul Yushkevish.
- *
- *Revision 1.43  2005/11/10 23:02:14  pauly
- *ENH: Added support for VoxBo CUB files to ITK-SNAP, as well as some cosmetic touches
- *
- *Revision 1.42  2005/11/03 20:59:15  pauly
- *COMP: Fixed compiler errors on newer versions of VTK
- *
- *Revision 1.41  2005/11/03 18:45:29  pauly
- *ENH: Enabled SNAP to read DICOM Series
- *
- *Revision 1.40  2005/10/29 14:00:15  pauly
- *ENH: SNAP enhacements like color maps and progress bar for 3D rendering
- *
- *Revision 1.39  2005/08/10 19:57:15  pauly
- *BUG: Labels not always appearing when loading an image in SNAP
- *
- *Revision 1.38  2005/08/10 03:24:20  pauly
- *BUG: Corrected problems with 3D window, label IO from association files
- *
- *Revision 1.37  2005/04/23 13:58:19  pauly
- *COMP: Fixing compile errors in the last SNAP checkin
- *
- *Revision 1.36  2005/04/23 12:56:59  lorensen
- *BUG: bad include.
- *
- *Revision 1.35  2005/04/21 18:52:38  pauly
- *ENH: Furhter improvements to SNAP label editor
- *
- *Revision 1.34  2005/04/21 14:46:30  pauly
- *ENH: Improved management and editing of color labels in SNAP
- *
- *Revision 1.33  2005/04/15 19:04:19  pauly
- *ENH: Improved the Intensity Contrast features in SNAP
- *
- *Revision 1.32  2005/04/14 16:35:10  pauly
- *ENH: Added Image Info window to SNAP
- *
- *Revision 1.31  2005/03/08 03:12:51  pauly
- *BUG: Minor bugfixes in SNAP, mostly to the user interface
- *
- *Revision 1.30  2004/09/21 15:50:40  jjomier
- *FIX: vector_multiply_mixed requires template parameters otherwise MSVC cannot deduce them
- *
- *Revision 1.29  2004/09/14 14:11:10  pauly
- *ENH: Added an activation manager to main UI class, improved snake code, various UI fixes and additions
- *
- *Revision 1.28  2004/09/08 12:09:45  pauly
- *ENH: Adapting SNAP to work with stop-n-go function in finite diff. framewk
- *
- *Revision 1.27  2004/08/26 19:43:27  pauly
- *ENH: Moved the Borland code into Common folder
- *
- *Revision 1.26  2004/08/26 18:29:19  pauly
- *ENH: New user interface for configuring the UI options
- *
- *Revision 1.25  2004/08/03 23:26:32  ibanez
- *ENH: Modification for building in multple platforms. By Julien Jomier.
- *
- *Revision 1.24  2004/07/29 14:00:36  pauly
- *ENH: A new interface for changing the appearance of SNAP
- *
- *Revision 1.23  2004/07/24 19:00:06  pauly
- *ENH: Thumbnail UI for slice zooming
- *
- *Revision 1.22  2004/07/22 19:22:49  pauly
- *ENH: Large image support for SNAP. This includes being able to use more screen real estate to display a slice, a fix to the bug with manual segmentation of images larger than the window size, and a thumbnail used when zooming into the image.
- *
- *Revision 1.21  2004/07/21 18:17:45  pauly
- *ENH: Enhancements to the way that the slices are displayed
- *
- *Revision 1.20  2004/03/19 00:54:48  pauly
- *ENH: Added the ability to externally load the advection image
- *
- *Revision 1.19  2004/01/24 18:21:00  king
- *ERR: Merged warning fixes from ITK 1.6 branch.
- *
- *Revision 1.18.2.1  2004/01/24 18:16:50  king
- *ERR: Fixed warnings.
- *
- *Revision 1.18  2003/12/12 19:34:01  pauly
- *FIX: Trying to get everything to compile again after API changes
- *
- *Revision 1.17  2003/12/10 23:20:15  hjohnson
- *UPD: Code changes to allow compilation under linux.
- *
- *Revision 1.16  2003/12/10 02:21:14  lorensen
- *ENH: Spacing is now a FixedArray.
- *
- *Revision 1.15  2003/12/07 21:19:32  pauly
- *ENH: SNAP can now resample the segmentation ROI, facilitating
- *multires segmentation and segmentation of anisotropic images
- *
- *Revision 1.14  2003/12/07 19:48:41  pauly
- *ENH: Resampling, multiresolution
- *
- *Revision 1.13  2003/11/29 17:06:48  pauly
- *ENH: Minor Help issues
- *
- *Revision 1.12  2003/11/29 14:02:42  pauly
- *FIX: History list and file associations faili with spaces in filenames
- *
- *Revision 1.11  2003/11/10 00:27:26  pauly
- *FIX: Bug with linear interpolation in PDE solver
- *ENH: Help viewer and tutorial
- *
- *Revision 1.10  2003/10/09 22:45:14  pauly
- *EMH: Improvements in 3D functionality and snake parameter preview
- *
- *Revision 1.9  2003/10/06 12:30:00  pauly
- *ENH: Added history lists, remembering of settings, new snake parameter preview
- *
- *Revision 1.8  2003/10/02 20:57:46  pauly
- *FIX: Made sure that the previous check-in compiles on Linux
- *
- *Revision 1.7  2003/10/02 18:43:47  pauly
- *FIX: Fixed crashes with using vtkContourFilter
- *
- *Revision 1.6  2003/10/02 14:55:52  pauly
- *ENH: Development during the September code freeze
- *
- *Revision 1.5  2003/09/16 16:10:17  pauly
- *FIX: No more Internal compiler errors on VC
- *FIX: Intensity curve no longer crashes
- *ENH: Histogram display on intensity curve window
- *
- *Revision 1.4  2003/09/15 19:06:58  pauly
- *FIX: Trying to get last changes to compile
- *
- *Revision 1.3  2003/09/15 17:32:19  pauly
- *ENH: Removed ImageWrapperImplementation classes
- *
- *Revision 1.2  2003/09/13 15:18:01  pauly
- *FIX: Got SNAP to work properly with different image orientations
- *
- *Revision 1.1  2003/09/11 13:51:01  pauly
- *FIX: Enabled loading of images with different orientations
- *ENH: Implemented image save and load operations
- *
- *Revision 1.5  2003/08/28 22:58:30  pauly
- *FIX: Erratic scrollbar behavior
- *
- *Revision 1.4  2003/08/28 14:37:09  pauly
- *FIX: Clean 'unused parameter' and 'static keyword' warnings in gcc.
- *FIX: Label editor repaired
- *
- *Revision 1.3  2003/08/27 14:03:22  pauly
- *FIX: Made sure that -Wall option in gcc generates 0 warnings.
- *FIX: Removed 'comment within comment' problem in the cvs log.
- *
- *Revision 1.2  2003/08/27 04:57:46  pauly
- *FIX: A large number of bugs has been fixed for 1.4 release
- *
- *Revision 1.1  2003/07/12 04:46:50  pauly
- *Initial checkin of the SNAP application into the InsightApplications tree.
- *
- *Revision 1.1  2003/07/11 23:33:57  pauly
- **** empty log message ***
- *
- *Revision 1.20  2003/07/10 14:30:26  pauly
- *Integrated ITK into SNAP level set segmentation
- *
- *Revision 1.19  2003/07/01 16:53:59  pauly
- **** empty log message ***
- *
- *Revision 1.18  2003/06/23 23:59:32  pauly
- *Command line argument parsing
- *
- *Revision 1.17  2003/06/14 22:42:06  pauly
- *Several changes.  Started working on implementing the level set function
- *in ITK.
- *
- *Revision 1.16  2003/06/08 23:27:56  pauly
- *Changed variable names using combination of ctags, egrep, and perl.
- *
- *Revision 1.15  2003/06/08 16:11:42  pauly
- *User interface changes
- *Automatic mesh updating in SNAP mode
- *
- *Revision 1.14  2003/05/22 17:36:19  pauly
- *Edge preprocessing settings
- *
- *Revision 1.13  2003/05/17 21:39:30  pauly
- *Auto-update for in/out preprocessing
- *
- *Revision 1.12  2003/05/14 18:33:58  pauly
- *SNAP Component is working. Double thresholds have been enabled.  Many other changes.
- *
- *Revision 1.11  2003/05/12 02:51:08  pauly
- *Got code to compile on UNIX
- *
- *Revision 1.10  2003/05/08 21:59:05  pauly
- *SNAP is almost working
- *
- *Revision 1.9  2003/05/07 19:14:46  pauly
- *More progress on getting old segmentation working in the new SNAP.  Almost there, region of interest and bubbles are working.
- *
- *Revision 1.8  2003/05/05 12:30:18  pauly
- **** empty log message ***
- *
- *Revision 1.7  2003/04/29 14:01:42  pauly
- *Charlotte Trip
- *
- *Revision 1.6  2003/04/25 02:58:29  pauly
- *New window2d model with InteractionModes
- *
- *Revision 1.5  2003/04/23 20:36:23  pauly
- **** empty log message ***
- *
- *Revision 1.4  2003/04/23 06:05:18  pauly
- **** empty log message ***
- *
- *Revision 1.3  2003/04/18 17:32:18  pauly
- **** empty log message ***
- *
- *Revision 1.2  2003/04/18 00:25:37  pauly
- **** empty log message ***
- *
- *Revision 1.1  2003/04/16 05:04:17  pauly
- *Incorporated intensity modification into the snap pipeline
- *New IRISApplication
- *Random goodies
- *
- *Revision 1.2  2003/04/01 18:20:56  pauly
- **** empty log message ***
- *
- *Revision 1.1  2003/03/07 19:29:47  pauly
- *Initial checkin
- *
- *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
- *Started the project repository
- *
- *
- *Revision 1.63  2002/05/08 17:32:57  moon
- *I made some changes Guido wanted in the GUI, including removing
- *Turello/Sapiro/Schlegel options (I only hid them, the code is all still there), changing a bunch of the ranges, etc. of the snake parameters.
- *
- *Revision 1.62  2002/04/28 17:29:43  scheuerm
- *Added some documentation
- *
- *Revision 1.61  2002/04/27 18:30:03  moon
- *Finished commenting
- *
- *Revision 1.60  2002/04/27 17:48:33  bobkov
- *Added comments
- *
- *Revision 1.59  2002/04/27 00:08:27  talbert
- *Final commenting run through . . . no functional changes.
- *
- *Revision 1.58  2002/04/26 17:37:12  moon
- *Fixed callback on save preproc dialog cancel button.
- *Fixed bubble browser output.  Position was zero-based, which didn't match the 2D
- *window slice numbers (1 based), so I changed the bubble positions to be cursor
- *position +1.
- *Disallowed starting snake window if current label in not visible.
- *Put in Apply+ button in threshold dialog, which changes seg overlay to be an
- *overlay of the positive voxels in the preproc data (a zero-level visualization).
- *Added more m_OutMessage and m_OutMessage messages.
- *
- *Revision 1.57  2002/04/25 14:13:13  moon
- *Enabled render options in snake window.
- *Changed snake params dialog slider (messed one up last time)
- *Hide r_ params in snake params dialog with in/out snake (they don't apply)
- *Calling segment3D with clear color is not allowed (error dialog)
- *
- *Revision 1.56  2002/04/24 19:50:22  moon
- *Pulled LoadGreyFileCallback out of GUI into UserInterfaceLogic, made modifications due
- *to change in ROI semantics.  Before, the ROI was from ul to lr-1, which is a bad
- *decision.  I changed everything to work with a ROI that is inclusive, meaning
- *that all voxels from ul through lr inclusive are part of the ROI. This involved
- *a lot of small changes to a lot of files.
- *
- *Revision 1.55  2002/04/24 17:10:33  bobkov
- *Added some changes to OnSnakeStartAction(),
- *OnAcceptInitializationAction() and
- *OnRestartInitializationAction()
- *so that ClearScreen() method is called on
- *m_IRISWindow3D and m_SNAPWindow3D to clear the glLists and
- *the previous segmentation is not shown in the 3D window
- *
- *Revision 1.54  2002/04/24 14:54:32  moon
- *Changed the ranges of some of the snake parameters after talking with Guido.
- *Put in a line to update mesh when the update continuously checkbox is checked.
- *
- *Revision 1.53  2002/04/24 14:13:26  moon
- *Implemented separate brightness/contrast settings for grey/preproc data
- *
- *Revision 1.52  2002/04/24 01:05:00  talbert
- *Changed IRIS2000 labels to SnAP.
- *
- *Revision 1.51  2002/04/23 21:56:50  moon
- *small bug fix with the snake params and the global state.  wasn't getting
- *the sapiro/turello/etc. option from the dialog to put into the global state.
- *
- *Revision 1.50  2002/04/23 03:19:40  talbert
- *Made some changes so that the load preproc menu option is unuseable once
- *the snake starts.
- *
- *Revision 1.49  2002/04/22 21:54:39  moon
- *Closed dialogs when accept/restart initialization is pressed, or snake type is
- *switched.
- *
- *Revision 1.48  2002/04/22 21:24:20  talbert
- *Small changes so that error messages for preprocessing loading appeared in
- *the correct status bar.
- *
- *Revision 1.47  2002/04/20 21:56:47  talbert
- *Made it impossible to save preprocessed data when it doesn't make sense
- *(if no preprocessing has been done since the last preproc load or since
- *the snake win opened).  Moved some checks for data type validity out of
- *the callbacks and into the Vox and SnakeVoxData classes where they belong.
- *
- *Revision 1.46  2002/04/19 23:03:59  moon
- *Changed more stuff to get the snake params state synched with the global state.
- *Changed the range of ground in snake params dialog.
- *Removed the use_del_g stuff, since it's really not necessary, I found out.
- *
- *Revision 1.45  2002/04/19 20:34:58  moon
- *Made preproc dialogs check global state and only preproc if parameters have changed.
- *So no if you hit apply, then ok, it doesn't re process on the ok.
- *
- *Revision 1.44  2002/04/18 21:36:51  scheuerm
- *Added documentation for my recent changes.
- *Fixed inverted display of edge preprocessing.
- *
- *Revision 1.43  2002/04/18 21:14:03  moon
- *I had changed the Cancel buttons to be Close on the Filter dialogs, and I changed
- *the names of the callbacks in GUI, but not in UserInterfaceLogic.  So I just hooked them
- *up so the dialogs get closed.
- *
- *Revision 1.42  2002/04/18 21:04:51  moon
- *Changed the IRIS window ROI stuff.  Now the ROI is always valid if an image is
- *loaded, but there is a toggle to show it or not.  This will work better with
- *Konstantin's addition of being able to drag the roi box.
- *
- *I also changed a bunch of areas where I was calling InitializeSlice for the 2D windows,
- *when this is not at all what I should have done.  Now those spots call
- *MakeSegTextureCurrent, or MakeGreyTextureCurrent.  This means that the view is not
- *reset every time the snake steps, the preproc/orig radio buttons are changed, etc.
- *
- *Revision 1.41  2002/04/16 18:54:32  moon
- *minor bug with not stopping snake when play is pushed, and then other
- *buttons are pushed.  Also added a function that can be called when the user
- *clicks the "X" on a window, but it's not what we want, I don't think.  The
- *problem is if the user clicks the "X" on the snake window when a "non modal"
- *dialog is up, all the windows close, but the program doesn't quit.  I think
- *it's a bug in FLTK, but I can't figure out how to solve it.
- *
- *Revision 1.40  2002/04/16 14:44:49  moon
- *Changed bubbles to be in world coordinates instead of image coordinates.
- *
- *Revision 1.39  2002/04/16 13:07:56  moon
- *Added tooltips to some widgets, made minor changes to enabling/disabling of
- *widgets, clearing 3D window when initialization is restarted in snake window,
- *changed kappa in edge preproc dialog to be [0..1] range instead of [0..3]
- *
- *Revision 1.38  2002/04/14 22:02:54  scheuerm
- *Changed loading dialog for preprocessed image data. Code restructuring
- *along the way: Most important is addition of
- *SnakeVoxDataClass::ReadRawPreprocData()
- *
- *Revision 1.37  2002/04/13 17:43:48  moon
- *Added some initslice calls to Win2Ds, so the redraw problem comming back
- *from snake to iris window (where the whole 2D window is yellow) would go away.
- *
- *Revision 1.36  2002/04/13 16:20:08  moon
- *Just put in a bunch of debug printouts.  They'll have to come out eventually.
- *
- *Revision 1.35  2002/04/10 21:20:16  moon
- *just added debug comments.
- *
- *Revision 1.34  2002/04/10 20:19:40  moon
- *got play and stop vcr buttons to work.
- *put in lots of comments.
- *
- *Revision 1.33  2002/04/10 14:45:03  scheuerm
- *Added documentation to the methods I worked on.
- *
- *Revision 1.32  2002/04/09 21:56:42  bobkov
- *
- *modified Step button callback to display snake in 3d window
- *
- *Revision 1.31  2002/04/09 19:32:22  talbert
- *Added comments to the save and load preprocessed functions.  Checked that
- *only float files entered as preprocessed.  Made some small cosmetic
- *changes:  loading a file switches to preproc view and sets snake mode.
- *
- *Revision 1.30  2002/04/09 18:59:33  moon
- *Put in dialog to change snake parameters.  Also implemented Rewind button, which
- *now restarts the snake.  It seems for now that changing snake parameters restarts
- *the snake.  I don't know if this is the way it has to be, or I just did something
- *wrong in snakewrapper.  I'll have to check with Sean.
- *
- *Revision 1.29  2002/04/09 17:59:37  talbert
- *Made changes to LoadPreprocessedCallback which allowed edge detection
- *preproc data to be loaded correctly.
- *
- *Revision 1.28  2002/04/09 03:48:51  talbert
- *Changed some functionality in the LoadPreprocessedCallback() so that it
- *would work with floating point data being loaded.  Most of the stuff
- *is uncommented, hackish, and limited in its testing beyond verification
- *that it displays on the screen with the right values.  These changes
- *will have to be cleaned up.
- *
- *Revision 1.27  2002/04/08 13:32:35  talbert
- *Added a preprocessed save dialog box as well as a save preprocessed menu
- *option in the snake window.  Added the code necessary to implement the
- *GUI side of saving.
- *
- *Revision 1.26  2002/04/07 02:22:49  scheuerm
- *Improved handling of OK and Apply buttons in preprocessing dialogs.
- *
- *Revision 1.23  2002/04/05 03:42:29  scheuerm
- *Thresholding sort of works. Steepness needs to be made configurable.
- *
- *Revision 1.21  2002/04/04 15:30:08  moon
- *Put in code to get StepSize choice box filled with values and working.
- *AcceptSegment button callback puts snake seg data into full_data (IRIS)
- *Fixed a couple more UI cosmetic things.
- *
- *Revision 1.20  2002/04/03 22:12:07  moon
- *Added color chip, image probe, seg probe to snake window, although seg probe
- *maybe shouldn't be there.  added update continuously checkbox to 3Dwindow.
- *changes accept/restart to be on top of each other, and one is shown at a time,
- *which I think is more intuitive.
- *changed snake iteration field to be text output.  added callback for step size
- *choice.
- *
- *Revision 1.19  2002/04/02 23:51:17  scheuerm
- *Gradient magnitude preprocessing is implemented. Stupid, stupid VTK.
- *Adjusted the range and resolution of the sigma slider. Apply button
- *still doesn't do anything but I think we don't need it.
- *
- *Revision 1.18  2002/04/02 15:12:43  moon
- *Put code in the step vcr button.  Now the snake can be "stepped"
- *
- *Revision 1.17  2002/04/01 22:29:54  moon
- *Modified OnAcceptInitializationAction, added functionality to
- *OnRestartInitializationAction
- *
- *Revision 1.16  2002/03/29 20:17:25  scheuerm
- *Implemented remapping of preprocessed data to (-1,1). The mapping can
- *be changed by altering the parameters to RemapPreprocData(...) in
- *LoadPreprocessedDataCallback() (UserInterfaceLogic.cpp).
- *
- *Revision 1.15  2002/03/29 03:33:29  scheuerm
- *Loaded preprocessed data is now converted to float. No remapping yet.
- *Stupid VTK. Added vtkImageDeepCopyFloat which copies the region of
- *interest out of a gray image and converts it to float as it goes.
- *
- *Revision 1.14  2002/03/27 17:59:40  moon
- *changed a couple things.  nothing big. a callback in .fl was bool return type
- *which didn't compile in windows. this is the version I think will work for a
- *demo for Kye
- *
- *Revision 1.13  2002/03/27 17:05:04  talbert
- *Made changes necessary to compile in Windows 2000 using Microsoft Visual C++ 6.0.
- *GUI.cpp - needed to return something from function LoadPreprocessedCallback()
- *UserInterfaceLogic.cpp - moved definitions of for loop control variables outside of loop for
- *scope reasons.
- *SnakeWrapper.cpp - changed outdt1->data to *outdt1 and outdt2->data to *outdt because
- *these variables are float, not structures.  Also changed a line using snprintf to
- *sprintf because snprintf is a GNU extension.
- *Added the files snake32.dsp and snake32.dsw for compiling in Windows 2000.
- *
- *Revision 1.12  2002/03/27 15:04:26  moon
- *Changed a bunch of stuff so that the state was basically reset when the snake
- *window is hidden (accept or cancel segmentation), and then opened again.  for
- *example, the bubbles browser needed to be emptied, the active/inactive groups
- *needed to be set to the defaults again, the radio button for the preproc
- *data needed to be turned off (so original data is shown), etc.
- *
- *Added code to the acceptinitialization button that converts bubble information
- *into binary snake initialization image, and previous segmentation info of the
- *same label should also be preserved (i.e. segmentation info that comes from
- *IRIS can be used for the initialization as well as bubbles). The snake is
- *initialized, and the controls are activated.
- *
- *Still need to code the resetinitialization so that the bubble stuff, etc. is re-
- *enabled.
- *
- *None of the vcr buttons do anything, still.
- *
- *Revision 1.11  2002/03/26 19:22:14  moon
- *I don't think I really changed anything, but I had updated, and it tried to "merge" versions with and without ^M endline characters
- *
- *Revision 1.10  2002/03/26 18:16:32  scheuerm
- *Added loading and display of preprocessed data:
- *- added vtkImageDeepCopy function
- *- added flags indicating which dataset to display in GlobalState
- *- added flag indicating whether to load gray or preprocessed data
- *  in the GUI class
- *
- *Revision 1.9  2002/03/25 02:15:57  scheuerm
- *Added loading of preprocessed data. It isn't being converted
- *to floats yet. It's not possible to actually display the data
- *right now.
- *
- *Revision 1.8  2002/03/24 19:27:46  talbert
- *Added callback the preprocess button to show dialog boxes for filtering.  Added callbacks for buttons in filtering dialog boxes.  Modified the AddBubbles callback so that the newest bubble is selected in the Bubble Browser.  m_OutAboutCompiled and ran to verify that new bubbles are selected and that the dialogs appear over the
- *3d window.  talbert s f
- *
- *Revision 1.7  2002/03/22 16:44:16  moon
- *added OpenGL display of bubbles in Window2D_s::draw
- *
- *Revision 1.6  2002/03/21 15:45:46  bobkov
- *implemented callbacks for buttons AddBubble and RemoveBubble, implemented callbacks for Radius slider and ActiveBubble browser, created methods getBubbles and getNumberOfBubbles   e
- *
- *Revision 1.5  2002/03/19 19:35:32  moon
- *added snakewrapper to makefile so it gets compiled. started putting in callback,
- *etc. for snake vcr buttons.  added snake object to IrisGlobals, instantiated in Main
- *
- *Revision 1.4  2002/03/19 17:47:10  moon
- *added some code to disable widgets, make the radio buttons work, etc. in the snake window.  fixed the quit callback from the snake window to work (crashed before)
- *changed the [accept/restart]bubble_button widgets to be acceptinitialization_button and added callbacks (empty).
- *
- *Revision 1.3  2002/03/08 14:06:29  moon
- *Added Header and Log tags to all files
- **/
-
diff --git a/UserInterface/MainComponents/UserInterfaceLogic.h b/UserInterface/MainComponents/UserInterfaceLogic.h
deleted file mode 100644
index 88eac1e..0000000
--- a/UserInterface/MainComponents/UserInterfaceLogic.h
+++ /dev/null
@@ -1,1543 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: UserInterfaceLogic.h,v $
-  Language:  C++
-  Date:      $Date: 2011/04/18 17:55:20 $
-  Version:   $Revision: 1.56 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __UserInterfaceLogic_h_
-#define __UserInterfaceLogic_h_
-
-#if defined(_MSC_VER)
-#pragma warning ( disable : 4786 )
-#endif
-
-#include "SNAPCommonUI.h"
-#include "UserInterface.h"
-
-// Necessary forward references
-class HelpViewerLogic;
-class PreprocessingUILogic;
-class RestoreSettingsDialogLogic;
-class SnakeParametersUILogic;
-class ImageIOWizardLogic;
-class RestrictedImageIOWizardLogic;
-class ImageInfoCallbackInterface;
-class LabelEditorUILogic;
-class LayerInspectorUILogic;
-class IRISSliceWindow;
-class SNAPSliceWindow;
-class MeshIOWizardUILogic;
-class SliceWindowCoordinator;
-class SimpleFileDialogLogic;
-class ResizeRegionDialogLogic;
-class AppearanceDialogUILogic;
-class ReorientImageUILogic;
-class Window3D;
-
-template <class TFlag> class FLTKWidgetActivationManager;
-//template<class TPixel> class ImageIOWizardLogic;
-//class SegmentationImageIOWizardLogic;
-
-#include <time.h>
-
-// ITK forward references
-namespace itk {
-  template <class TObject> class SimpleMemberCommand;
-  template <class TObject> class MemberCommand;
-};
-
-/**
- * \class UserInterfaceLogic
- * \brief Logic for the main user interface.
- *
- * This class implements virtual function from
- * the GUI class that is generated by fluid.
- * The idea is to have virtual functions for
- * all the GUI callbacks, and then override
- * them in this class, allowing us to avoid
- * coding inside fluid, since it's annoying.
- *
- * Note that the GUI class contains all the
- * windows (the IRIS window, the 3D Snake window,
- * and all the dialogs).
- */
-class UserInterfaceLogic : public UserInterface 
-{
-public:
-
-  /** Constructor, calls GUI constructor, calls init */
-  UserInterfaceLogic(IRISApplication *iris);
-
-  /** Destructor */
-  virtual ~UserInterfaceLogic();
-
-  /** This method launches the user interface */
-  void Launch();
-
-  /** Resets the region of interest to contain the entire volume */
-  void OnResetROIAction();
-
-  /** Reset to the initial state */
-  void OnMenuResetAll();
-
-  /**
-   *
-   * DESCRIPTION:
-   * callback for the snake button
-   * this function takes care of initializing
-   * the global variable roi_data, sets vox_data
-   * to point to roi_data, sets up the snake window
-   * and calls ShowSNAP()
-   *
-   * PRECONDITIONS:
-   * - global_state must have a valid ROI
-   *
-   * POSTCONDITIONS:
-   * - snake window is displayed, IRIS is hidden
-   */
-  void OnSnakeStartAction();
-
-  /**
-   *
-   * DESCRIPTION:
-   * Callback for showing the dialog box for preprocessing the grey data.
-   * Depending on the type of snake chosen either the dialog for thresholding
-   * or edge detection is displayed.
-   *
-   * PRECONDITIONS:
-   * - main snake window is initialized and active
-   *
-   * POSTCONDITIONS:
-   * - preprocessing dialog appears on screen
-   */
-  void OnPreprocessAction();
-  
-  /** Callback for when the preprocessing completes */
-  void OnPreprocessClose();
-
-  /** Callback to display the color map window */
-  void OnPreprocessedColorMapAction();
-  void OnColorMapCloseAction();
-  void OnColorMapSelectAction();
-
-  /** Callback for when preprocessing preview status changes */
-  void OnPreprocessingPreviewStatusUpdate(bool flagPreview);
-
-  /**
-   *
-   * DESCRIPTION:
-   * callback to set bubbles for snake initialization
-   * - sets a bubble at the current crosshairs position with the radius
-   * equal to the current value on the  radius slider
-   * - adds the bubble to the Active Bubbles browser
-   *
-   * PRECONDITIONS:
-   * - Snake GUI is active
-   * - Crosshairs position is within allowed boundaries
-   *
-   * POSTCONDITIONS:
-   * - all previously set bubbles as well as the new bubble are displayed
-   * in 2d windows
-   * - Active Bubbles browser contains all previously set bubbles as
-   * well as the new bubble and their parameters are displayed in the browser
-   */
-  void OnAddBubbleAction();
-
-  /**
-   *
-   * DESCRIPTION:
-   * callback to remove a bubble
-   * - removes a highlighted bubble from Active Bubbles browser
-   *
-   * PRECONDITIONS:
-   * - Snake GUI is active
-   * - Active Bubbles browser contains at least one bubble
-   *
-   * POSTCONDITIONS:
-   * - highlighted bubble has been removed from Active Bubbles browser
-   * and is no longer displayed in 2d windows
-   * - Active Bubbles browser contains all remaining bubbles and their
-   * parameters are displayed in the browser
-   * - all remaining bubbles are displayed in 2d windows
-   *
-   */
-  void OnRemoveBubbleAction();
-
-  /**
-   *
-   * DESCRIPTION:
-   * callback to browse through the bubbles in the Active Bubbles browser
-   * - highlights a line clicked in the browser window and sets the radius
-   * slider to the value of the highlighted bubble's radius
-   *
-   * PRECONDITIONS:
-   * - Snake GUI is active
-   * - Active Bubbles browser contains at least one bubble
-   *
-   * POSTCONDITIONS:
-   * - the line clicked in the browser window is highlighted
-   * - value of m_HighlightedBubble integer variable is set to the
-   * number of the line highlighted in the browser window
-   * - radius slider value is reset to the value of the highlighted
-   * bubble's radius
-   */
-  void OnActiveBubblesChange();
-
-  /**
-   *
-   * DESCRIPTION:
-   * callback to set the radius of a bubble highlighted in the
-   * Active Bubbles browser
-   * - sets the radius of the highlighted bubble to the current value of
-   * the radius slider
-   * - only displays the current value of the radius slider if no bubble is
-   * highlighted or if the Active Bubbles browser is empty
-   *
-   * PRECONDITIONS:
-   * - Snake GUI is active
-   *
-   * POSTCONDITIONS:
-   * - current value of the radius slider is displayed
-   * - radius of the highlighted bubble is set to the current value of
-   * the radius slider
-   * - visualisation of the highlighted bubble in 2d windows changes
-   * its radius correspondingly
-   * - all remaining bubbles are left unchanged
-   */
-  void OnBubbleRadiusChange();
-
-  /** 
-   * Opens the snake params dialog, allowing the user to modify snake params
-   */
-  void OnSnakeParametersAction();
-
-  /**
-   *
-   * DESCRIPTION:
-   * callback for accepting a snake segmentation
-   *
-   * PRECONDITIONS:
-   * - roi_data is valid
-   * - roi_data.snakeImageData is initialized
-   *
-   * POSTCONDITIONS:
-   * - roi_data.snakeImageData has been merged with full_data.segImageData
-   * - roi_data is deleted
-   * - IRIS window is shown
-   *
-   */
-  void OnAcceptSegmentationAction();
-
-  /**
-   *
-   * DESCRIPTION:
-   * callback for canceling a snake segmentation
-   *
-   * PRECONDITIONS:
-   *
-   * POSTCONDITIONS:
-   * - snake window is hidden, IRIS is shown
-   * - roi_data is deleted
-   *
-   */
-  void OnCancelSegmentationAction();
-
-
-  /**
-   *
-   * DESCRIPTION:
-   * disables or enables the UpdateMesh button in snake win depending
-   * on the state of the checkbox
-   *
-   * PRECONDITIONS:
-   *
-   * POSTCONDITIONS:
-   *
-   */
-  void OnContinuousViewUpdateChange();
-
-  /**
-   *
-   * DESCRIPTION:
-   * Switches to InOut snake mode
-   *
-   * PRECONDITIONS:
-   * - Snake UI is active
-   *
-   * POSTCONDITIONS:
-   * - all current preprocessed data is invalidated
-   */
-  void OnInOutSnakeSelect();
-
-  /**
-   *
-   * DESCRIPTION:
-   * Switches to Edge snake mode
-   *
-   * PRECONDITIONS:
-   * - Snake UI is active
-   *
-   * POSTCONDITIONS:
-   * - all current preprocessed data is invalidated
-   */
-  void OnEdgeSnakeSelect();
-
-  /**
-   *
-   * DESCRIPTION:
-   * callback for accepting the snake initialization.  The active
-   * bubbles are voxelized.  roi_data.segImageData and snakeInitImageData
-   * are initialized and synchronized.  The bubble voxels are put into
-   * snakeInitImageData. If the grey data has been preprocessed, and
-   * some type of initialization is present in snakeInitImageData (either
-   * a bubble or pre-existing segmentation data from segImageData), the
-   * snake can now be run.
-   *
-   * PRECONDITIONS:
-   * - snake window is up and running
-   *
-   * POSTCONDITIONS:
-   * - global_state.GetSnakeActive is true
-   *
-   */
-  void OnAcceptInitializationAction();
-
-  /**
-   *
-   * DESCRIPTION:
-   * callback for restarting the snake initialization.  Any current snake
-   * state is forgotten, the snake controls are disabled, the segmentation
-   * shown in the 2D windows reverts back to the segImageData, and the bubbles
-   * are shown again.  The initialization widgets (bubbles, preproc) are enabled
-   *
-   * PRECONDITIONS:
-   *
-   * POSTCONDITIONS:
-   * - global_state.GetSnakeActive is false
-   *
-   */
-  void OnRestartInitializationAction();
-
-  /**
-   * User wants to go back to the preprocessing page from the segmentation 
-   * initialization page.  This callback will simply flip the page and clear
-   * the bubbles
-   */
-  void OnRestartPreprocessingAction();
-
-  /** The user has finished preprocessing the image and flips to the next 
-   * page in the wizard.  The speed image must be valid for this button to be
-   * active */
-  void OnAcceptPreprocessingAction();
-
-  /**
-   *
-   * DESCRIPTION:
-   * callback for the snake "vcr" rewind button.  Restarts the snake
-   * at the same state as when AcceptInitialization button was pressed
-   *
-   * PRECONDITIONS:
-   *
-   * POSTCONDITIONS:
-   *
-   */
-  void OnSnakeRewindAction();
-
-  /**
-   *
-   * DESCRIPTION:
-   * simply sets a flag so that the play button knows to stop
-   *
-   * PRECONDITIONS:
-   *
-   * POSTCONDITIONS:
-   *
-   */
-  void OnSnakeStopAction();
-
-  /**
-   *
-   * DESCRIPTION:
-   * continuously steps the snake until m_SnakeIsRunning flag is unset
-   *
-   * PRECONDITIONS:
-   *
-   * POSTCONDITIONS:
-   *
-   */
-  void OnSnakePlayAction();
-
-  /**
-   *
-   * DESCRIPTION:
-   * runs the snake for one step.
-   *
-   * PRECONDITIONS:
-   *
-   * POSTCONDITIONS:
-   * - 2D displays are updated according to the current snake state
-   * - if updatecontinuously checkbox is checked, 3D display is updated
-   *
-   */
-  void OnSnakeStepAction();
-
-  /**
-   *
-   * DESCRIPTION:
-   * callback for choice box of how many snake iterations to run per "step"
-   *
-   * PRECONDITIONS:
-   *
-   * POSTCONDITIONS:
-   * m_SnakeStepSize is set
-   *
-   */
-  void OnSnakeStepSizeChange();
-
-  /**
-   * Pops up a dialog to choose a preprocessed data file
-   * pre: LoadPreproc_win is active
-   * post: header information is filled in in the dialog
-   * void LoadPreprocSelectCallback();
-
-   * Fills the header information in the Load Preprocessed data dialog
-   * pre: the filename field contains a valid filename
-   * post: header information is filled in
-   * void SelectPreprocFileCallback();
-
-   * Implements action performed when user presses OK
-   * in the Load Preprocessed data dialog
-   * PRE: nothing
-   * POST: the preprocessed in roi_data is valid
-   * AUTHORS: Talbert and Scheuermann
-   * void LoadPreprocessedDataCallback();
-
-   * Implements callback for Save->Preprocessed
-   * menu item
-   * PRE: nothing
-   * POST: save dialog appears
-   * void SavePreprocessedData_Callback();
-
-   * Implements callback for Okay button in the
-   * Save Preprocessed dialog box
-   * PRE: nothing
-   * POST: If a valid filename was supplied then
-   * the preprocessed data set is saved to the
-   * specified file
-   * void OkaySavePreproc_button_Callback();
-
-   * callback of the radio button for selecting the grey data
-   * for display
-   */
-  void OnSNAPViewOriginalSelect();
-
-  /**
-   * callback of the radio button for selecting the preprocessed data
-   * for display
-   */
-  void OnViewPreprocessedSelect();
-
-  /**
-   *
-   * DESCRIPTION:
-   * close both windows so FL::run returns, and program exits
-   *
-   * PRECONDITIONS:
-   *
-   * POSTCONDITIONS:
-   * - program will exit
-   *
-   */
-  void OnMenuQuit();
-
-  void OnMenuCheckForUpdate();
-  void OnCheckForUpdate();
-
-  void OnMenuViewToggleUI();
-  void OnMenuViewToggleFullscreen();
-  void OnMenuViewRestoreDefault();
-  void OnMenuLaunchNewInstance();
-  void OnMenuShowVolumes();
-
-
-  // Color label callbacks
-  void UpdateColorLabelMenu();
-  void UpdateColorLabelSelection();
-  void OnDrawingLabelUpdate();
-  void OnDrawOverLabelUpdate();
-  
-  void RedrawWindows();
-  void ResetScrollbars();
-  void UpdateImageProbe();
-  void UpdateMainLabel();
-  // void Activate3DAccept(bool on);
-  
-  void OnEditLabelsAction();
-  void OnLabelListUpdate();
-  void UpdateEditLabelWindow();
-  void UpdatePositionDisplay(int id);
-
-  /** Set the current interaction mode */
-  void SetToolbarMode(ToolbarModeType mode);
-  
-  /** Set the current 3D interaction mode */
-  void SetToolbarMode3D(ToolbarMode3DType mode);
-
-  /** Get the pointer to the driving application */
-  irisGetMacro(Driver,IRISApplication *);
-
-  /** Get the pointer to the system interface */
-  irisGetMacro(SystemInterface,SystemInterface *);
-
-  /** Get the reference to the appearance settings */
-  irisGetMacro(AppearanceSettings, SNAPAppearanceSettings *);
-
-  /** Update slice data when loading/unloading overly */
-  void UpdateOverlaySlice();
-
-  /** Clear memory before loading a new main image */
-  void UnloadAllImages();
-
-  /** Update the common user interface after loading a new main image  */
-  void OnMainImageUpdate();
-
-  /** Update the common user interface after loading an overlay image  */
-  void OnOverlayImageUpdate();
-
-  /** Update the user interface after loading a new grey main image  */
-  void OnGreyImageUpdate();
-
-  /** Update the user interface after loading a new RGB main image  */
-  void OnRGBImageUpdate();
-
-  /** Called before unloading a grey image, saves settings associated with it */
-  void OnGreyImageUnload();
-
-  /** Update the user interface after loading a new segmentation image  */
-  void OnSegmentationImageUpdate(bool reloaded);
-
-  /** Update the user interface after loading a new labels file  */
-  // void OnSegmentationLabelsUpdate(bool resetCurrentAndDrawOverLabels);
-
-  /** Update the user interface after loading a new preprocessing image  */
-  void OnSpeedImageUpdate();
-
-  // Splash screen functions
-  void ShowSplashScreen();
-  void HideSplashScreen();
-  void UpdateSplashScreen(const char *message);
-  
-  /** A utility to center one window inside another */
-  static void CenterChildWindowInParentWindow(Fl_Window *childWindow,
-                                              Fl_Window *parentWindow);
-  void CenterChildWindowInMainWindow(Fl_Window *childWindow);
-
-  // Zoom/pan management callbacks
-  void OnResetView2DAction(unsigned int window);
-  void OnResetAllViews2DAction();
-  void OnLinkedZoomChange();
-  void OnZoomLevelChange();
-  void OnMultisessionZoomChange();
-  void OnMultisessionPanChange();
-
-  // Method that allows global zoom to be set from the code (i.e., main)
-  void SetZoomLevelAllWindows(float zoom);
-
-  // Internal callback used to update the zoom percentage displayed
-  void OnZoomUpdate(bool flagBroadcastUpdate = true);
-
-  // Internal callback for when the crosshairs position changes. The flag
-  // specifies if this update should be broadcast to other SNAP instances
-  void OnCrosshairPositionUpdate(bool flagBroadcastUpdate = true);
-
-  // Internal callback for when the view position changes
-  void OnViewPositionsUpdate (bool flagBroadcastUpdate = true);
-
-  // Callback for when 3D view changes
-  void OnTrackballUpdate(bool flagBroadcastUpdate = true);
-
-  // Internal method called when slices need to be re-connected to the image,
-  // i.e., when a new image is loaded or the image-display geometry changes
-  void OnImageGeometryUpdate();
-
-  /** Get the object used to coordinate zoom in slice windows */
-  irisGetMacro(SliceCoordinator,SliceWindowCoordinator *);
-
-  // Polygon button callbacks
-  void OnClosePolygonAction(unsigned int window);
-  void OnUndoPointPolygonAction(unsigned int window);
-  void OnClearPolygonAction(unsigned int window);
-  void OnAcceptPolygonAction(unsigned int window);
-  void OnInsertIntoPolygonSelectedAction(unsigned int window);
-  void OnDeletePolygonSelectedAction(unsigned int window);
-  void OnPastePolygonAction(unsigned int window);
-  void OnPolygonStateUpdate(unsigned int id);
-  void OnIRISFreehandFittingRateUpdate();
-
-  // Paintbrush action callbacks
-  void OnPaintbrushAttributesUpdate();
-  void OnPaintbrushPaint();
-  void UpdatePaintbrushAttributes();
-
-  // IRIS: Annotation mode
-  void OnAnnotationAttributesUpdate();
-
-  // IRIS: 3D Window callbacks
-  void OnIRISMeshUpdateAction();
-  void OnIRISMeshAcceptAction();
-  void OnMeshResetViewAction();
-  void OnIRISMeshEditingAction();
-  void OnIRISMeshDisplaySettingsUpdate();
-   
-  // SNAP: 3D Window callbacks
-  void OnSNAPMeshUpdateAction();
-  void OnSNAPMeshResetViewAction();
-  void OnSNAPMeshContinuousUpdateAction();
-
-  // Volume and statistics actions
-  void OnStatisticsUpdateAction();
-  void OnStatisticsExportAction();
-  void OnStatisticsCopyAction();
-
-  // Method called when user tries to close the window
-  void OnMainWindowCloseAction();
-  
-  // Show the help system
-  void ShowHTMLPage(const char *link);
-
-  // Update Layer Inspector
-  void OnLayerInspectorUpdate();
-
-  // Get the window under mouse focus or -1 if none
-  int GetWindowUnderFocus(void);
-  
-  // Opacity slider callbacks
-  void OnIRISLabelOpacityChange();
-
-  // Undo/Redo buttons
-  void OnUndoAction();
-  void OnRedoAction();
-
-  // Method for creating undo points
-  void StoreUndoPoint(const char *text);
-  void ClearUndoPoints();
-
-  // Methods to tweak window positions
-  void OnWindowFocus(int iWindow);
-  void OnWindowCollapse(int iWindow);
-
-  // Save As PNG
-  void OnActiveWindowSaveSnapshot(unsigned int window);
-
-  // Get the value of the freehand drawing widget
-  double GetFreehandFittingRate()
-    { return m_InIRISFreehandFittingRate->value(); }
-
-  // Load Images Non-Interactively
-  void NonInteractiveLoadRGB(const char *fname);
-  void NonInteractiveLoadGrey(const char *fname);
-  void NonInteractiveLoadSegmentation(const char *fname);
-  void NonInteractiveLoadLabels(const char *fname);
-
-  // Load main image, whether it's RGB or Gray
-  void NonInteractiveLoadMainImage(const char *fname, bool force_grey, bool force_rgb);
-  void NonInteractiveLoadOverlayImage(const char *fname, bool force_grey, bool force_rgb);
-
-  // Update menu of color labels
-  // TODO: move this to a separate class in FLTK widget directory
-  Fl_Menu_Item *GenerateColorLabelMenu(bool all, bool visible, bool clear);
-  void DeleteColorLabelMenu(Fl_Menu_Item *menu);
-
-  // Display tips and tricks
-  void DisplayTips();
-
-  // Get the current display layout
-  DisplayLayout GetDisplayLayout() const 
-    { return m_DisplayLayout; } 
-
-  // Change the layout, size of the SNAP window
-  void SetDisplayLayout(DisplayLayout dlo);
-
-  Fl_Menu_Bar* GetMainMenuBar() { return m_MenubarMain; }
-  Fl_Window* GetMainWindow() { return m_WinMain; }
-  Fl_Window* GetPopupToolbarWindow() { return m_WinTestPop; }
-
-  void OnCollapsedViewPopupMenu();
-
-protected:
-
-  /**
-   *
-   * DESCRIPTION:
-   * Initializes everything so the IRIS window can be shown.
-   * This method is essentially the same as IRIS2000, but
-   * we added a couple initializations of snake window stuff.
-   *
-   * PRECONDITIONS:
-   * - basically assumes it's going to be called in the constructor.
-   *
-   * POSTCONDITIONS:
-   * - the IRIS window can now be shown
-   */
-  void InitializeUI();
-
-  /** hides the iris window and shows the snake window */
-  void ShowSNAP();
-
-  /** Hides the snake window and shows the iris window */
-  void ShowIRIS();
-
-  /**
-   * DESCRIPTION
-   * Runs the snake, and updates the GUI
-   *
-   * PRE
-   * snake must be ready to run
-   *
-   * POST
-   *
-   * RETURNS
-   * 1 if running is successful, 0 if an error occurred
-   */
-  // int RunSnake();
-
-  // Callbacks to the simple file dialog
-  void OnLoadLabelsAction();
-  void OnSaveLabelsAction();
-  void OnWriteVoxelCountsAction();
-
-  void OnSliceSliderChange(int id);
-
-  // Menu item callbacks
-  void OnMenuNewSegmentation();
-  void OnMenuSaveGrey();
-  void OnMenuLoadGrey();
-  void OnMenuLoadRGB();
-  void OnMenuLoadGreyOverlay();
-  void OnMenuLoadRGBOverlay();
-  void OnMenuUnloadOverlayLast();
-  void OnMenuUnloadOverlays();
-  void OnMenuLoadSegmentation();
-  void OnMenuLoadLabels();
-  void OnMenuSaveGreyROI();
-  void OnMenuSaveSegmentation();
-  void OnMenuSaveSegmentationMesh();
-  void OnMenuSaveLabels();
-  void OnMenuSaveScreenshot(unsigned int iSlice);
-  void OnMenuSaveScreenshotSeries(unsigned int iSlice);
-  void OnMenuWriteVoxelCounts();
-  void OnMenuIntensityCurve();
-  void OnMenuColorMap();
-  void OnMenuShowLayerInspector();
-  void OnMenuSavePreprocessed(); 
-  void OnMenuSaveLevelSet(); 
-  void OnLoadRecentAction(unsigned int iRecent);
-  void OnLoadPreprocessedImageAction();
-  void OnMenuLoadAdvection();
-  void OnMenuImageInfo();
-  void OnMenuReorientImage();
-
-  // Save a slice
-  void OnMenuExportSlice(unsigned int iSlice);
-
-  // Display options callbacks
-  void OnMenuShowDisplayOptions();
-  
-  // Opacity slider callbacks
-  void OnSNAPLabelOpacityChange();
-
-  // Help system callbacks
-  void OnLaunchTutorialAction();
-
-  // Set the active page in the segmentation pipeline
-  void SetActiveSegmentationPipelinePage(unsigned int page);
-
-  // Restoring settings
-  void OnRestoreSettingsAction();
-  void OnDoNotRestoreSettingsAction();
-
-  // Toggle cursor synchronization
-  void OnSynchronizeCursorAction();
-
-  // Toggle hidden features
-  void OnHiddenFeaturesToggleAction();
-
-  // Common code for loading segmentation
-  void LoadSegmentation(const bool noninteractive, const char *fname = NULL);
-
-  char *m_ChosedFile;
-
-  // Set of logical states that the UI may encounter
-  enum UIStateFlags {
-    UIF_NULL,
-    UIF_GRAY_LOADED,
-    UIF_RGB_LOADED,
-    UIF_BASEIMG_LOADED,
-    UIF_OVERLAY_LOADED,
-    UIF_IRIS_ACTIVE,
-    UIF_IRIS_WITH_BASEIMG_LOADED,
-    UIF_IRIS_WITH_GRAY_LOADED,
-    UIF_IRIS_MESH_DIRTY,
-    UIF_IRIS_MESH_ACTION_PENDING,
-    UIF_IRIS_ROI_VALID,
-    UIF_LINKED_ZOOM,
-    UIF_UNDO_POSSIBLE,
-    UIF_REDO_POSSIBLE,
-    UIF_UNSAVED_CHANGES,
-    UIF_MESH_SAVEABLE,
-
-    UIF_SNAP_ACTIVE,
-    UIF_SNAP_PAGE_PREPROCESSING,
-    UIF_SNAP_PAGE_BUBBLES,
-    UIF_SNAP_PAGE_SEGMENTATION,
-    UIF_SNAP_PREPROCESSING_ACTIVE,
-    UIF_SNAP_PREPROCESSING_DONE,
-    UIF_SNAP_DIALOG_PARAMETERS,
-    UIF_SNAP_DIALOG_PREPROCESSING,
-    UIF_SNAP_SNAKE_RUNNING,
-    UIF_SNAP_SNAKE_INITIALIZED,
-    UIF_SNAP_SNAKE_EDITABLE,
-    UIF_SNAP_SPEED_AVAILABLE,
-    UIF_SNAP_MESH_DIRTY,
-    UIF_SNAP_MESH_CONTINUOUS_UPDATE
-  };
-
-private:
-
-  // Typedef for event callback commands
-  typedef itk::SimpleMemberCommand<UserInterfaceLogic> SimpleCommandType;
-  typedef itk::MemberCommand<UserInterfaceLogic> ProgressCommandType;
-
-  // Pointer to the driving IRIS application object
-  IRISApplication *m_Driver;
-
-  // Pointer to the instance of the UserInterfaceLogic that has been launched
-  // (for static members, like GlobalEventHandler)
-  static UserInterfaceLogic *m_GlobalUI;
-
-  // Pointer to the system interface object
-  SystemInterface *m_SystemInterface;
-
-  // Settings related to the cosmetic appearance of the application
-  SNAPAppearanceSettings *m_AppearanceSettings;
-
-  /** Reason why a user may be prompted to save changes */
-  enum PromptReason {
-    REASON_QUIT,
-    REASON_RESET,
-    REASON_LOAD_MAIN,
-    REASON_LOAD_SEGMENTATION };
-
-  // Widget activation manager - simplifies the headache of keeping widgets
-  // activated and deactivated
-  FLTKWidgetActivationManager<UIStateFlags> *m_Activation; 
-
-  // how many snake iterations per step
-  int m_SnakeStepSize;
-
-  // The callback command used in the (complicated) snake VCR pipeline
-  itk::SmartPointer<SimpleCommandType> m_PostSnakeCommand;
-
-  // The main window label
-  std::string m_MainWindowLabel;
-
-  /** Wizard used to load grey image files */
-  ImageIOWizardLogic *m_WizGreyIO;
-
-  /** Wizard used to load and save segmentation image files */
-  RestrictedImageIOWizardLogic *m_WizSegmentationIO;
-
-  /** Wizard used to load and save preprocessing image files */
-  RestrictedImageIOWizardLogic *m_WizPreprocessingIO;
-
-  /** Wizard used to load and save preprocessing image files */
-  RestrictedImageIOWizardLogic *m_WizLevelSetIO;
-
-  /** Wizard for 3D mesh export */
-  MeshIOWizardUILogic *m_WizMeshExport;
-
-  /** Layer dialog */
-  LayerInspectorUILogic *m_LayerUI;
-
-  /** UI object for label editing */
-  LabelEditorUILogic *m_LabelEditorUI;
-
-  /** Preprocessing UI object */
-  PreprocessingUILogic *m_PreprocessingUI;
-
-  /** Parameter setting UI object */
-  SnakeParametersUILogic *m_SnakeParametersUI;
-
-  /** A restore settings dialog */
-  RestoreSettingsDialogLogic *m_DlgRestoreSettings;
-
-  /** A dialog for resampling the image */
-  ResizeRegionDialogLogic *m_DlgResampleRegion;
-
-  /** A dialog for showing display options */
-  AppearanceDialogUILogic *m_DlgAppearance;
-
-  /** Image reorientation dialog */
-  ReorientImageUILogic *m_DlgReorientImage;
-
-  /** Help window */
-  HelpViewerLogic *m_HelpUI;
-
-  /** Managers for the slice view windows */
-  IRISSliceWindow *m_IRISWindowManager2D[3];
-  SNAPSliceWindow *m_SNAPWindowManager2D[3];
-
-  /** A coordinator for the slice windows */
-  SliceWindowCoordinator *m_SliceCoordinator;
-
-  /** Managers for the 3D windows */
-  Window3D *m_IRISWindowManager3D, *m_SNAPWindowManager3D;
-
-  /** Splash screen timer */
-  clock_t m_SplashScreenStartTime;
-
-  /** Save/load labels dialog */
-  SimpleFileDialogLogic *m_DlgLabelsIO;
-
-  /** Write voxels dialog */
-  SimpleFileDialogLogic *m_DlgVoxelCountsIO;
-
-  // An adapter used in association with the image IO wizard
-  ImageInfoCallbackInterface *m_GreyCallbackInterface;
-
-  // A list of recently open files shown in the load recent menu
-  std::string m_RecentFileNames[5];
-
-  // Temporary value used for opacity slider toggling
-  double m_OpacityToggleValue;
-
-  // Whether the main window is in fullscreen mode
-  bool m_FullScreen;
-
-  // Global event handler (shortcuts, etc)
-  static int GlobalEventHandler(int);
-
-  // Global 'open document' event handler (Apple for now)
-  static void GlobalOpenDocumentHandler(const char *fn_open);
-  
-  // Method to actually open a document
-  void OpenDraggedContent(const char *fn_open, bool interactive);
-  void OnOpenDroppedAction(int selection);
-
-  // Called by the above, responds to global events
-  int OnGlobalEvent(int);
-
-  // Main idle function (for cursor sync)
-  static void GlobalIdleHandler(void *);
-
-  // Callbacks for state flags
-  void OnUnsavedChangesStateChange(UIStateFlags flag, bool value);
-  void OnMeshAvailabilityStateChange(UIStateFlags flag, bool value);
-
-  /** Initialization subroutine that sets up the activation manager */
-  void InitializeActivationFlags();
-
-  /**
-   * Some GUI state is shared between the windows, like opacity settings, 
-   * toolbar mode. This function syncs the two.
-   */
-  void SyncIRISToSnake();
-  
-  /**
-   * Some GUI state is shared between the windows, like opacity settings, 
-   * toolbar mode. This function syncs the two.
-   */
-  void SyncSnakeToIRIS();
-
-  /** Common code for cancelling and accepting the segmentation */
-  void CloseSegmentationCommon();
-
-  /** This method is used to figure out which image axis corresponds to a
-   * given display window */
-  unsigned int GetImageAxisForDisplayWindow(unsigned int window);
-
-  /** Progress callback for ITK methods. Will show the progress bar and fill
-   * the bar as necessary */
-  void OnITKProgressEvent(itk::Object *source, const itk::EventObject &event);
-
-  // This method is called when the snake image has changed.
-  void OnSnakeUpdate();
-
-  // Set 'zoomed' window to 0..3, or pass in -1 in order to restore the display
-  // to four side by side windows
-  void UpdateWindowFocus(
-    Fl_Group *parent, Fl_Group **panels, Fl_Gl_Window **boxes, int iWindow);
-
-  // Update the color map of the speed image
-  void UpdateSpeedColorMap();
-
-  // Update the bubble display
-  void UpdateBubbleUI();
-
-  // Prompt the user if there are unsaved changes. Returns true if it's ok to 
-  // proceed without saving
-  bool PromptBeforeLosingChanges(PromptReason reason);
-
-  // Toggle display elements (hide control panel, slice window toolbars)
-  void ToggleDisplayElements();
-  void ToggleFullScreen();
-
-  // Current display layout
-  DisplayLayout m_DisplayLayout;
-
-  /* Command used for progress tracking */
-  itk::SmartPointer<ProgressCommandType> m_ProgressCommand;
-
-  // A function used to run the snake in the background
-  friend void fnSnakeIdleFunction(void *userData);
-  friend class UserInterfaceLogicMemberObserver;
-
-  // Update the menu of recent files
-  void GenerateRecentFilesMenu();
-
-  // Generate a PNG filename for use in saving snapshots
-  std::string GenerateScreenShotFilename();
-
-  // A string where the last saved filename is stored
-  std::string m_LastSnapshotFileName;
-
-  // State of the UNDO system at the time the segmentation image
-  // was last saved or loaded. This allows us to set the unsaved
-  // changes flag during undo and redo operations
-  std::list<unsigned long> m_UndoStateAtLastIO;
-
-  // Menu containing color labels, for use in FLTK menus
-  Fl_Menu_Item *m_MenuDrawingLabels, *m_MenuDrawOverLabels;
-};
-
-#endif
-
-/*
- *$Log: UserInterfaceLogic.h,v $
- *Revision 1.56  2011/04/18 17:55:20  pyushkevich
- *Fixed bug 3243462. We can now save the mesh in SNAP (level set) mode
- *
- *Revision 1.55  2010/10/12 16:02:05  pyushkevich
- *Improved handling of collapsed windows
- *
- *Revision 1.54  2010/05/31 19:52:37  pyushkevich
- *Added volumes and statistics window
- *
- *Revision 1.53  2010/05/27 11:16:22  pyushkevich
- *Further improved polygon drawing interface
- *
- *Revision 1.52  2010/05/27 07:29:36  pyushkevich
- *New popup menu for polygon drawing, other improvements to polygon tool
- *
- *Revision 1.51  2010/04/16 05:14:38  pyushkevich
- *FIX: touched up previous checkin
- *
- *Revision 1.50  2010/04/16 04:02:35  pyushkevich
- *ENH: implemented drag and drop, OSX events, new command-line interface
- *
- *Revision 1.49  2010/04/14 10:06:23  pyushkevich
- *Added option to launch external SNAP
- *
- *Revision 1.48  2010/03/23 21:23:23  pyushkevich
- *Added display halving capability,
- *command line switches --zoom, --help, --compact
- *
- *Revision 1.47  2009/11/16 20:29:29  garyhuizhang
- *BUGFIX: a fix for messed up display on mac when switching between different panel zoom mode
- *ENH: added color map menu item
- *
- *Revision 1.46  2009/10/30 13:49:48  pyushkevich
- *FIX: improved behavior of synchronized pan. it now broadcasts viewport center rel. to cursor posn.
- *FIX: improved IPC. only 'new' messages are now acted on.
- *
- *Revision 1.45  2009/10/26 16:00:56  pyushkevich
- *ENH: improved/fixed cursor movement in all modes. added menu items for F3/F4
- *
- *Revision 1.44  2009/10/17 20:39:51  pyushkevich
- *ENH: added tip of the day
- *
- *Revision 1.43  2009/09/14 19:04:52  garyhuizhang
- *ENH: layer inspector support for curor position input
- *
- *Revision 1.42  2009/09/10 21:25:24  garyhuizhang
- *ENH: Layer inspector now supports contrast adjustment of main image
- *
- *Revision 1.41  2009/08/29 23:17:02  garyhuizhang
- *BUGFIX: fix a memory leak
- *
- *Revision 1.40  2009/08/28 20:35:15  garyhuizhang
- *ENH: remove OverlayUI (replaced by LayerInspectorUI)
- *
- *Revision 1.39  2009/08/28 16:33:03  garyhuizhang
- *ENH: rename LayerEditor as LayerInspector
- *
- *Revision 1.38  2009/08/28 16:05:44  pyushkevich
- *Enabled toggling of UI components with 'F3' key and fullscreen mode with 'F4' key
- *
- *Revision 1.37  2009/08/26 21:49:56  pyushkevich
- *Improvements to the color map widget
- *
- *Revision 1.36  2009/08/26 01:10:20  garyhuizhang
- *ENH: merge grey and RGB overlays into one wrapper list and modify the associated GUI codes
- *
- *Revision 1.35  2009/07/22 21:06:24  pyushkevich
- *Changed the IO system and wizards, removed templating
- *
- *Revision 1.34  2009/06/18 18:11:24  garyhuizhang
- *ENH: multisession pan ui support
- *BUGFIX: single session pan working again
- *
- *Revision 1.33  2009/06/16 05:57:01  garyhuizhang
- *ENH: initial UI for layer manager, which replacing the old RGB overlay UI
- *
- *Revision 1.32  2009/06/15 01:54:10  garyhuizhang
- *BUGFIX: linked zoom misbehaving with overlay
- *
- *Revision 1.31  2009/06/14 20:43:17  garyhuizhang
- *ENH: multiple RGB overlay support
- *
- *Revision 1.30  2009/06/14 06:13:20  garyhuizhang
- *ENH: menu item association for grey overlay unload
- *
- *Revision 1.29  2009/06/13 05:02:00  garyhuizhang
- *ENH: improved implementation of recent file lists that combines both grey and RGB main images
- *
- *Revision 1.28  2009/06/13 03:29:40  garyhuizhang
- *ENH: checking for available software update
- *
- *Revision 1.27  2009/06/12 05:11:08  garyhuizhang
- *ENH: reorganized user interface
- *
- *Revision 1.26  2009/06/10 02:52:46  garyhuizhang
- *ENH: multiple grey overlay images support
- *
- *Revision 1.25  2009/06/09 05:46:38  garyhuizhang
- *ENH: main image support & grey overlay support
- *
- *Revision 1.24  2009/05/04 20:15:57  garyhuizhang
- *multisession panning support added
- *
- *Revision 1.23  2009/02/10 00:10:12  garyhuizhang
- *ENH: Support two drawing options in the Annotation mode: 1) each line shown only on the slice level it is drawn; 2) each line is shown on all slice levels
- *
- *Revision 1.22  2009/02/09 17:07:47  garyhuizhang
- *FIX: code refactoring -- command line and GUI loading of segmentation now shares the same code.  this enables the validity checking of segmentation image on command line originally implemented for GUI.
- *
- *Revision 1.21  2009/02/05 23:03:41  garyhuizhang
- *ENH: support for saving the hidden feature flag
- *
- *Revision 1.20  2009/02/05 16:21:14  pyushkevich
- *ENH: added hidden features button
- *
- *Revision 1.19  2009/02/03 19:12:35  pyushkevich
- *ENH: added support for checking version via internet
- *
- *Revision 1.18  2009/01/17 10:40:28  pyushkevich
- *Added synchronization to 3D window viewpoint
- *
- *Revision 1.17  2008/12/02 21:43:24  pyushkevich
- *Reorganization of the watershed code
- *
- *Revision 1.16  2008/11/17 19:38:23  pyushkevich
- *Added tools dialog to label editor window
- *
- *Revision 1.15  2008/11/15 12:20:38  pyushkevich
- *Several new features added for release 1.8, including (1) support for reading floating point and mapping to short range; (2) use of image direction cosines to determine image orientation; (3) new reorient image dialog and changes to the IO wizard; (4) display of NIFTI world coordinates and yoking based on them; (5) multi-session zoom; (6) fixes to the way we keep track of unsaved changes to segmentation, including a new discard dialog; (7) more streamlined code for offline loading; (8) [...]
- *
- *Revision 1.14  2008/11/01 11:32:00  pyushkevich
- *Compatibility with ITK 3.8 support for reading oriented images
- *Command line loading of RGB images
- *Improved load-image commands in UserInterfaceLogic
- *
- *Revision 1.13  2008/03/25 19:31:33  pyushkevich
- *Bug fixes for release 1.6.0
- *
- *Revision 1.12  2008/02/27 04:34:46  garyhuizhang
- *1) rename OnMenuSaveScreenshots to OnMenuSaveScreenshotSeries
- *2) support menu access to both save single screenshot and screenshot series
- *
- *Revision 1.11  2008/02/23 23:41:12  garyhuizhang
- *add support for saving screenshots of the whole image volume
- *
- *Revision 1.10  2008/02/10 23:55:22  pyushkevich
- *Added "Auto" button to the intensity curve window; Added prompt before quitting on unsaved data; Fixed issues with undo on segmentation image load; Added synchronization between SNAP sessions.
- *
- *Revision 1.9  2008/01/08 20:34:52  pyushkevich
- *Implement toggle for opacity slider
- *
- *Revision 1.8  2007/12/30 04:05:18  pyushkevich
- *GPL License
- *
- *Revision 1.7  2007/12/25 15:46:23  pyushkevich
- *Added undo/redo functionality to itk-snap
- *
- *Revision 1.6  2007/09/18 18:42:40  pyushkevich
- *Added tablet drawing to polygon mode
- *
- *Revision 1.5  2007/06/07 00:49:16  pyushkevich
- *Debugged RGB changes
- *
- *Revision 1.4  2007/06/06 22:27:22  garyhuizhang
- *Added support for RGB images in SNAP
- *
- *Revision 1.3  2007/05/10 20:19:50  pyushkevich
- *Added VTK mesh export code and GUI
- *
- *Revision 1.2  2006/12/06 01:26:07  pyushkevich
- *Preparing for 1.4.1. Seems to be stable in Windows but some bugs might be still there
- *
- *Revision 1.1  2006/12/02 04:22:23  pyushkevich
- *Initial sf checkin
- *
- *Revision 1.1.1.1  2006/09/26 23:56:18  pauly2
- *Import
- *
- *Revision 1.32  2006/02/02 01:23:10  pauly
- *BUG: Fixed SNAP bugs in the last checkin
- *
- *Revision 1.31  2006/02/01 20:21:26  pauly
- *ENH: An improvement to the main SNAP UI structure: one set of GL windows is used to support SNAP and IRIS modes
- *
- *Revision 1.30  2005/12/12 00:27:44  pauly
- *ENH: Preparing SNAP for 1.4 release. Snapshot functionality
- *
- *Revision 1.29  2005/11/10 23:02:14  pauly
- *ENH: Added support for VoxBo CUB files to ITK-SNAP, as well as some cosmetic touches
- *
- *Revision 1.28  2005/11/03 18:45:29  pauly
- *ENH: Enabled SNAP to read DICOM Series
- *
- *Revision 1.27  2005/10/29 14:00:15  pauly
- *ENH: SNAP enhacements like color maps and progress bar for 3D rendering
- *
- *Revision 1.26  2005/08/11 04:37:07  pauly
- *BUG: Fixed crash when using single-slice mode and entering auto-seg
- *
- *Revision 1.25  2005/04/21 14:46:30  pauly
- *ENH: Improved management and editing of color labels in SNAP
- *
- *Revision 1.24  2005/04/14 16:35:10  pauly
- *ENH: Added Image Info window to SNAP
- *
- *Revision 1.23  2005/03/08 03:12:51  pauly
- *BUG: Minor bugfixes in SNAP, mostly to the user interface
- *
- *Revision 1.22  2004/09/14 14:11:11  pauly
- *ENH: Added an activation manager to main UI class, improved snake code, various UI fixes and additions
- *
- *Revision 1.21  2004/09/08 12:09:46  pauly
- *ENH: Adapting SNAP to work with stop-n-go function in finite diff. framewk
- *
- *Revision 1.20  2004/08/26 18:29:19  pauly
- *ENH: New user interface for configuring the UI options
- *
- *Revision 1.19  2004/08/03 23:26:32  ibanez
- *ENH: Modification for building in multple platforms. By Julien Jomier.
- *
- *Revision 1.18  2004/07/30 15:56:34  jjomier
- *FIX: Warning, disabling 4786 on MSVC
- *
- *Revision 1.17  2004/07/29 14:00:36  pauly
- *ENH: A new interface for changing the appearance of SNAP
- *
- *Revision 1.16  2004/07/24 19:00:06  pauly
- *ENH: Thumbnail UI for slice zooming
- *
- *Revision 1.15  2004/07/21 18:17:45  pauly
- *ENH: Enhancements to the way that the slices are displayed
- *
- *Revision 1.14  2004/03/19 00:54:48  pauly
- *ENH: Added the ability to externally load the advection image
- *
- *Revision 1.13  2004/01/19 22:17:52  pauly
- *ENH: Final touches before the 1.0 release
- *
- *Revision 1.12  2003/12/07 19:48:41  pauly
- *ENH: Resampling, multiresolution
- *
- *Revision 1.11  2003/11/29 17:06:48  pauly
- *ENH: Minor Help issues
- *
- *Revision 1.10  2003/11/10 00:27:26  pauly
- *FIX: Bug with linear interpolation in PDE solver
- *ENH: Help viewer and tutorial
- *
- *Revision 1.9  2003/10/09 22:45:14  pauly
- *EMH: Improvements in 3D functionality and snake parameter preview
- *
- *Revision 1.8  2003/10/07 00:37:27  jjomier
- *ENH: Added cygwin support
- *
- *Revision 1.7  2003/10/06 12:30:00  pauly
- *ENH: Added history lists, remembering of settings, new snake parameter preview
- *
- *Revision 1.6  2003/10/02 14:55:52  pauly
- *ENH: Development during the September code freeze
- *
- *Revision 1.2  2003/09/13 15:18:01  pauly
- *FIX: Got SNAP to work properly with different image orientations
- *
- *Revision 1.1  2003/09/11 13:51:01  pauly
- *FIX: Enabled loading of images with different orientations
- *ENH: Implemented image save and load operations
- *
- *Revision 1.5  2003/08/28 22:58:30  pauly
- *FIX: Erratic scrollbar behavior
- *
- *Revision 1.4  2003/08/28 14:37:09  pauly
- *FIX: Clean 'unused parameter' and 'static keyword' warnings in gcc.
- *FIX: Label editor repaired
- *
- *Revision 1.3  2003/08/27 14:03:23  pauly
- *FIX: Made sure that -Wall option in gcc generates 0 warnings.
- *FIX: Removed 'comment within comment' problem in the cvs log.
- *
- *Revision 1.2  2003/08/27 04:57:47  pauly
- *FIX: A large number of bugs has been fixed for 1.4 release
- *
- *Revision 1.1  2003/07/12 04:46:50  pauly
- *Initial checkin of the SNAP application into the InsightApplications tree.
- *
- *Revision 1.17  2003/07/12 01:34:18  pauly
- *More final changes before ITK checkin
- *
- *Revision 1.16  2003/07/11 23:28:10  pauly
- **** empty log message ***
- *
- *Revision 1.15  2003/07/10 14:30:26  pauly
- *Integrated ITK into SNAP level set segmentation
- *
- *Revision 1.14  2003/06/23 23:59:32  pauly
- *Command line argument parsing
- *
- *Revision 1.13  2003/06/14 22:42:06  pauly
- *Several changes.  Started working on implementing the level set function
- *in ITK.
- *
- *Revision 1.12  2003/06/08 23:27:56  pauly
- *Changed variable names using combination of ctags, egrep, and perl.
- *
- *Revision 1.11  2003/06/08 16:11:42  pauly
- *User interface changes
- *Automatic mesh updating in SNAP mode
- *
- *Revision 1.10  2003/05/22 17:36:19  pauly
- *Edge preprocessing settings
- *
- *Revision 1.9  2003/05/17 21:39:30  pauly
- *Auto-update for in/out preprocessing
- *
- *Revision 1.8  2003/05/14 18:33:58  pauly
- *SNAP Component is working. Double thresholds have been enabled.  Many other changes.
- *
- *Revision 1.7  2003/05/07 19:14:46  pauly
- *More progress on getting old segmentation working in the new SNAP.  Almost there, region of interest and bubbles are working.
- *
- *Revision 1.6  2003/05/05 12:30:18  pauly
- **** empty log message ***
- *
- *Revision 1.5  2003/04/25 02:58:29  pauly
- *New window2d model with InteractionModes
- *
- *Revision 1.4  2003/04/23 06:05:18  pauly
- **** empty log message ***
- *
- *Revision 1.3  2003/04/18 17:32:18  pauly
- **** empty log message ***
- *
- *Revision 1.2  2003/04/18 00:25:37  pauly
- **** empty log message ***
- *
- *Revision 1.1  2003/04/16 05:04:17  pauly
- *Incorporated intensity modification into the snap pipeline
- *New IRISApplication
- *Random goodies
- *
- *Revision 1.1  2003/03/07 19:29:47  pauly
- *Initial checkin
- *
- *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
- *Started the project repository
- *
- *
- *Revision 1.33  2002/04/28 20:12:40  scheuerm
- *tiny documentation changes
- *
- *Revision 1.32  2002/04/28 17:29:43  scheuerm
- *Added some documentation
- *
- *Revision 1.31  2002/04/27 18:30:03  moon
- *Finished commenting
- *
- *Revision 1.30  2002/04/27 17:48:34  bobkov
- *Added comments
- *
- *Revision 1.29  2002/04/27 00:08:27  talbert
- *Final commenting run through . . . no functional changes.
- *
- *Revision 1.28  2002/04/26 17:37:13  moon
- *Fixed callback on save preproc dialog cancel button.
- *Fixed bubble browser output.  Position was zero-based, which didn't match the 2D
- *window slice numbers (1 based), so I changed the bubble positions to be cursor
- *position +1.
- *Disallowed starting snake window if current label in not visible.
- *Put in Apply+ button in threshold dialog, which changes seg overlay to be an
- *overlay of the positive voxels in the preproc data (a zero-level visualization).
- *Added more m_OutMessage and m_OutMessage messages.
- *
- *Revision 1.27  2002/04/24 19:50:23  moon
- *Pulled LoadGreyFileCallback out of GUI into UserInterfaceLogic, made modifications due
- *to change in ROI semantics.  Before, the ROI was from ul to lr-1, which is a bad
- *decision.  I changed everything to work with a ROI that is inclusive, meaning
- *that all voxels from ul through lr inclusive are part of the ROI. This involved
- *a lot of small changes to a lot of files.
- *
- *Revision 1.26  2002/04/23 19:28:20  bobkov
- *declared TweakROI method in UserInterfaceLogic.h to be public
- *left ColorLabel.h and ColorLabel.cpp unchanged
- *
- *Revision 1.25  2002/04/19 23:03:59  moon
- *Changed more stuff to get the snake params state synched with the global state.
- *Changed the range of ground in snake params dialog.
- *Removed the use_del_g stuff, since it's really not necessary, I found out.
- *
- *Revision 1.24  2002/04/19 20:34:58  moon
- *Made preproc dialogs check global state and only preproc if parameters have changed.
- *So no if you hit apply, then ok, it doesn't re process on the ok.
- *
- *Revision 1.23  2002/04/18 21:14:03  moon
- *I had changed the Cancel buttons to be Close on the Filter dialogs, and I changed
- *the names of the callbacks in GUI, but not in UserInterfaceLogic.  So I just hooked them
- *up so the dialogs get closed.
- *
- *Revision 1.22  2002/04/18 21:04:51  moon
- *Changed the IRIS window ROI stuff.  Now the ROI is always valid if an image is
- *loaded, but there is a toggle to show it or not.  This will work better with
- *Konstantin's addition of being able to drag the roi box.
- *
- *I also changed a bunch of areas where I was calling InitializeSlice for the 2D windows,
- *when this is not at all what I should have done.  Now those spots call
- *MakeSegTextureCurrent, or MakeGreyTextureCurrent.  This means that the view is not
- *reset every time the snake steps, the preproc/orig radio buttons are changed, etc.
- *
- *Revision 1.21  2002/04/16 18:54:33  moon
- *minor bug with not stopping snake when play is pushed, and then other
- *buttons are pushed.  Also added a function that can be called when the user
- *clicks the "X" on a window, but it's not what we want, I don't think.  The
- *problem is if the user clicks the "X" on the snake window when a "non modal"
- *dialog is up, all the windows close, but the program doesn't quit.  I think
- *it's a bug in FLTK, but I can't figure out how to solve it.
- *
- *Revision 1.20  2002/04/16 13:07:56  moon
- *Added tooltips to some widgets, made minor changes to enabling/disabling of
- *widgets, clearing 3D window when initialization is restarted in snake window,
- *changed kappa in edge preproc dialog to be [0..1] range instead of [0..3]
- *
- *Revision 1.19  2002/04/14 22:02:54  scheuerm
- *Changed loading dialog for preprocessed image data. Code restructuring
- *along the way: Most important is addition of
- *SnakeVoxDataClass::ReadRawPreprocData()
- *
- *Revision 1.18  2002/04/11 23:07:43  bobkov
- *Commented the Bubble class
- *Commented m_BtnAddBubble, m_BtnRemoveBubble,
- *m_BrsActiveBubbles and m_InBubbleRadius callbacks
- *Commented GetBubbles and GetNumberOfBubbles methodS
- *
- *Revision 1.17  2002/04/10 20:19:40  moon
- *got play and stop vcr buttons to work.
- *put in lots of comments.
- *
- *Revision 1.16  2002/04/09 18:59:33  moon
- *Put in dialog to change snake parameters.  Also implemented Rewind button, which
- *now restarts the snake.  It seems for now that changing snake parameters restarts
- *the snake.  I don't know if this is the way it has to be, or I just did something
- *wrong in snakewrapper.  I'll have to check with Sean.
- *
- *Revision 1.15  2002/04/08 13:32:35  talbert
- *Added a preprocessed save dialog box as well as a save preprocessed menu
- *option in the snake window.  Added the code necessary to implement the
- *GUI side of saving.
- *
- *Revision 1.14  2002/04/07 02:22:49  scheuerm
- *Improved handling of OK and Apply buttons in preprocessing dialogs.
- *
- *Revision 1.13  2002/04/04 15:30:09  moon
- *Put in code to get StepSize choice box filled with values and working.
- *AcceptSegment button callback puts snake seg data into full_data (IRIS)
- *Fixed a couple more UI cosmetic things.
- *
- *Revision 1.12  2002/04/03 22:12:07  moon
- *Added color chip, image probe, seg probe to snake window, although seg probe
- *maybe shouldn't be there.  added update continuously checkbox to 3Dwindow.
- *changes accept/restart to be on top of each other, and one is shown at a time,
- *which I think is more intuitive.
- *changed snake iteration field to be text output.  added callback for step size
- *choice.
- *
- *Revision 1.11  2002/03/27 17:59:40  moon
- *changed a couple things.  nothing big. a callback in .fl was bool return type
- *which didn't compile in windows. this is the version I think will work for a
- *demo for Kye
- *
- *Revision 1.10  2002/03/26 18:16:32  scheuerm
- *Added loading and display of preprocessed data:
- *- added vtkImageDeepCopy function
- *- added flags indicating which dataset to display in GlobalState
- *- added flag indicating whether to load gray or preprocessed data
- *  in the GUI class
- *
- *Revision 1.9  2002/03/25 02:15:57  scheuerm
- *Added loading of preprocessed data. It isn't being converted
- *to floats yet. It's not possible to actually display the data
- *right now.
- *
- *Revision 1.8  2002/03/24 19:27:46  talbert
- *Added callback the preprocess button to show dialog boxes for filtering.  Added callbacks for buttons in filtering dialog boxes.  Modified the AddBubbles callback so that the newest bubble is selected in the Bubble Browser.  m_OutAboutCompiled and ran to verify that new bubbles are selected and that the dialogs appear over the
- *3d window.  talbert s f
- *
- *Revision 1.7  2002/03/21 15:45:46  bobkov
- *implemented callbacks for buttons AddBubble and RemoveBubble, implemented callbacks for Radius slider and ActiveBubble browser, created methods getBubbles and getNumberOfBubbles   e
- *
- *Revision 1.6  2002/03/19 19:35:32  moon
- *added snakewrapper to makefile so it gets compiled. started putting in callback,
- *etc. for snake vcr buttons.  added snake object to IrisGlobals, instantiated in Main
- *
- *Revision 1.5  2002/03/19 17:47:10  moon
- *added some code to disable widgets, make the radio buttons work, etc. in the snake window.  fixed the quit callback from the snake window to work (crashed before)
- *changed the [accept/restart]bubble_button widgets to be acceptinitialization_button and added callbacks (empty).
- *
- *Revision 1.4  2002/03/08 14:23:48  moon
- *added comments
- *
- *Revision 1.3  2002/03/08 14:06:29  moon
- *Added Header and Log tags to all files
- **/
diff --git a/UserInterface/MeshIOWizard/MeshIOWizardUI.fl b/UserInterface/MeshIOWizard/MeshIOWizardUI.fl
deleted file mode 100644
index c1a3ddc..0000000
--- a/UserInterface/MeshIOWizard/MeshIOWizardUI.fl
+++ /dev/null
@@ -1,128 +0,0 @@
-# data file for the Fltk User Interface Designer (fluid)
-version 1.0109 
-header_name {.h} 
-code_name {.cxx}
-class MeshIOWizardUI {open : MeshIOWizardUIBase
-} {
-  Function {MakeWindow()} {open return_type {virtual void}
-  } {
-    Fl_Window m_WinWizard {
-      label {3D Mesh Export Wizard} open
-      xywh {627 170 470 330} type Double
-      code0 {\#include "MeshIOWizardUIBase.h"} visible
-    } {
-      Fl_Wizard m_GrpWizard {open
-        xywh {0 0 475 330} box PLASTIC_DOWN_BOX
-      } {
-        Fl_Group m_PageMesh {
-          label {Mesh Selection} open
-          xywh {0 20 470 310} labelsize 12
-        } {
-          Fl_Group {} {open selected
-            xywh {25 65 415 195} labeltype ENGRAVED_LABEL align 21
-          } {
-            Fl_Round_Button m_BtnMeshPageSingleExport {
-              label {Export 3D mesh for a single selected label:}
-              callback {this->OnMeshPageRadioChange();}
-              xywh {50 85 310 20} type Radio down_box ROUND_DOWN_BOX value 1 labelsize 12
-            }
-            Fl_Round_Button m_BtnMeshPageMultiExport {
-              label {Export meshes for all the labels in the segmentation:}
-              callback {this->OnMeshPageRadioChange();}
-              xywh {50 165 310 20} type Radio down_box ROUND_DOWN_BOX labelsize 12
-            }
-            Fl_Choice m_InMeshPageSelectedLabel {
-              label {Label to export:} open
-              xywh {160 115 185 20} down_box BORDER_BOX labelsize 12 textsize 12
-            } {}
-            Fl_Group {} {open
-              xywh {60 185 340 50}
-            } {
-              Fl_Round_Button m_BtnMeshPageIndexedExport {
-                label {As individual mesh files (indexed by 001, 002, etc)}
-                callback {this->OnMeshPageRadioChange();}
-                xywh {70 190 310 20} type Radio down_box ROUND_DOWN_BOX labelsize 12 deactivate
-              }
-              Fl_Round_Button m_BtnMeshPageSceneExport {
-                label {As a single 3D scene (not supported by all file formats)}
-                callback {this->OnMeshPageRadioChange();}
-                xywh {70 210 310 20} type Radio down_box ROUND_DOWN_BOX value 1 labelsize 12 deactivate
-              }
-            }
-          }
-          Fl_Button m_BtnMeshPageNext {
-            label {&Next  >}
-            callback {this->OnMeshPageNext();}
-            xywh {290 295 80 25} box PLASTIC_UP_BOX shortcut 0x8006e color 180 labelfont 1 labelsize 12
-          }
-          Fl_Button {} {
-            label {< Back}
-            xywh {200 295 80 25} box PLASTIC_UP_BOX color 180 labelsize 12 deactivate
-          }
-          Fl_Button {} {
-            label Cancel
-            callback {this->OnCancel();}
-            xywh {380 295 80 25} box PLASTIC_UP_BOX shortcut 0xff1b color 180 labelsize 12
-          }
-          Fl_Group {} {
-            label {Select which segmentation labels to export:}
-            xywh {10 30 370 40} labeltype EMBOSSED_LABEL align 20
-          } {}
-        }
-        Fl_Group m_PageFile {
-          label {File Selection} open
-          xywh {0 20 470 310} labelsize 12 hide
-        } {
-          Fl_Group {} {
-            label {Choose a filename to save the 3D mesh:}
-            xywh {10 30 370 40} labeltype EMBOSSED_LABEL align 20
-          } {}
-          Fl_Input m_InFilePageBrowser {
-            label {Filename:}
-            callback {this->OnFilePageFileInputChange();}
-            tooltip {Enter the filename of the image you want to save, or select one using the 'Browse' and 'History' buttons} xywh {30 110 405 25} labelsize 12 align 5 when 1 textsize 12
-          }
-          Fl_Button {} {
-            label {&Browse...}
-            callback {this->OnFilePageBrowse();}
-            xywh {265 140 80 25} box PLASTIC_UP_BOX shortcut 0x80062 labelsize 12
-          }
-          Fl_Menu_Button m_InFilePageHistory {
-            label History
-            callback {this->OnFilePageFileHistoryChange();} open
-            xywh {355 140 80 25} box PLASTIC_UP_BOX selection_color 181 labelsize 12 align 20 textsize 12
-          } {}
-          Fl_Choice m_InFilePageFormat {
-            label {Mesh file format:}
-            callback {this->OnFilePageFileFormatChange();} open
-            tooltip {Use this dropdown box to select an image format if one is not selected for you automatically. Normally, SNAP will figure out the file format once you select an image file using the 'Browse' button.} xywh {30 200 210 25} down_box BORDER_BOX labelsize 12 align 5 textsize 12
-          } {
-            MenuItem {} {
-              label {Select a format...}
-              xywh {30 30 100 20} labelsize 12 hide
-            }
-          }
-          Fl_Button m_BtnFilePageNext {
-            label {&Save}
-            callback {this->OnFilePageNext();}
-            xywh {290 295 80 25} box PLASTIC_UP_BOX shortcut 0x8006e color 180 labelfont 1 labelsize 12 deactivate
-          }
-          Fl_Button m_BtnFilePageBack {
-            label {< Back}
-            callback {this->OnFilePageBack()}
-            xywh {200 295 80 25} box PLASTIC_UP_BOX color 180 labelsize 12
-          }
-          Fl_Button {} {
-            label Cancel
-            callback {this->OnCancel();}
-            xywh {380 295 80 25} box PLASTIC_UP_BOX shortcut 0xff1b color 180 labelsize 12
-          }
-        }
-        Fl_Group m_PageOptions {
-          label Options open
-          xywh {0 20 470 310} labelsize 12 hide
-        } {}
-      }
-    }
-  }
-} 
diff --git a/UserInterface/MeshIOWizard/MeshIOWizardUIBase.h b/UserInterface/MeshIOWizard/MeshIOWizardUIBase.h
deleted file mode 100644
index 6af0e97..0000000
--- a/UserInterface/MeshIOWizard/MeshIOWizardUIBase.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: MeshIOWizardUIBase.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:27 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __MeshIOWizardUIBase_h_
-#define __MeshIOWizardUIBase_h_
-
-/**
- * \class MeshIOWizardUIBase
- * The base class for the Mesh Export Wizard UI.
- */
-class MeshIOWizardUIBase {
-public:
-  // Dummy constructor and destructor
-  MeshIOWizardUIBase() {};
-  virtual ~MeshIOWizardUIBase() {};
-
-  virtual void OnCancel() = 0;
-  virtual void OnFilePageBrowse() = 0;
-  virtual void OnFilePageNext() = 0;
-  virtual void OnFilePageFileInputChange() = 0;
-  virtual void OnFilePageFileHistoryChange() = 0;
-  virtual void OnFilePageFileFormatChange() = 0;
-  virtual void OnFilePageBack() = 0;
-
-  virtual void OnMeshPageNext() = 0;
-  virtual void OnMeshPageRadioChange() = 0;
-};
-
-#endif // __MeshIOWizardUIBase_h_
-
diff --git a/UserInterface/MeshIOWizard/MeshIOWizardUILogic.cxx b/UserInterface/MeshIOWizard/MeshIOWizardUILogic.cxx
deleted file mode 100644
index 88cf95c..0000000
--- a/UserInterface/MeshIOWizard/MeshIOWizardUILogic.cxx
+++ /dev/null
@@ -1,426 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: MeshIOWizardUILogic.cxx,v $
-  Language:  C++
-  Date:      $Date: 2011/04/18 17:35:30 $
-  Version:   $Revision: 1.10 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "MeshIOWizardUILogic.h"
-#include "IRISApplication.h"
-#include "GuidedMeshIO.h"
-#include "FL/Fl_Native_File_Chooser.H"
-#include "FL/filename.H"
-#include "FL/fl_ask.H"
-
-using namespace std;
-
-MeshIOWizardUILogic
-::MeshIOWizardUILogic()
-{
-  m_MeshSelected = false;
-  m_Driver = NULL;
-
-  // Initialize the file format database
-  m_FileFormatPattern[GuidedMeshIO::FORMAT_VTK] = "vtk";
-  m_FileFormatPattern[GuidedMeshIO::FORMAT_STL] = "stl";
-  m_FileFormatPattern[GuidedMeshIO::FORMAT_BYU] = "byu,y";
-
-  m_FileFormatDescription[GuidedMeshIO::FORMAT_VTK] = "VTK PolyData File";
-  m_FileFormatDescription[GuidedMeshIO::FORMAT_STL] = "STL Mesh File";
-  m_FileFormatDescription[GuidedMeshIO::FORMAT_BYU] = "BYU Mesh File";
-
-}
-
-string
-MeshIOWizardUILogic
-::GetFilePattern() 
-{
-  // String containing the whole patterns
-  StringType pattern = "";
-  bool patternNeedsNewline = false;
-
-  // String containing the "All Image Files" pattern
-  StringType allImageFiles = "All Mesh Files\t*.{"; 
-  bool allImageFilesNeedsComma = false;
-
-  // Go through all supported formats
-  for(size_t i = 0; i < GuidedMeshIO::FORMAT_COUNT; i++)
-    {
-    // Add comma to allImageFiles
-    if(allImageFilesNeedsComma)
-      allImageFiles += ",";
-    else
-      allImageFilesNeedsComma = true;
-
-    // Add extension to all image files
-    allImageFiles += m_FileFormatPattern[i];
-
-    // Add a tab to the pattern
-    if(patternNeedsNewline)
-      pattern += "\n";
-    else
-      patternNeedsNewline = true;
-
-    // Construct the pattern
-    pattern += m_FileFormatDescription[i];
-    pattern += " Files\t*.{";
-    pattern += m_FileFormatPattern[i];
-    pattern += "}";
-    }
-
-  // Finish the all image pattern
-  allImageFiles += "}\n";
-
-  // Compete the pattern
-  pattern = allImageFiles + pattern;
-  return pattern;
-}
-
-void 
-MeshIOWizardUILogic::
-OnCancel()
-{
-  m_MeshSelected = false;
-  m_WinWizard->hide();  
-}
-
-void 
-MeshIOWizardUILogic
-::OnFilePageBrowse()
-{
-  // Get the pattern for selecting the file
-  string pattern = GetFilePattern();
-
-  // Get the current pathname
-  const char *path = m_InFilePageBrowser->value();
-  path = strlen(path) ? path : NULL;
-
-  // Configure a file dialog
-  const char *fName = NULL;
-  Fl_Native_File_Chooser chooser;
-  chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
-  chooser.title("Select a mesh file");
-  chooser.options(Fl_Native_File_Chooser::NEW_FOLDER);
-  chooser.preset_file(path);
-  chooser.filter(pattern.c_str());
-  if(chooser.show() == 0)
-    fName = chooser.filename(); 
-
-  // Bring up th choice dialog
-  if (fName && strlen(fName) > 0)
-    {
-    // Set the new filename
-    m_InFilePageBrowser->value(fName);
-
-    // Reset the format drop-down box to a null value
-    m_InFilePageFormat->value(0);
-
-    // Call the filename-changed callback
-    OnFilePageFileInputChange();
-    }
-}
-
-void 
-MeshIOWizardUILogic
-::OnFilePageFileInputChange()
-{
-  // Clear the registry
-  m_Registry.Clear();
-
-  // Deactivate the next page
-  m_BtnFilePageNext->deactivate();
-
-  // Check the length of the input
-  const char *text = m_InFilePageBrowser->value();
-  if (text != NULL && strlen(text) > 0)
-    {
-    // Try to load the registry associated with this filename
-    m_Driver->GetSystemInterface()->FindRegistryAssociatedWithFile(
-      m_InFilePageBrowser->value(), m_Registry);
-
-    // If the registry contains a file format, override with that
-    GuidedMeshIO::FileFormat fmt = 
-      m_GuidedIO.GetFileFormat(m_Registry, GuidedMeshIO::FORMAT_COUNT);
-
-    // Try to select a file format accoring to the file name
-    if(fmt == GuidedMeshIO::FORMAT_COUNT)
-      fmt = DetermineFileFormatFromFileName(text);
-
-    // If the filename does not match any format, we do not change the 
-    // format choice box in case that the user has already set it manually
-    if(fmt < GuidedMeshIO::FORMAT_COUNT)
-      {
-      m_InFilePageFormat->value((int)fmt+1);
-      m_BtnFilePageNext->activate();
-      }
-    else
-      {
-      m_InFilePageFormat->value(0);
-      }
-    } 
-}
-
-GuidedMeshIO::FileFormat
-MeshIOWizardUILogic
-::DetermineFileFormatFromFileName(const char *testFile) 
-{
-  // Iterate over the known file types
-  for(size_t i = 0;i < GuidedMeshIO::FORMAT_COUNT;i++)
-    {
-    // Create a matching pattern
-    StringType pattern = "*.{" + m_FileFormatPattern[i] + "}";
-
-    // Check if the filename matches the pattern
-    if(fl_filename_match(testFile, pattern.c_str()))
-      return (GuidedMeshIO::FileFormat) i;
-    }
-
-  // Failed: return illegal pattern
-  return GuidedMeshIO::FORMAT_COUNT;
-}
-
-void 
-MeshIOWizardUILogic
-::SetHistory(const HistoryType &history)
-{
-  // Store the history
-  m_History = history;
-
-  // Clear the history drop box
-  m_InFilePageHistory->clear();
-
-  // Add the history
-  if(history.size() > 0)
-    {  
-    // Add each item to the history menu (history is traversed
-    // backwards)
-    for(HistoryType::reverse_iterator it=m_History.rbegin();
-        it!=m_History.rend();it++)
-      {
-      // FLTK's add() treats slashes as submenu separators, hence this code
-      m_InFilePageHistory->replace(
-        m_InFilePageHistory->add("dummy"),it->c_str());      
-      }
-
-    // Activate the history menu    
-    m_InFilePageHistory->activate();
-    }
-  else
-    {
-    // Deactivate history
-    m_InFilePageHistory->deactivate();
-    }
-}
-
-void 
-MeshIOWizardUILogic
-::OnFilePageNext()
-{
-  // There must be a file format
-  assert(m_InFilePageFormat->value() > 0);
-
-  // There must be a selected label
-  assert((size_t) m_InMeshPageSelectedLabel->value() < m_ColorLabelMenuIndex.size());
-
-  // The mesh has been selected
-  m_MeshSelected = true;
-
-  // Set the mesh filename
-  m_ExportSettings.SetMeshFileName(m_InFilePageBrowser->value());
-
-  // Set the mesh file type
-  m_GuidedIO.SetFileFormat(m_Registry, 
-    static_cast<GuidedMeshIO::FileFormat>(m_InFilePageFormat->value() - 1));
-  m_ExportSettings.SetMeshFormat(m_Registry);
-
-  // Set the export properties
-  if(m_BtnMeshPageSingleExport->value())
-    {
-    m_ExportSettings.SetFlagSingleLabel(true);
-    m_ExportSettings.SetFlagSingleScene(false);
-    m_ExportSettings.SetExportLabel(
-      m_ColorLabelMenuIndex[m_InMeshPageSelectedLabel->value()]);
-    }
-  else if(m_BtnMeshPageMultiExport->value())
-    {
-    m_ExportSettings.SetFlagSingleLabel(false);
-    m_ExportSettings.SetExportLabel(0);
-    if(m_BtnMeshPageSceneExport->value())
-      {
-      m_ExportSettings.SetFlagSingleScene(true);
-      }
-    else
-      {
-      m_ExportSettings.SetFlagSingleScene(false);
-      }
-    }
-
-  // Hide the wizard
-  m_WinWizard->hide();
-}
-
-
-void 
-MeshIOWizardUILogic
-::OnFilePageFileHistoryChange()
-{
-  // Copy the history value to the filename
-  m_InFilePageBrowser->value(
-    m_InFilePageHistory->mvalue()->label());
-
-  // Update everything
-  OnFilePageFileInputChange();  
-}
-
-void 
-MeshIOWizardUILogic
-::OnFilePageFileFormatChange()
-{
-  // Activate the next button if there is a format selected
-  if(m_InFilePageFormat->value() > 0)
-    m_BtnFilePageNext->activate();
-  else 
-    m_BtnFilePageNext->deactivate();  
-}
-
-void 
-MeshIOWizardUILogic
-::OnFilePageBack()
-{
-  m_GrpWizard->value(m_PageMesh);
-}
-
-void 
-MeshIOWizardUILogic
-::OnMeshPageNext()
-{
-  m_GrpWizard->value(m_PageFile);
-}
-
-void 
-MeshIOWizardUILogic
-::OnMeshPageRadioChange()
-{
-  // Set the other radio buttons
-  if(m_BtnMeshPageSingleExport->value())
-    {
-    m_InMeshPageSelectedLabel->activate();
-    m_BtnMeshPageIndexedExport->deactivate();
-    m_BtnMeshPageSceneExport->deactivate();
-    }
-  else
-    {
-    m_InMeshPageSelectedLabel->deactivate();
-    m_BtnMeshPageIndexedExport->activate();
-    m_BtnMeshPageSceneExport->activate();
-    }
-}
-
-// Custom initialization code
-void 
-MeshIOWizardUILogic
-::MakeWindow()
-{
-  // Parent's method
-  MeshIOWizardUI::MakeWindow();
-
-  // Initialize the file save dialog box based on the allowed file types
-  for(size_t i = 0; i < GuidedMeshIO::FORMAT_COUNT; i++)
-    {
-    // Create an appropriate description
-    string text = m_FileFormatDescription[i];
-    
-    // Add a menu option to the save menu, disabling it if it's unsupported
-    m_InFilePageFormat->add(text.c_str(), 0, NULL, NULL, 0);    
-    }
-
-  // Set the format description to 0
-  m_InFilePageFormat->value(0);
-}
-
-// Display the wizard and get the save settings
-bool 
-MeshIOWizardUILogic
-::DisplayWizard(IRISApplication *driver, bool snapmode)
-{
-  // Set the driver
-  m_Driver = driver;
-
-  // The loaded flag is false
-  m_MeshSelected = false;
-
-  // Switch IRIS mode / SNAP mode
-  if(snapmode)
-    {
-    // Just go to the file page
-    m_GrpWizard->value(m_PageFile);
-    }
-  else
-    {
-    // Point the wizard to the first page
-    m_GrpWizard->value(m_PageMesh);
-    }
-    
-  // Get the list of all currenly available labels
-  ColorLabelTable *clt = m_Driver->GetColorLabelTable();
-
-  // Initialize the mapping from menu index to color label
-  m_ColorLabelMenuIndex.clear();
-
-  // Populate the color label list
-  m_InMeshPageSelectedLabel->clear();
-  size_t k = 0;
-  for(size_t i = 1; i < MAX_COLOR_LABELS; i++)
-    {
-    if(clt->IsColorLabelValid(i))
-      {
-      ColorLabel label = clt->GetColorLabel(i);
-      m_InMeshPageSelectedLabel->add(label.GetLabel());
-      if(i == m_Driver->GetGlobalState()->GetDrawingColorLabel())
-        m_InMeshPageSelectedLabel->value(k);
-      m_ColorLabelMenuIndex.push_back(i);
-      k++;
-      }
-    }
-
-  // Show the input window
-  m_WinWizard->show();
-
-  // Loop until the window has been closed
-  while (m_WinWizard->visible())
-    Fl::wait();
-
-  // Remove the driver
-  m_Driver = NULL;
-
-  // Whether or not the load has been succesfull
-  return m_MeshSelected;  
-}
-
diff --git a/UserInterface/MeshIOWizard/MeshIOWizardUILogic.h b/UserInterface/MeshIOWizard/MeshIOWizardUILogic.h
deleted file mode 100644
index 47697b8..0000000
--- a/UserInterface/MeshIOWizard/MeshIOWizardUILogic.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: MeshIOWizardUILogic.h,v $
-  Language:  C++
-  Date:      $Date: 2011/04/18 17:35:30 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __MeshIOWizardUILogic_h_
-#define __MeshIOWizardUILogic_h_
-
-#include "FLTKWidgetActivationManager.h"
-#include "MeshIOWizardUI.h"
-#include "MeshExportSettings.h"
-#include "GuidedMeshIO.h"
-#include <string>
-#include <vector>
-
-class IRISApplication;
-
-/**
- * \class MeshIOWizardUILogic
- * The UI logic class for the Mesh Export Wizard UI.
- */
-class MeshIOWizardUILogic : public MeshIOWizardUI {
-public:
-
-  // History typedef
-  typedef std::string StringType;
-  typedef std::vector<StringType> HistoryType;
-
-  // Dummy constructor and destructor
-  MeshIOWizardUILogic();
-  virtual ~MeshIOWizardUILogic() {};
-
-  // Callback methods extended from the UIBase class
-  void OnCancel();
-  void OnFilePageBrowse();
-  void OnFilePageNext();
-  void OnFilePageFileInputChange();
-  void OnFilePageFileHistoryChange();
-  void OnFilePageFileFormatChange();
-  void OnFilePageBack();
-  void OnMeshPageNext();
-  void OnMeshPageRadioChange();
-
-  // Custom initialization code
-  void MakeWindow();
-
-  // Display the wizard and get the save settings
-  bool DisplayWizard(IRISApplication *driver, bool snapmode);
-
-  /** Set the history list of recently opened files */
-  void SetHistory(const HistoryType &history);
-
-  // Set the history values for the wizard
-  irisGetMacro(History, HistoryType);
-
-  // Get the export settings
-  irisGetMacro(ExportSettings, MeshExportSettings);
-
-private:
-  
-  // State flag system
-  enum UIStateFlags {
-    UIF_NULL
-  };
-
-  // Activation manager
-  FLTKWidgetActivationManager<UIStateFlags> m_Activation;
-
-  // Parent-level IRIS application
-  IRISApplication *m_Driver;
-
-  // History of loaded filenames
-  HistoryType m_History;
-
-  // The settings collected by the wizard
-  MeshExportSettings m_ExportSettings;
-
-  // Whether a mesh has been loaded in the wizard
-  bool m_MeshSelected;
-
-  /** Extensions for different file formats */
-  StringType m_FileFormatPattern[GuidedMeshIO::FORMAT_COUNT];
-
-  /** Brief descriptions of different file formats */
-  StringType m_FileFormatDescription[GuidedMeshIO::FORMAT_COUNT];  
-
-  // Generate an FLTK search pattern based on selection
-  StringType GetFilePattern();
-
-  // Guess file format from a filename
-  GuidedMeshIO::FileFormat DetermineFileFormatFromFileName(const char *testFile);
-
-  // The registry associated with the mesh being saves
-  Registry m_Registry;
-
-  // A guided mesh IO object used to save meshes
-  GuidedMeshIO m_GuidedIO;
-
-  // An array used to link labels in the drop down to label indices
-  std::vector<LabelType> m_ColorLabelMenuIndex;
-};
-
-#endif // __MeshIOWizardUILogic_h_
-
diff --git a/UserInterface/SNAPMain.cxx b/UserInterface/SNAPMain.cxx
deleted file mode 100644
index 2047650..0000000
--- a/UserInterface/SNAPMain.cxx
+++ /dev/null
@@ -1,777 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SNAPMain.cxx,v $
-  Language:  C++
-  Date:      $Date: 2011/05/04 15:25:42 $
-  Version:   $Revision: 1.23 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-// Borland compiler is very lazy so we need to instantiate the template
-//  by hand 
-#if defined(__BORLANDC__)
-#include "SNAPBorlandDummyTypes.h"
-#endif
-
-#include "FL/Fl.H"
-#include "FL/Fl_Native_File_Chooser.H"
-#include <FL/Fl_File_Chooser.H>
-
-#include "CommandLineArgumentParser.h"
-#include "ImageCoordinateGeometry.h"
-#include "ImageIORoutines.h"
-#include "IRISApplication.h"
-#include "IRISException.h"
-#include "IRISImageData.h"
-#include "SNAPRegistryIO.h"
-#include "SystemInterface.h"
-#include "UserInterfaceLogic.h"
-
-#include "itkOrientedImage.h"
-#include "itkImageFileReader.h"
-#include "itkNumericTraits.h"
-
-
-#include <itksys/SystemTools.hxx>
-
-//#include <limits>
-
-using namespace std;
-
-// Define the verbose output stream
-ostream &verbose = cout;
-
-// MAX grey value - TODO find somewhere to stick this
-const GreyType MAXGREYVAL = itk::NumericTraits<GreyType>::max();
-const GreyType MINGREYVAL = itk::NumericTraits<GreyType>::min();
-
-#include "Registry.h"
-
-// A templated load image method
-template<class TPixel>
-bool LoadImageFromFileInteractive(
-  const char *file, typename itk::SmartPointer< itk::OrientedImage<TPixel,3> > &target)
-{
-  try
-    {
-    LoadImageFromFile(file,target);
-    return true;
-    }
-  catch(itk::ExceptionObject &exc)
-    {
-    cerr << "Error loading file '" << file << "'" << endl;
-    cerr << "Reason: " << exc << endl;
-    return false;
-    }
-}
-
-/** Make sure we have a path to the SNAP root directory 
- * so that we can read external files */
-bool FindDataDirectoryInteractive(const char *sExePath, SystemInterface &system)
-{
-  // Try to find the root directory
-  while(!system.FindDataDirectory(sExePath))
-    {
-    // Tell the user the directory is missing
-    int choice = 
-      fl_choice("The SNAP root directory could not be found!\n"
-                "Please click 'Search' to find this directory\n"
-                "or click 'Exit' to terminate the program.",
-                "Exit Program","Browse...","More Info...");
-
-    if(choice == 0)
-      {
-      // Exit the application
-      return false;
-      }      
-    else if(choice == 2)
-      {
-      // More help
-      fl_message("  SNAP could not find its help files and other data that it needs\n"
-                 "to run properly.  These files should be located in a subdirectory \n"
-                 "called ProgramData in the same directory where the SNAP executable \n"
-                 "is located.  \n"
-                 "  If you are not sure where to look, search your computer's hard drive \n"
-                 "for a file called '%s', and then use the Browse... button to tell SNAP \n"
-                 "where this file is located.\n"
-                 "  For more help, consult your system administrator.",
-                 system.GetProgramDataDirectoryTokenFileName());
-      }
-    else
-      {
-      // The file we're looking for
-      string sMissingFile = system.GetProgramDataDirectoryTokenFileName();
-      string sTitle = "Find a directory that contains file " + sMissingFile;
-
-      // Look for the file using a file chooser
-      Fl_Native_File_Chooser fc;
-      fc.type(Fl_Native_File_Chooser::BROWSE_FILE);
-      fc.title(sTitle.c_str());
-      fc.filter("Directory Token File\t*.txt");
-      fc.preset_file(sMissingFile.c_str());
-          
-      // Show the file chooser
-      const char *fName = NULL;
-      if (fc.show())
-        {
-        fName = fc.filename();
-        }
-      
-      // If user hit cancel, continue
-      if(!fName || !strlen(fName)) continue;
-
-      // Make sure that the filename matches and get the path
-      string sBrowseName = itksys::SystemTools::GetFilenameName(fName);
-             
-      // If not, check if they've selected a valid directory
-      if(sBrowseName != sMissingFile)
-        {
-        // Wrong directory specified!
-        fl_alert("The directory must contain file '%s'!",sMissingFile.c_str());
-        continue;
-        }
-
-      // Make sure that the filename matches and get the path
-      string sBrowsePath = itksys::SystemTools::GetFilenamePath(fName);
-
-      // Set the path
-      system["System.ProgramDataDirectory"] << sBrowsePath;
-      }
-    }
-  return true;
-}
-
-bool LoadUserPreferencesInteractive(SystemInterface &system) 
-{
-  try
-    {
-    system.LoadUserPreferences();
-    }
-  catch(std::string &exc)
-    {
-    if(0 == fl_choice("Error reading preferences file %s\n%s",
-                      "Exit Program","Continue",NULL,
-                      system.GetUserPreferencesFileName(),exc.c_str()))
-      {
-      return false;
-      }   
-    }
-
-  return true;
-}
-
-// Setup printing of stack trace on segmentation faults. This only
-// works on select GNU systems
-#if defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(sun) && !defined(WIN32)
-
-#include <signal.h>
-#include <execinfo.h>
-
-void SegmentationFaultHandler(int sig)
-{
-  cerr << "*************************************" << endl;
-  cerr << "ITK-SNAP: Segmentation Fault!   " << endl;
-  cerr << "BACKTRACE: " << endl;
-  void *array[50];
-  int nsize = backtrace(array, 50);
-  backtrace_symbols_fd(array, nsize, 2);
-  cerr << "*************************************" << endl;
-  exit(-1);
-}
-
-void SetupSignalHandlers()
-{
-  signal(SIGSEGV, SegmentationFaultHandler);
-}
-
-#else
-
-void SetupSignalHandlers()
-{
-  // Nothing to do!
-}
-
-#endif
-
-
-void usage()
-{
-  // Print usage info and exit
-  cout << "ITK-SnAP Command Line Usage:" << endl;
-  cout << "   snap [options] [main_image]" << endl;
-  
-  cout << "Options:" << endl;
-
-  cout << "   --main, -m FILE              : " <<
-    "Load main image FILE; automatically determine grey or RGB" << endl;
-  
-  cout << "   --grey, -g FILE              : " <<
-    "Load main image FILE as greyscale" << endl;
-  
-  cout << "   --rgb FILE                   : " <<
-    "Load main image FILE as RGB image" << endl;
-
-  cout << "   --segmentation, -s FILE      : " <<
-    "Load segmentation image FILE" << endl;
-  
-  cout << "   --labels, -l FILE            : " <<
-    "Load label description file FILE" << endl;
-
-  cout << "   --overlay, -o FILE           : " <<
-    "Load overlay image FILE; automatically determine grey or RGB" << endl;
-  
-  cout << "   --compact <a|c|s>            : " <<
-    "Launch in compact single-slice mode (axial, coronal, sagittal)" << endl;
-
-  cout << "   --zoom, -z FACTOR            : " <<
-    "Specify initial zoom in screen pixels / physical mm" << endl;
-}
-    
-
-// creates global pointers
-// sets up the GUI and lets things run
-int main(int argc, char **argv) 
-{
-  // Handle signals gracefully, with trace-back
-  SetupSignalHandlers();
-
-  // Turn off ITK warning windows
-  itk::Object::GlobalWarningDisplayOff();
-
-  // Parse command line parameters
-  CommandLineArgumentParser parser;
-  parser.AddOption("--grey",1);
-  parser.AddSynonim("--grey","-g");
-
-  parser.AddOption("--main",1);
-  parser.AddSynonim("--main","-m");
-
-  parser.AddOption("--rgb", 1);
-
-  parser.AddOption("--segmentation",1);
-  parser.AddSynonim("--segmentation","-s");
-  parser.AddSynonim("--segmentation","-seg");
-  
-  parser.AddOption("--overlay", 1);
-  parser.AddSynonim("--overlay", "-o");
-
-  parser.AddOption("--labels",1);
-  parser.AddSynonim("--labels","--label");
-  parser.AddSynonim("--labels","-l");
-
-  parser.AddOption("--zoom", 1);
-  parser.AddSynonim("--zoom", "-z");
-
-  parser.AddOption("--compact", 1);
-  parser.AddSynonim("--compact", "-c");
-
-  parser.AddOption("--help", 0);
-  parser.AddSynonim("--help", "-h");
-
-
-  CommandLineArgumentParseResult parseResult;
-  int iTrailing = 0;
-  if(!parser.TryParseCommandLine(argc,argv,parseResult,false,iTrailing))
-    {
-    cerr << "Unable to parse command line. Run " << argv[0] << " -h for help" << endl;
-    return -1;
-    }
-
-  if(parseResult.IsOptionPresent("--help"))
-    {
-    usage();
-    return 0;
-    }
-
-  // Create a new IRIS application
-  IRISApplication *iris = new IRISApplication;
-
-  // Initialize the operating system interface
-  SystemInterface &system = *iris->GetSystemInterface();  
-
-  // Load the user preferences into the system
-  if(!LoadUserPreferencesInteractive(system))
-    return -1;
-
-  // Work with the user to try to find the root directory
-  if(!FindDataDirectoryInteractive(argv[0],system))
-    return -1;
-
-  // Create a UI object
-  UserInterfaceLogic *ui = new UserInterfaceLogic(iris);
-
-  // Initialize FLTK
-  Fl::visual(FL_DOUBLE|FL_INDEX);
-  Fl::gl_visual(FL_RGB);  
-  Fl::background(236,233,216);
-
-  // Show the IRIS Interface
-  ui->Launch();
-
-  // Show the splash screen
-  ui->ShowSplashScreen();
-
-  // The following situations are possible for main image
-  // itksnap file                       <- load as main image, detect file type
-  // itksnap --main file                <- load as main image, detect file type
-  // itksnap --gray file                <- load as main image, force gray
-  // itksnap --rgb file                 <- load as main image, force RGB
-  // itksnap --gray file1 --rgb file2   <- error
-  // itksnap --gray file1 file2         <- ignore file2
-  // itksnap --rgb file1 file2          <- ignore file2
-
-  // Check validity of options for main image
-  if(parseResult.IsOptionPresent("--grey") && parseResult.IsOptionPresent("--rgb"))
-    {
-    cerr << "Error: options --rgb and --grey are mutually exclusive." << endl;
-    return -1;
-    }
-
-  if(parseResult.IsOptionPresent("--main") && parseResult.IsOptionPresent("--rgb"))
-    {
-    cerr << "Error: options --main and --rgb are mutually exclusive." << endl;
-    return -1;
-    }
-
-  if(parseResult.IsOptionPresent("--main") && parseResult.IsOptionPresent("--grey"))
-    {
-    cerr << "Error: options --main and --grey are mutually exclusive." << endl;
-    return -1;
-    }
-
-  // Check if a main image file is specified 
-  bool force_grey = false, force_rgb = false;
-  const char *fnMain = NULL;
-  if(parseResult.IsOptionPresent("--main"))
-    {
-    fnMain = parseResult.GetOptionParameter("--main");
-    }
-  else if(parseResult.IsOptionPresent("--grey"))
-    {
-    fnMain = parseResult.GetOptionParameter("--grey");
-    force_grey = true;
-    }
-  else if(parseResult.IsOptionPresent("--rgb")) 
-    {
-    fnMain = parseResult.GetOptionParameter("--rgb");
-    force_rgb = true;
-    }
-  else if(iTrailing < argc)
-    {
-    fnMain = argv[iTrailing];
-    }
-
-
-  // If no main, there should be no overlays, segmentation
-  if(!fnMain && parseResult.IsOptionPresent("--segmentation"))
-    {
-    cerr << "Error: --segmentation can not be used without --main, --grey, or --rgb" << endl;
-    return -1;
-    }
-  
-  if(!fnMain && parseResult.IsOptionPresent("--overlay"))
-    {
-    cerr << "Error: --overlay can not be used without --main, --grey, or --rgb" << endl;
-    return -1;
-    }
-
-  // Load main image file
-  if(fnMain)
-    {
-    // Update the splash screen
-    ui->UpdateSplashScreen("Loading image...");
-
-    // Try loading the image
-    try 
-      {
-      ui->NonInteractiveLoadMainImage(fnMain, force_grey, force_rgb);
-      }  
-    catch(itk::ExceptionObject &exc)
-      {
-      cerr << "Error loading file '" << fnMain << "'" << endl;
-      cerr << "Reason: " << exc << endl;
-      return -1;
-      }
-    }
-
-  // If one main image loaded, load segmentation
-  if(fnMain)
-    {
-    // Load the segmentation if supplied
-    if(parseResult.IsOptionPresent("--segmentation"))
-      {
-      // Get the filename 
-      const char *fname = parseResult.GetOptionParameter("--segmentation");
-
-      // Update the splash screen
-      ui->UpdateSplashScreen("Loading segmentation image...");
-
-      // Try to load the image
-      try
-        {
-        ui->NonInteractiveLoadSegmentation(fname);
-        }
-      catch(itk::ExceptionObject &exc)
-        {
-        cerr << "Error loading file '" << fname << "'" << endl;
-        cerr << "Reason: " << exc << endl;
-        return -1;
-        }
-      }    
-
-    // Load overlay is supplied
-    if(parseResult.IsOptionPresent("--overlay"))
-      {
-      // Get the filename
-      const char *fname = parseResult.GetOptionParameter("--overlay");
-
-      // Update the splash screen
-      ui->UpdateSplashScreen("Loading overlay image...");
-
-      // Try to load the image
-      try
-        {
-        ui->NonInteractiveLoadOverlayImage(fname, false, false);
-        }
-      catch(itk::ExceptionObject &exc)
-        {
-        cerr << "Error loading file '" << fname << "'" << endl;
-        cerr << "Reason: " << exc << endl;
-        return -1;
-        }
-      }
-    }
-
-  // Load labels if supplied
-  if(parseResult.IsOptionPresent("--labels"))
-    {
-    // Get the filename 
-    const char *fname = parseResult.GetOptionParameter("--labels");
-    
-    // Update the splash screen
-    ui->UpdateSplashScreen("Loading label descriptions...");
-
-    try 
-      {
-      // Load the label file
-      ui->NonInteractiveLoadLabels(fname);
-      }
-    catch(itk::ExceptionObject &exc)
-      {
-      cerr << "Error reading label descriptions: " << 
-        exc.GetDescription() << endl;
-      }
-    }
-
-  // Set initial zoom if specified
-  if(parseResult.IsOptionPresent("--zoom"))
-    {
-    double zoom = atof(parseResult.GetOptionParameter("--zoom"));
-    cout << "Using ZOOM " << zoom << endl;
-    if(zoom >= 0.0)
-      {
-      ui->SetZoomLevelAllWindows(zoom);
-      }
-    else
-      {
-      cerr << "Invalid zoom level (" << zoom << ") specified" << endl;
-      }
-    }
-
-  if(parseResult.IsOptionPresent("--compact"))
-    {
-    string slice = parseResult.GetOptionParameter("--compact");
-    if(slice.length() == 0 || !(slice[0] == 'a' || slice[0] == 'c' || slice[0] == 's'))
-      cerr << "Wrong parameter passed for '--compact', ignoring" << endl;
-    else
-      {
-      DisplayLayout dl = ui->GetDisplayLayout();
-      dl.show_main_ui = false;
-      ui->SetDisplayLayout(dl);
-      dl.show_panel_ui = false;
-      ui->SetDisplayLayout(dl);
-      dl.size = HALF_SIZE;
-      ui->SetDisplayLayout(dl);
-      dl.slice_config = slice[0] == 'a' ? AXIAL : (slice[0] == 'c' ? CORONAL : SAGITTAL);
-      ui->SetDisplayLayout(dl);
-      }
-    }
-
-  // Show the welcome message
-  ui->UpdateSplashScreen("Welcome to SnAP!");
-    
-  // Show the splash screen
-  ui->HideSplashScreen();
-
-  // Run the UI
-  try
-    {
-    Fl::run();
-    }
-  catch(std::exception &exc)
-    {
-    int salvage = fl_choice(
-      "A run-time exception has occurred. ITK-SNAP must terminate.\n\n"
-      "The text of the exception follows:\n%s\n\n"
-      "ITK-SNAP can try to save your segmentation image before exiting.\n"
-      "Do you wish to do so?", 
-      "No, quit without saving!", "Yes, try saving segmentation!", NULL,
-      exc.what());
-    if(salvage)
-      {
-      char *fnsave = fl_file_chooser(
-        "Select a filename to save segmentation", 
-        "*.nii", "recovered_segmentation.nii");
-      if(fnsave)
-        {
-        try 
-          {
-          typedef itk::ImageFileWriter<LabelImageWrapper::ImageType> WriterType;
-          WriterType::Pointer writer = WriterType::New();
-          writer->SetInput(
-            ui->GetDriver()->GetIRISImageData()->GetSegmentation()->GetImage());
-          writer->SetFileName(fnsave);
-          writer->Update();
-          }
-        catch(...)
-          {
-          fl_alert("Failed to save segmentation image. Unfortunately, your work was lost.");
-          }
-        }
-      }
-    }
-
-  // Write the user's preferences to disk
-  try 
-    {
-    system.SaveUserPreferences();
-    }
-  catch(std::string &exc)
-    {
-    fl_alert("Failed to write preferences to file %s\n%s",
-             system.GetUserPreferencesFileName(),exc.c_str());
-    }
-  
-  // Delete the UI object
-  delete ui;
-
-  // Terminate the application
-  delete iris;
-  
-  return 0;
-}
-
-/*
- *$Log: SNAPMain.cxx,v $
- *Revision 1.23  2011/05/04 15:25:42  pyushkevich
- *Fixes to build with fltk 1.3.0rc3
- *
- *Revision 1.22  2010/04/16 04:02:35  pyushkevich
- *ENH: implemented drag and drop, OSX events, new command-line interface
- *
- *Revision 1.21  2010/03/23 21:23:07  pyushkevich
- *Added display halving capability,
- *command line switches --zoom, --help, --compact
- *
- *Revision 1.20  2009/10/28 08:05:36  pyushkevich
- *FIX: Multisession pan causing continuous screen updates
- *
- *Revision 1.19  2009/10/26 20:19:12  pyushkevich
- *ENH: added top-level exception handler with option to save work
- *
- *Revision 1.18  2009/10/17 20:39:50  pyushkevich
- *ENH: added tip of the day
- *
- *Revision 1.17  2009/07/23 15:50:58  pyushkevich
- *Got the template-removal changes to compile on Linux
- *
- *Revision 1.16  2009/07/22 21:06:24  pyushkevich
- *Changed the IO system and wizards, removed templating
- *
- *Revision 1.15  2009/07/14 20:41:56  pyushkevich
- *Making Linux compilation work
- *
- *Revision 1.14  2009/06/09 05:50:04  garyhuizhang
- *ENH: main image & grey overlay support
- *
- *Revision 1.13  2009/05/25 17:09:44  garyhuizhang
- *ENH: switch from Fl_File_Chooser to Fl_Native_File_Chooser which requires the fltk to be patched with Fl_Native_File_Chooser add-on.
- *
- *Revision 1.12  2009/02/05 14:58:30  pyushkevich
- *FIX: save slice layout appearance settings to registry; ENH: added linear interpolation option for grey images
- *
- *Revision 1.11  2009/01/23 20:09:38  pyushkevich
- *FIX: 3D rendering now takes place in Nifti(RAS) world coordinates, rather than the VTK (x spacing + origin) coordinates. As part of this, itk::OrientedImage is now used for 3D images in SNAP. Still have to fix cut plane code in Window3D
- *
- *Revision 1.10  2008/11/15 12:20:38  pyushkevich
- *Several new features added for release 1.8, including (1) support for reading floating point and mapping to short range; (2) use of image direction cosines to determine image orientation; (3) new reorient image dialog and changes to the IO wizard; (4) display of NIFTI world coordinates and yoking based on them; (5) multi-session zoom; (6) fixes to the way we keep track of unsaved changes to segmentation, including a new discard dialog; (7) more streamlined code for offline loading; (8) [...]
- *
- *Revision 1.9  2008/11/01 11:32:00  pyushkevich
- *Compatibility with ITK 3.8 support for reading oriented images
- *Command line loading of RGB images
- *Improved load-image commands in UserInterfaceLogic
- *
- *Revision 1.8  2007/12/30 04:43:03  pyushkevich
- *License/Packaging updates
- *
- *Revision 1.7  2007/12/26 12:26:52  pyushkevich
- *Removed the OpenGL extension thing
- *
- *Revision 1.6  2007/12/06 20:43:37  pyushkevich
- *More gentle parsing of command line arguments
- *
- *Revision 1.5  2007/09/17 20:33:09  pyushkevich
- *VTK5 compatibility
- *
- *Revision 1.4  2007/09/17 16:10:31  pyushkevich
- *Updated to VTK 5
- *
- *Revision 1.3  2007/09/17 14:22:06  pyushkevich
- *fixed slicing bug
- *
- *Revision 1.2  2007/05/11 13:06:50  pyushkevich
- *Sun compatibility fix
- *
- *Revision 1.1  2006/12/02 04:22:26  pyushkevich
- *Initial sf checkin
- *
- *Revision 1.1.1.1  2006/09/26 23:56:17  pauly2
- *Import
- *
- *Revision 1.16  2006/02/01 20:21:26  pauly
- *ENH: An improvement to the main SNAP UI structure: one set of GL windows is used to support SNAP and IRIS modes
- *
- *Revision 1.15  2005/11/07 15:50:33  pauly
- *COMP: Fixed problem with execinfo.h missing on some platforms. Also fixed
- *compilation error in GuidedImageIO.h
- *
- *Revision 1.14  2005/11/03 18:45:29  pauly
- *ENH: Enabled SNAP to read DICOM Series
- *
- *Revision 1.13  2005/10/29 14:00:14  pauly
- *ENH: SNAP enhacements like color maps and progress bar for 3D rendering
- *
- *Revision 1.12  2005/04/21 14:46:30  pauly
- *ENH: Improved management and editing of color labels in SNAP
- *
- *Revision 1.11  2005/02/04 17:01:09  lorensen
- *COMP: last of gcc 2.96 changes (I hope).
- *
- *Revision 1.10  2004/08/26 19:43:27  pauly
- *ENH: Moved the Borland code into Common folder
- *
- *Revision 1.9  2004/08/03 23:26:32  ibanez
- *ENH: Modification for building in multple platforms. By Julien Jomier.
- *
- *Revision 1.8  2004/07/09 23:07:38  pauly
- *ENH: Added a zoom-locator frame inside of the slice display window.
- *
- *Revision 1.7  2003/12/16 13:19:26  pauly
- *FIX: Removed Fl::lock()
- *
- *Revision 1.6  2003/11/25 23:32:48  pauly
- *FIX: Snake evolution did not work in multiprocessor mode
- *
- *Revision 1.5  2003/10/06 12:30:01  pauly
- *ENH: Added history lists, remembering of settings, new snake parameter preview
- *
- *Revision 1.4  2003/10/02 14:55:52  pauly
- *ENH: Development during the September code freeze
- *
- *Revision 1.3  2003/09/15 19:06:58  pauly
- *FIX: Trying to get last changes to compile
- *
- *Revision 1.2  2003/09/13 15:18:01  pauly
- *FIX: Got SNAP to work properly with different image orientations
- *
- *Revision 1.1  2003/09/11 13:51:01  pauly
- *FIX: Enabled loading of images with different orientations
- *ENH: Implemented image save and load operations
- *
- *Revision 1.3  2003/08/27 14:03:23  pauly
- *FIX: Made sure that -Wall option in gcc generates 0 warnings.
- *FIX: Removed 'comment within comment' problem in the cvs log.
- *
- *Revision 1.2  2003/08/27 04:57:47  pauly
- *FIX: A large number of bugs has been fixed for 1.4 release
- *
- *Revision 1.1  2003/07/12 04:46:50  pauly
- *Initial checkin of the SNAP application into the InsightApplications tree.
- *
- *Revision 1.1  2003/07/11 23:33:57  pauly
- **** empty log message ***
- *
- *Revision 1.8  2003/07/11 21:41:38  pauly
- *Preparation for ITK checkin
- *
- *Revision 1.7  2003/07/01 16:53:59  pauly
- **** empty log message ***
- *
- *Revision 1.6  2003/06/23 23:59:32  pauly
- *Command line argument parsing
- *
- *Revision 1.5  2003/06/14 22:42:06  pauly
- *Several changes.  Started working on implementing the level set function
- *in ITK.
- *
- *Revision 1.4  2003/05/05 12:30:18  pauly
- **** empty log message ***
- *
- *Revision 1.3  2003/04/18 17:32:18  pauly
- **** empty log message ***
- *
- *Revision 1.2  2003/04/16 05:04:17  pauly
- *Incorporated intensity modification into the snap pipeline
- *New IRISApplication
- *Random goodies
- *
- *Revision 1.1  2003/03/07 19:29:47  pauly
- *Initial checkin
- *
- *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
- *Started the project repository
- *
- *
- *Revision 1.8  2002/04/01 22:27:57  moon
- *Took out global snake3D.  It's now part of SnakeVoxDataClass
- *
- *Revision 1.7  2002/03/26 19:20:13  moon
- *Changed full_data back to VoxDataClass, from SnakeVoxDataClass.  roi_data
- *is a SnakeVoxDataClass now.
- *
- *Revision 1.6  2002/03/23 02:16:37  scheuerm
- *Added subclass of VoxData called SnakeVoxData which includes
- *a preprocessed image. Doesn't do much yet but it's a start.
- *
- *Revision 1.5  2002/03/19 19:35:06  moon
- *added snakewrapper to makefile so it gets compiled. started putting in callback,
- *etc. for snake vcr buttons.  added snake object to IrisGlobals, instantiated in Main
- *
- *Revision 1.4  2002/03/08 13:54:47  moon
- *trying to add log tags
- **/
diff --git a/UserInterface/SliceWindow/AnnotationInteractionMode.cxx b/UserInterface/SliceWindow/AnnotationInteractionMode.cxx
deleted file mode 100644
index 18e8533..0000000
--- a/UserInterface/SliceWindow/AnnotationInteractionMode.cxx
+++ /dev/null
@@ -1,240 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: AnnotationInteractionMode.cxx,v $
-  Language:  C++
-  Date:      $Date: 2009/02/12 00:13:06 $
-  Version:   $Revision: 1.13 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-#include "AnnotationInteractionMode.h"
-
-#include "GlobalState.h"
-#include "PolygonDrawing.h"
-#include "UserInterfaceBase.h"
-#include "IRISApplication.h"
-#include <cmath>
-#include <iomanip>
-
-#ifndef PI
-#define PI 3.14159265358979323846
-#endif
-
-AnnotationInteractionMode
-::AnnotationInteractionMode(GenericSliceWindow *parent)
-: GenericSliceWindow::EventHandler(parent)
-{
-  m_FlagDrawingLine = false;
-}
-
-AnnotationInteractionMode
-::~AnnotationInteractionMode()
-{
-}
-
-int
-AnnotationInteractionMode
-::OnKeyDown(const FLTKEvent &event)
-{
-  // on mac there are two delete keys
-  // one maps to backspace on other pc
-  if(Fl::event_key() == FL_Delete || Fl::event_key() == FL_BackSpace)
-    {
-    // delete all or delete just the last line
-    if(Fl::event_state() == FL_SHIFT)
-      m_Lines.clear();
-    else if(!m_Lines.empty())
-      m_Lines.pop_back();
-    // Redraw
-    m_Parent->GetCanvas()->redraw();
-    // only return 1 when the keystroke is handled
-    return 1;
-    }
-  // leave it for additional handling
-  return 0;
-}
-
-int
-AnnotationInteractionMode
-::OnMousePress(const FLTKEvent &event)
-{
-  // when active drawing
-  if(m_FlagDrawingLine)
-    {
-    // Record the location
-    Vector3f xEvent = m_Parent->MapWindowToSlice(event.XSpace.extract(2));
-    // Handle different mouse buttons
-    if(Fl::event_button() == FL_LEFT_MOUSE)
-      // Move the second point around the first point which is fixed
-      m_CurrentLine.second = xEvent;
-    else if (Fl::event_button() == FL_MIDDLE_MOUSE)
-      {
-      // Translation of the segment
-      Vector3f delta = xEvent - m_CurrentLine.second;
-	 m_CurrentLine.second = xEvent;
-      m_CurrentLine.first += delta;
-      }
-    else if(Fl::event_button() == FL_RIGHT_MOUSE)
-      {
-      // Commit the segment
-      m_Lines.push_back(m_CurrentLine);
-      m_FlagDrawingLine = false;
-      }
-    // Redraw
-    m_Parent->GetCanvas()->redraw();
-
-    // Even though no action may have been performed, we don't want other handlers
-    // to get the left and right mouse button events
-    return 1;
-    }
-  else
-    return 0;
-}
-
-int
-AnnotationInteractionMode
-::OnMouseDrag(const FLTKEvent &event,
-              const FLTKEvent &pressEvent)
-{
-  // Make sure it's left mouse button being pressed
-  if(Fl::event_button() == FL_RIGHT_MOUSE)
-    return 1;
-
-  // Record the location
-  Vector3f xEvent = m_Parent->MapWindowToSlice(event.XSpace.extract(2));
-
-  // Record the location of the event
-  if(m_FlagDrawingLine)
-    {
-    if(Fl::event_button() == FL_LEFT_MOUSE)
-      // Move the second point around the first point which is fixed
-      m_CurrentLine.second = xEvent;
-    else if(Fl::event_button() == FL_MIDDLE_MOUSE)
-	 {
-      // Translation of the segment
-      Vector3f delta = xEvent - m_CurrentLine.second;
-	 m_CurrentLine.second = xEvent;
-      m_CurrentLine.first += delta;
-      }
-    }
-  else if(Fl::event_button() == FL_LEFT_MOUSE)
-    {
-    m_CurrentLine.first = xEvent;
-    m_CurrentLine.second = xEvent;
-    m_FlagDrawingLine = true;
-    }
-
-  // redraw
-  m_Parent->GetCanvas()->redraw();
-  return 1;
-}
-
-void
-AnnotationInteractionMode
-::OnDraw()
-{
-  // Get the current annotation settings
-  AnnotationSettings as = m_ParentUI->GetDriver()->GetGlobalState()->GetAnnotationSettings();
-  const bool shownOnAllSlices = as.shownOnAllSlices;
-
-  // Push the line state
-  glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
-
-  // set line and point drawing parameters
-  glPointSize(3);
-  glLineWidth(1.0);
-  glEnable(GL_LINE_SMOOTH);
-  glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
-  glEnable(GL_BLEND);
-  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-  // Draw current line
-  if(m_FlagDrawingLine)
-    {
-    glColor3d(1.,1.,0.);
-    glBegin(GL_POINTS);
-    glVertex2d(m_CurrentLine.first[0], m_CurrentLine.first[1]);
-    glVertex2d(0.5 * (m_CurrentLine.first[0] + m_CurrentLine.second[0]),
-               0.5 * (m_CurrentLine.first[1] + m_CurrentLine.second[1]));
-    glVertex2d(m_CurrentLine.second[0], m_CurrentLine.second[1]);
-    glEnd();
-    glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
-    glEnable(GL_LINE_STIPPLE);
-    glLineStipple(1, 0x9999);
-    glBegin(GL_LINES);
-    glVertex2d(m_CurrentLine.first[0], m_CurrentLine.first[1]);
-    glVertex2d(m_CurrentLine.second[0], m_CurrentLine.second[1]);
-    glEnd();
-    glPopAttrib();
-
-    // Compute the length of the drawing line
-    Vector2f pt1InAna = m_Parent->MapSliceToPhysicalWindow(m_CurrentLine.first);
-    Vector2f pt2InAna = m_Parent->MapSliceToPhysicalWindow(m_CurrentLine.second);
-    double length = (pt1InAna[0] - pt2InAna[0]) * (pt1InAna[0] - pt2InAna[0])
-                  + (pt1InAna[1] - pt2InAna[1]) * (pt1InAna[1] - pt2InAna[1]);
-    length = sqrt(length);
-    std::ostringstream oss_length;
-    oss_length << std::setprecision(4) << length << " " << "mm";
-
-    // Compute the offset of 5 screen pixels
-    Vector3f v_offset = 
-      m_Parent->MapWindowToSlice(Vector2f(5.f,5.f)) - m_Parent->MapWindowToSlice(Vector2f(0.f,0.f));
-    Vector3f v_dims = 
-      m_Parent->MapWindowToSlice(Vector2f(48.f,12.f)) - m_Parent->MapWindowToSlice(Vector2f(0.f,0.f));
-
-    // Show the length of the drawing line
-    gl_draw(oss_length.str().c_str(),
-      (float) (m_CurrentLine.second[0] + v_offset(0)),
-      (float) (m_CurrentLine.second[1] + v_offset(1)));
-
-    // Compute and show the intersection angles of the drawing line with the other (visible) lines
-    for(LineIntervalList::iterator it = m_Lines.begin(); it!=m_Lines.end(); it++)
-      {
-      if(shownOnAllSlices || it->first[2] == m_Parent->m_DisplayAxisPosition)
-        {
-        Vector2f vit = m_Parent->MapSliceToPhysicalWindow(it->first) - m_Parent->MapSliceToPhysicalWindow(it->second);
-        vit /= sqrt(vit[0]*vit[0] + vit[1]*vit[1]);
-	   Vector2f vc = pt1InAna - pt2InAna;
-        vc /= sqrt(vc[0]*vc[0] + vc[1]*vc[1]);
-
-        // Compute the dot product and no need for the third components that are zeros
-        double angle = 180.0 * acos(fabs(vc[0]*vit[0]+vc[1]*vit[1])) / PI;
-        std::ostringstream oss_angle;
-        oss_angle << std::setprecision(3) << angle << " " << "deg";
-
-	   // Show the length of the drawing line
-        gl_draw(oss_angle.str().c_str(), 
-          (float) (0.5*(it->first[0] + it->second[0]) + v_offset(0)), 
-          (float) (0.5*(it->first[1] + it->second[1]) + v_offset(1)));
-        }
-      }
-    }
-
-  // Draw each of the lines
-  glColor3d(1.,0.,0.);
-  glBegin(GL_POINTS);
-  for(LineIntervalList::iterator it = m_Lines.begin(); it!=m_Lines.end(); it++)
-    {
-    if(shownOnAllSlices || it->first[2] == m_Parent->m_DisplayAxisPosition)
-      glVertex2d(0.5*(it->first[0] + it->second[0]), 0.5*(it->first[1] + it->second[1]));
-    }
-  glEnd();
-  glBegin(GL_LINES);
-  for(LineIntervalList::iterator it = m_Lines.begin(); it!=m_Lines.end(); it++)
-    {
-    if(shownOnAllSlices || it->first[2] == m_Parent->m_DisplayAxisPosition)
-      {
-      glVertex2d(it->first[0], it->first[1]);
-      glVertex2d(it->second[0], it->second[1]);
-	 }
-    }
-  glEnd();
-
-  glPopAttrib();
-}
-
diff --git a/UserInterface/SliceWindow/AnnotationInteractionMode.h b/UserInterface/SliceWindow/AnnotationInteractionMode.h
deleted file mode 100644
index 9d719f1..0000000
--- a/UserInterface/SliceWindow/AnnotationInteractionMode.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: AnnotationInteractionMode.h,v $
-  Language:  C++
-  Date:      $Date: 2009/02/10 16:50:05 $
-  Version:   $Revision: 1.6 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __AnnotationInteractionMode_h_
-#define __AnnotationInteractionMode_h_
-
-#include "GenericSliceWindow.h"
-#include "GlobalState.h"
-#include <list>
-#include <utility>
-
-/**
- * \class AnnotationInteractionMode
- * \brief UI interaction mode that takes care of polygon drawing and editing.
- *
- * \see GenericSliceWindow
- */
-class AnnotationInteractionMode : public GenericSliceWindow::EventHandler 
-{
-public:
-  AnnotationInteractionMode(GenericSliceWindow *parent);
-  virtual ~AnnotationInteractionMode();
-
-  int OnMousePress(const FLTKEvent &event);
-  int OnKeyDown(const FLTKEvent &event);
-  int OnMouseRelease(const FLTKEvent &event, const FLTKEvent &pressEvent) {return 0;};
-  int OnMouseDrag(const FLTKEvent &event, const FLTKEvent &pressEvent);
-  int OnShortcut(const FLTKEvent &event) {return 0;};
-  void OnDraw();  
-
-private:
-
-  // Annotations
-  typedef std::pair<Vector3f, Vector3f> LineIntervalType;
-  typedef std::list<LineIntervalType> LineIntervalList;
-  LineIntervalList m_Lines;
-
-  // What happened on last click
-  bool m_FlagDrawingLine;
-  LineIntervalType m_CurrentLine;
- 
-  // The window handler needs to access our privates
-  friend class IRISSliceWindow;
-};
-
-
-
-#endif // __AnnotationInteractionMode_h_
diff --git a/UserInterface/SliceWindow/BubblesInteractionMode.cxx b/UserInterface/SliceWindow/BubblesInteractionMode.cxx
deleted file mode 100644
index f67a9e1..0000000
--- a/UserInterface/SliceWindow/BubblesInteractionMode.cxx
+++ /dev/null
@@ -1,191 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: BubblesInteractionMode.cxx,v $
-  Language:  C++
-  Date:      $Date: 2008/02/10 23:55:22 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "BubblesInteractionMode.h"
-
-#include "IRISApplication.h"
-#include "IRISSliceWindow.h"
-#include "UserInterfaceBase.h"
-#include "IRISImageData.h"
-#include <vnl/vnl_math.h>
-
-#include <assert.h>
-#include <cmath>
-
-const GLubyte stipple[] = {
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
-  0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55 };
-
-BubblesInteractionMode
-::BubblesInteractionMode(GenericSliceWindow *parent)
-:GenericSliceWindow::EventHandler(parent)
-{
-}
-
-void
-BubblesInteractionMode
-::OnDraw()
-{
-  // Draw the bubbles if necessary
-  if (m_GlobalState->GetSnakeActive() == false)
-    {
-    // Get the list of bubbles
-    std::vector<Bubble> bubbles = m_GlobalState->GetBubbleArray();
-
-    // draw bubbles
-    int numBubbles = bubbles.size();
-    int activeBubble = m_GlobalState->GetActiveBubble();
-
-    if (numBubbles > 0)
-      {
-      // Get the active color label 
-      int currentcolor =  m_GlobalState->GetDrawingColorLabel();      
-      ColorLabel cl = 
-        m_Driver->GetColorLabelTable()->GetColorLabel(currentcolor);
-      
-      if (cl.IsValid())
-        {
-        // Get the current alpha blending factor for displaying overlays
-        unsigned char alpha = m_GlobalState->GetSegmentationAlpha();
-        
-        // Get the color of the active color label
-        unsigned char rgb[3];
-        cl.GetRGBVector(rgb);
-
-        // Get the current crosshairs position
-        Vector3f cursorImage = 
-          to_float(m_Driver->GetCursorPosition()) + Vector3f(0.5f);
-
-        // Get the image space dimension that corresponds to this window
-        int iid = m_Parent->m_ImageAxes[2];
-        
-        // Get the other essentials from the parent
-        Vector3f scaling = m_Parent->m_SliceSpacing;       
-        
-        // Turn on alpha blending
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-        // Create a filled circle object
-        GLUquadricObj *object = gluNewQuadric();
-        gluQuadricDrawStyle(object,GLU_FILL);
-
-        // Draw each bubble
-        for (int i = 0; i < numBubbles; i++)
-          {  
-          
-          // Get the center and radius of the i-th bubble
-          Vector3f ctrImage = to_float(bubbles[i].center) + Vector3f(0.5f);
-          double radius = bubbles[i].radius;
-
-          // Remap the center into slice coordinates
-          Vector3f ctrSlice = m_Parent->MapImageToSlice(to_float(ctrImage));
-
-          // Compute the offset from the center along the slice z-direction
-          // in physical coordinates
-          double dcenter = scaling(2) * (cursorImage(iid) - ctrImage(iid));
-                    
-          // Check if the bubble is intersected by the current slice plane
-          if (dcenter >= radius || -dcenter >= radius) continue;
-            
-          // Compute the radius of the bubble in the cut plane
-          double diskradius = sqrt(fabs(radius*radius - dcenter*dcenter));
-
-          // Draw the bubble
-          glColor4ub(rgb[0],rgb[1],rgb[2],alpha);
-          glPushMatrix();
-
-          glPushAttrib(GL_POLYGON_BIT | GL_COLOR_BUFFER_BIT);
-          if(activeBubble == i)
-            {
-            glEnable(GL_POLYGON_STIPPLE);
-            glPolygonStipple(stipple);
-            }
-          
-          glTranslatef(ctrSlice[0], ctrSlice[1], 0.0f);
-          glScalef(1.0f / scaling(0),1.0f / scaling(1),1.0f);
-          gluDisk(object,0,diskradius,100,1);
-          glPopAttrib();
-
-          // If the bubble is active, draw an outline around the bubble
-          if(activeBubble == i)
-            {
-            glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
-
-            glEnable(GL_BLEND);
-            glEnable(GL_LINE_SMOOTH);
-            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-            glLineWidth(1.5);
-            
-            glColor4ub(
-              255 - (255 - rgb[0]) / 2,
-              255 - (255 - rgb[1]) / 2,
-              255 - (255 - rgb[2]) / 2, 255);
-            
-            glBegin(GL_LINE_LOOP);
-            for(unsigned int d = 0; d < 360; d+=2)
-              {
-              double rad = d * vnl_math::pi / 180.0;
-              glVertex2f(diskradius * cos(rad), diskradius * sin(rad));
-              }
-            glEnd();
-            glPopAttrib();
-            }
-          
-          glPopMatrix();
-
-          }
-
-        gluDeleteQuadric(object);
-        glDisable(GL_BLEND);
-        }
-      }
-    }
-}
-
-
diff --git a/UserInterface/SliceWindow/BubblesInteractionMode.h b/UserInterface/SliceWindow/BubblesInteractionMode.h
deleted file mode 100644
index efdbd20..0000000
--- a/UserInterface/SliceWindow/BubblesInteractionMode.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: BubblesInteractionMode.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:27 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __BubblesInteractionMode_h_
-#define __BubblesInteractionMode_h_
-
-#include "GenericSliceWindow.h"
-
-/**
- * \class BubblesInteractionMode
- * \brief UI interaction mode that takes care of bubble placement 
- * in segmentation.
- *
- * The interaction mode for display (and one day, manipulation) of 
- * intialization bubbles for the segmentation.  Presently, this class 
- * only has a draw method, but if we ever want to me able to click and
- * drag bubbles, this is the place to do so
- *
- * \see GenericSliceWindow
- */
-class BubblesInteractionMode : public GenericSliceWindow::EventHandler {
-public:
-  BubblesInteractionMode(GenericSliceWindow *parent);
-  void OnDraw();
-};
-
-#endif // __BubblesInteractionMode_h_
diff --git a/UserInterface/SliceWindow/CrosshairsInteractionMode.cxx b/UserInterface/SliceWindow/CrosshairsInteractionMode.cxx
deleted file mode 100644
index dea1ff2..0000000
--- a/UserInterface/SliceWindow/CrosshairsInteractionMode.cxx
+++ /dev/null
@@ -1,431 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: CrosshairsInteractionMode.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/19 20:28:56 $
-  Version:   $Revision: 1.13 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "CrosshairsInteractionMode.h"
-#include "SNAPOpenGL.h"
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-#include "SNAPAppearanceSettings.h"
-#include "UserInterfaceBase.h"
-#include "SliceWindowCoordinator.h"
-
-CrosshairsInteractionMode
-::CrosshairsInteractionMode(
-  GenericSliceWindow *parent, Button cursor_button, Button zoom_button, Button pan_button) 
-: GenericSliceWindow::EventHandler(parent), 
-  m_BtnCursor(cursor_button), m_BtnZoom(zoom_button), m_BtnPan(pan_button)
-{
-  m_NeedToRepaintControls = false;
-  m_LastViewposUpdateTime = 0;
-  m_NeedUIUpdateOnRepaint = false;
-}
-
-int
-CrosshairsInteractionMode
-::OnMousePress(const FLTKEvent &event)
-{
-  if(m_BtnCursor == ANY || event.SoftButton == m_BtnCursor)
-    {
-    UpdateCrosshairs(event);
-    m_Parent->m_GlobalState->SetUpdateSliceFlag(0);
-    m_RepeatEvent = event;
-    }
-  else if(m_BtnZoom == ANY || event.SoftButton == m_BtnZoom)
-    {
-    m_StartViewZoom = m_Parent->GetViewZoom();
-    }
-  else if(m_BtnPan == ANY || event.SoftButton == m_BtnPan)
-    {
-    m_StartViewPosition = m_Parent->m_ViewPosition;
-    }
-  return 1;
-}
-
-int
-CrosshairsInteractionMode
-::OnMouseRelease(const FLTKEvent &event,const FLTKEvent &dragEvent)
-{
-  if(m_BtnCursor == ANY || dragEvent.SoftButton == m_BtnCursor)
-    {
-    UpdateCrosshairs(event);
-    m_Parent->m_GlobalState->SetUpdateSliceFlag(1);
-    m_RepeatEvent = event;
-    return 1;
-    }
-  else if(m_BtnZoom == ANY || dragEvent.SoftButton == m_BtnZoom)
-    return 1;
-  else if(m_BtnPan == ANY || dragEvent.SoftButton == m_BtnPan)
-    return 1;
-
-  return 0;
-}
-
-int
-CrosshairsInteractionMode
-::OnMouseDrag(const FLTKEvent &event, 
-              const FLTKEvent &dragEvent)
-{
-  if(m_BtnCursor == ANY || dragEvent.SoftButton == m_BtnCursor)
-    {
-    UpdateCrosshairs(event);
-    m_Parent->m_GlobalState->SetUpdateSliceFlag(1);
-    m_RepeatEvent = event;
-    return 1;
-    }
-  else if(m_BtnZoom == ANY || dragEvent.SoftButton == m_BtnZoom)
-    {
-    // Under the right button, the tool causes us to zoom based on the vertical
-    // motion
-    float zoom = m_StartViewZoom 
-      * pow(1.02f,(float)(event.XSpace(1) - dragEvent.XSpace(1)));
-
-
-    // Clamp the zoom factor to reasonable limits
-    zoom = m_ParentUI->GetSliceCoordinator()->ClampZoom(m_Parent->m_Id,zoom);
-
-    // Make sure the zoom factor is an integer fraction
-    zoom = m_Parent->GetOptimalZoom() * 
-           ((int)(zoom / m_Parent->GetOptimalZoom() * 100)) / 100.0f;
-
-    // Set the zoom factor using the window coordinator
-    m_Parent->SetViewZoom(zoom);
-    m_ParentUI->GetSliceCoordinator()->OnZoomUpdateInWindow(m_Parent->m_Id,zoom);
-
-    // Schedule an update of the zoom percentage display in the parent
-    m_NeedUIUpdateOnRepaint = true;
-    return 1;
-    } 
-  else if (m_BtnPan == ANY || dragEvent.SoftButton == m_BtnPan)
-    {
-    // Compute the start and end point in slice coordinates
-    Vector3f xStart = m_Parent->MapWindowToSlice(dragEvent.XSpace.extract(2));
-    Vector3f xEnd = m_Parent->MapWindowToSlice(event.XSpace.extract(2));
-    Vector2f xOffset(xEnd[0] - xStart[0],xEnd[1] - xStart[1]);
-
-    // Remove the scaling by spacing
-    xOffset(0) *= m_Parent->m_SliceSpacing(0);
-    xOffset(1) *= m_Parent->m_SliceSpacing(1);
-
-    // Under the left button, the tool changes the view_pos by the
-    // distance traversed
-    m_Parent->SetViewPosition(m_StartViewPosition - xOffset);
-    m_ParentUI->OnViewPositionsUpdate();
-    return 1;
-    } 
-  return 0;
-}
-
-int
-CrosshairsInteractionMode
-::OnMouseWheel(const FLTKEvent &irisNotUsed(event))
-{
-  // Must have the cursor inside the window to process key events
-  if(!m_Parent->GetCanvas()->GetFocus()) return 0;
-
-  // Get the amount of the scroll
-  float scroll = (float) Fl::event_dy();
-  
-  // Get the cross-hairs position in image space
-  Vector3ui xCrossImage = m_Driver->GetCursorPosition();
-
-  // Map it into slice space
-  Vector3f xCrossSlice = 
-    m_Parent->MapImageToSlice(to_float(xCrossImage) + Vector3f(0.5f));
-
-  // Advance by the scroll amount
-  xCrossSlice[2] += scroll;
-
-  // Map back into display space
-  xCrossImage = to_unsigned_int(m_Parent->MapSliceToImage(xCrossSlice));
-
-  // Clamp by the display size
-  Vector3ui xSize = m_Driver->GetCurrentImageData()->GetVolumeExtents();
-  Vector3ui xCrossClamped = xCrossImage.clamp(
-    Vector3ui(0,0,0),xSize - Vector3ui(1,1,1));
-
-  // Update the crosshairs position in the global state
-  m_Driver->SetCursorPosition(xCrossClamped);
-
-  // Cause a repaint
-  m_NeedToRepaintControls = true;
-
-  // Update the crosshairs position in the current image data
-  m_ParentUI->OnCrosshairPositionUpdate(true);  
-  m_ParentUI->RedrawWindows();  
-
-  return 1;
-}
-
-void
-CrosshairsInteractionMode
-::UpdateCrosshairs(const Vector3f &xClick)
-{
-  // Compute the new cross-hairs position in image space
-  Vector3f xCross = m_Parent->MapSliceToImage(xClick);
-
-  // Round the cross-hairs position down to integer
-  Vector3i xCrossInteger = to_int(xCross);
-  
-  // Make sure that the cross-hairs position is within bounds by clamping
-  // it to image dimensions
-  Vector3i xSize = to_int(m_Driver->GetCurrentImageData()->GetVolumeExtents());
-  Vector3ui xCrossClamped = to_unsigned_int(
-    xCrossInteger.clamp(Vector3i(0),xSize - Vector3i(1)));
-
-  // Update the crosshairs position in the global state
-  m_Driver->SetCursorPosition(xCrossClamped);
-
-  // Cause a repaint
-  m_NeedToRepaintControls = true;
-
-  // Update the crosshairs position in the current image data
-  m_ParentUI->OnCrosshairPositionUpdate(true);  
-  m_ParentUI->RedrawWindows();  
-}
-
-
-void
-CrosshairsInteractionMode
-::TimeoutCallback(void *vp)
-{
-  CrosshairsInteractionMode *cim  = (CrosshairsInteractionMode *)vp;
-  FLTKEvent ev;
-  if(cim->GetCanvas()->IsDragging())
-    {
-    FLTKEvent ev = cim->m_RepeatEvent;
-    ev.TimeStamp = FLTKEventTimeStamp();
-    cim->UpdateCrosshairs(ev);
-    }
-}
-
-
-
-void
-CrosshairsInteractionMode
-::UpdateCrosshairs(const FLTKEvent &event)
-{
-  // Compute the position in slice coordinates
-  Vector3f xClick = m_Parent->MapWindowToSlice(event.XSpace.extract(2));
-
-  // Check if the cursor is in one of the hot zones
-  Vector3f z0 = m_Parent->MapWindowToSlice(
-    Vector2f(0.1 * m_Parent->GetCanvas()->w(),0.1 * m_Parent->GetCanvas()->h()));
-  Vector3f z1 = m_Parent->MapWindowToSlice(
-    Vector2f(0.9 * m_Parent->GetCanvas()->w(),0.9 * m_Parent->GetCanvas()->h()));
-  Vector3f y0 = m_Parent->MapWindowToSlice(
-    Vector2f(0.0 * m_Parent->GetCanvas()->w(),0.0 * m_Parent->GetCanvas()->h()));
-  Vector3f y1 = m_Parent->MapWindowToSlice(
-    Vector2f(1.0 * (m_Parent->GetCanvas()->w()-1),1.0 * (m_Parent->GetCanvas()->h()-1)));
- 
-  bool hotzone = false;
-  Vector2f newViewPos = m_Parent->m_ViewPosition;
-  for(size_t i = 0; i < 2; i++)
-    {
-    // There are three discrete speeds
-    int pixel_speeds[] = {5, 10, 20};
-    int min_voxel_speeds[] = {1, 2, 4};
-
-    double zmin = std::min(z0[i], z1[i]), zmax = std::max(z0[i], z1[i]);
-    double ymin = std::min(y0[i], y1[i]), ymax = std::max(y0[i], y1[i]);
-
-    if(xClick[i] < zmin)
-      {
-      // The speed is based on how close to the border we are
-      double relspeed = (zmin - xClick[i]) / (zmin - ymin);
-      int speedidx = std::min((int) (relspeed * 2.0), 2);
-      int pixspeed = pixel_speeds[speedidx];
-      
-      // We want to move 5 screen pixels every 0.1 sec. How many voxels is that
-      int nvox = std::max(min_voxel_speeds[speedidx], 
-        (int) (0.5 + pixspeed / (m_Parent->m_ViewZoom * m_Parent->m_SliceSpacing[i])));
-
-      
-      // Move the cursor left by nvox voxel
-      newViewPos[i] -= nvox * m_Parent->m_SliceSpacing[i];
-      hotzone = true;
-      }
-    else if(xClick[i] > zmax)
-      {
-      // The speed is based on how close to the border we are
-      double relspeed = (xClick[i] - zmax) / (ymax - zmax);
-      int speedidx = std::min((int) (relspeed * 2.0), 2);
-      int pixspeed = pixel_speeds[speedidx];
-      
-      // We want to move 5 screen pixels every 0.1 sec. How many voxels is that
-      int nvox = std::max(min_voxel_speeds[speedidx], 
-        (int) (0.5 + pixspeed / (m_Parent->m_ViewZoom * m_Parent->m_SliceSpacing[i])));      
-
-      // Move the cursor left by 1 voxel
-      newViewPos[i] += nvox * m_Parent->m_SliceSpacing[i];
-      hotzone = true;
-      }
-    }
-
-  // Hotzone is disabled when whole slice is visible
-  if(m_Parent->m_ViewZoom <= m_Parent->m_OptimalZoom)
-    hotzone = false;
-
-  // Check apperarance settings
-  if(!m_ParentUI->GetAppearanceSettings()->GetFlagAutoPan())
-    hotzone = false;
-
-  // Now we are ready to do something about the hotzome
-  if(hotzone)
-    {
-    // If we were in the hotzone less that 100 ms ago, forget it
-    static FLTKEventTimeStamp last_hotzone_action;
-    FLTKEventTimeStamp tsnow;
-    if(tsnow.ElapsedUSecFrom(last_hotzone_action) > 100000)
-      {
-      m_Parent->SetViewPosition(newViewPos);
-      m_ParentUI->OnViewPositionsUpdate(true);
-      last_hotzone_action = tsnow;
-      }
-  
-    // Even if we were too soon for a hotzone, schedule the check in a few ms
-    Fl::add_timeout(0.02, CrosshairsInteractionMode::TimeoutCallback, this);
-    }
-  
-  xClick = m_Parent->MapWindowToSlice(event.XSpace.extract(2));
-
-  UpdateCrosshairs(xClick);
-}
-
-int 
-CrosshairsInteractionMode
-::OnKeyDown(const FLTKEvent &event)
-{
-  // Must have the cursor inside the window to process key events
-  if(!m_Parent->GetCanvas()->GetFocus()) return 0;
-
-  // Vector encoding the movement in pixels
-  Vector3f xMotion(0.0f);
-
-  // Check the shift state
-  float xStep = (event.State & FL_SHIFT) ? 5.0f : 1.0f;
-
-  // Handle up, down, left, right, pg-up and pg-down events
-  switch(Fl::event_key())
-    {
-    case FL_Right:     xMotion[0] += xStep; break;
-    case FL_Left:      xMotion[0] -= xStep; break;
-    case FL_Down:      xMotion[1] -= xStep; break;
-    case FL_Up:        xMotion[1] += xStep; break;
-    case FL_Page_Up:   xMotion[2] -= xStep; break;
-    case FL_Page_Down: xMotion[2] += xStep; break;
-    default: return 0;
-    };
-
-  // Get the crosshair coordinates, in slice space
-  Vector3f xCross = 
-    m_Parent->MapImageToSlice(
-      to_float(m_Driver->GetCursorPosition()));
-
-  // Add the motion vector
-  UpdateCrosshairs(xCross + xMotion);
-
-  // Handled!
-  return 1;
-}
-
-void 
-CrosshairsInteractionMode::
-OnDraw()
-{
-  // Do the painting only if necessary
-  if(m_NeedToRepaintControls)
-    {
-    // Update the image probe and scrollbar controls
-    m_ParentUI->OnCrosshairPositionUpdate(false);
-    
-    // No need to call this until another update
-    m_NeedToRepaintControls = false;
-    }
-
-  if(m_NeedUIUpdateOnRepaint)
-    {
-    m_ParentUI->OnZoomUpdate();
-    m_NeedUIUpdateOnRepaint = false;
-    }
-
-  // Get the line color, thickness and dash spacing for the crosshairs
-  SNAPAppearanceSettings::Element elt = 
-    m_Parent->m_ThumbnailIsDrawing 
-    ? m_ParentUI->GetAppearanceSettings()->GetUIElement(
-      SNAPAppearanceSettings::CROSSHAIRS_THUMB)
-    : m_ParentUI->GetAppearanceSettings()->GetUIElement(
-      SNAPAppearanceSettings::CROSSHAIRS);
-
-  // Exit if the crosshars are not drawn
-  if(!elt.Visible) return;
-
-  // Get the current cursor position
-  Vector3ui xCursorInteger = m_Driver->GetCursorPosition();
-
-  // Shift the cursor position by by 0.5 in order to have it appear
-  // between voxels
-  Vector3f xCursorImage = to_float(xCursorInteger) + Vector3f(0.5f);
-  
-  // Get the cursor position on the slice
-  Vector3f xCursorSlice = m_Parent->MapImageToSlice(xCursorImage);
-
-  // Upper and lober bounds to which the crosshairs are drawn
-  Vector2i lower(0);
-  Vector2i upper = m_Parent->m_SliceSize.extract(2);
-
-  // Set line properties
-  glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
-
-  // Apply the line properties; thick line is only applied in zoom thumbnail (?)
-  SNAPAppearanceSettings::ApplyUIElementLineSettings(elt);
-
-  // Apply the color
-  glColor3dv(elt.NormalColor.data_block());
-  
-  // Refit matrix so that the lines are centered on the current pixel
-  glPushMatrix();
-  glTranslated( xCursorSlice(0), xCursorSlice(1), 0.0 );
-
-  // Paint the cross-hairs
-  glBegin(GL_LINES);  
-  glVertex2f(0, 0); glVertex2f(lower(0) - xCursorSlice(0), 0);
-  glVertex2f(0, 0); glVertex2f(upper(0) - xCursorSlice(0), 0);
-  glVertex2f(0, 0); glVertex2f(0, lower(1) - xCursorSlice(1));
-  glVertex2f(0, 0); glVertex2f(0, upper(1) - xCursorSlice(1));
-  glEnd();
-
-  glPopMatrix();
-  glPopAttrib();
-}
-
diff --git a/UserInterface/SliceWindow/CrosshairsInteractionMode.h b/UserInterface/SliceWindow/CrosshairsInteractionMode.h
deleted file mode 100644
index 8aa78fc..0000000
--- a/UserInterface/SliceWindow/CrosshairsInteractionMode.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: CrosshairsInteractionMode.h,v $
-  Language:  C++
-  Date:      $Date: 2010/10/12 16:02:05 $
-  Version:   $Revision: 1.6 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __CrosshairsInteractionMode_h_
-#define __CrosshairsInteractionMode_h_
-
-#include "GenericSliceWindow.h"
-#include "GlobalState.h"
-
-/**
- * \class CrosshairsInteractionMode
- * \brief UI interaction mode that takes care of crosshair positioning.
- *
- * \see GenericSliceWindow
- */
-class CrosshairsInteractionMode : public GenericSliceWindow::EventHandler {
-public:
-  /* Enum used to specify what mouse buttons different navigation functionality
-     responds to */
-
-  enum Button { 
-    LEFT=FL_LEFT_MOUSE, RIGHT=FL_RIGHT_MOUSE, MIDDLE=FL_MIDDLE_MOUSE, NONE=-1, ANY=-2 };
-
-  CrosshairsInteractionMode(
-    GenericSliceWindow *parent,
-    Button cursor_button = LEFT,
-    Button zoom_button = RIGHT,
-    Button pan_button = MIDDLE);
-
-  void SetInteractionStyle(Button cursor_button, Button zoom_button, Button pan_button)
-    {
-    m_BtnCursor = cursor_button;
-    m_BtnZoom = zoom_button;
-    m_BtnPan = pan_button;
-    }
-
-  void OnDraw(); 
-  int OnMousePress(const FLTKEvent &event);
-  int OnMouseWheel(const FLTKEvent &event);
-  int OnMouseRelease(const FLTKEvent &event, 
-                     const FLTKEvent &irisNotUsed(pressEvent));
-  int OnMouseDrag(const FLTKEvent &event, 
-                  const FLTKEvent &irisNotUsed(pressEvent));
-  int OnKeyDown(const FLTKEvent &event);
-
-private:
-  void UpdateCrosshairs(const FLTKEvent &event);
-  void UpdateCrosshairs(const Vector3f &xCross);
-
-  // Whether or not we need to repaint the controls that depend on
-  // the current slice position
-  bool m_NeedToRepaintControls;
-
-  FLTKEvent m_RepeatEvent;
-  long int m_LastViewposUpdateTime;
-
-  // Buttons assigned to each of the functionalities
-  Button m_BtnCursor, m_BtnZoom, m_BtnPan;
-
-  // Copied from zoom-pan. All your base are belong to us.
-  Vector2f m_StartViewPosition;
-  float m_StartViewZoom;
-  bool m_NeedUIUpdateOnRepaint;
-
-  static void TimeoutCallback(void *);
-};
-
-#endif // __CrosshairsInteractionMode_h_
diff --git a/UserInterface/SliceWindow/GLToPNG.cxx b/UserInterface/SliceWindow/GLToPNG.cxx
deleted file mode 100644
index 12418d4..0000000
--- a/UserInterface/SliceWindow/GLToPNG.cxx
+++ /dev/null
@@ -1,100 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: GLToPNG.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/05/01 21:29:32 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "GLToPNG.h"
-
-#include <iostream>
-using namespace std;
-
-vtkImageData* GLToVTKImageData(unsigned int format, int x, int y, int w, int h) 
-{
-  // Cast the format to GL enum
-  GLenum glformat = (GLenum) format;
-
-  // OSX does double buffer automatically (???)
-  //glReadBuffer(GL_BACK);
-  unsigned int GL_comps = 0;
-  if (glformat == GL_RGBA) 
-    {
-    GL_comps = 4;
-    } 
-  else if (glformat == GL_RGB) 
-    {
-    GL_comps = 3;
-    } 
-  else 
-    {
-    std::cerr << "Invalid GLenum" << endl;
-    exit(1);
-    }
-
-  unsigned char* pixmap = new unsigned char[w*h*GL_comps];
-  glReadPixels(x, y, w, h, format, GL_UNSIGNED_BYTE, pixmap);
-
-  // convert to vtkImageData
-  vtkImageData* img = vtkImageData::New();
-  if (format == GL_RGBA) 
-    {
-    img->SetExtent(0, w-1, 0, h-1, 0, 0);
-    } 
-  else if (format == GL_RGB) 
-    {
-    img->SetExtent(0, w, 0, h, 0, 0);
-    }
-  img->SetSpacing(1.0, 1.0, 1.0);
-  img->SetOrigin(0.0, 0.0, 0.0);
-  img->SetNumberOfScalarComponents(GL_comps);
-  img->SetScalarType(VTK_UNSIGNED_CHAR);
-  int rowSize = w*GL_comps;
-  unsigned char* pixmap2 = pixmap;
-  unsigned char* imgPtr = (unsigned char*) img->GetScalarPointer(0, 0, 0);
-  for (int i = 0; i < h; ++i) 
-    {
-    memcpy(imgPtr, pixmap2, rowSize);
-    imgPtr += rowSize;
-    pixmap2 += rowSize;
-    }
-  delete[] pixmap;
-  return img;
-}
-
-void VTKImageDataToPNG(vtkImageData* img, const char* filename)
-{
-  vtkPNGWriter* pngw = vtkPNGWriter::New();
-  pngw->SetInput(img);
-  pngw->SetFileName(filename);
-  pngw->Write();
-  pngw->Delete();
-}
-
diff --git a/UserInterface/SliceWindow/GLToPNG.h b/UserInterface/SliceWindow/GLToPNG.h
deleted file mode 100644
index e746312..0000000
--- a/UserInterface/SliceWindow/GLToPNG.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: GLToPNG.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:28 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __GLToPNG_h_
-#define __GLToPNG_h_
-
-#include <FL/gl.h>
-
-/**
- * 
- * Simple Functions that convert GL buffer into vtkImageData
- * and save the vtkImageData as PNG file
- * 
- * 01/25/2004
- * Hui Gary Zhang
- *
- */
-
-#include "vtkImageData.h"
-#include "vtkPNGWriter.h"
-
-// convert a GL buffer into vtkImageData
-vtkImageData* GLToVTKImageData(unsigned int format, int x, int y, int w, int h);
-
-// output vtkImageData as PNG
-void VTKImageDataToPNG(vtkImageData* img, const char* filename);
-
-#endif
-
diff --git a/UserInterface/SliceWindow/GenericSliceWindow.cxx b/UserInterface/SliceWindow/GenericSliceWindow.cxx
deleted file mode 100644
index d93d450..0000000
--- a/UserInterface/SliceWindow/GenericSliceWindow.cxx
+++ /dev/null
@@ -1,950 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: GenericSliceWindow.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/13 16:59:25 $
-  Version:   $Revision: 1.36 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "GenericSliceWindow.h"
-
-#include "CrosshairsInteractionMode.h"
-#include "GlobalState.h"
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-#include "OpenGLSliceTexture.h"
-#include "SliceWindowCoordinator.h"
-#include "SNAPAppearanceSettings.h"
-#include "UserInterfaceBase.h"
-#include "ThumbnailInteractionMode.h"
-#include "PopupButtonInteractionMode.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <cstdlib>
-#include <cmath>
-#include <iostream>
-
-#include "itkConstantPadImageFilter.h"
-
-using namespace std;
-
-GenericSliceWindow
-::GenericSliceWindow(int index, UserInterfaceBase *ui, FLTKCanvas *canvas)
-: RecursiveInteractionMode(canvas)
-{
-  // Copy parent pointers
-  m_ParentUI = ui;
-  m_Driver = m_ParentUI->GetDriver();
-  m_GlobalState = m_Driver->GetGlobalState();    
-
-  // Set the window ID
-  m_Id = index;
-
-  // Initialize the interaction modes
-  m_NavigationMode = new CrosshairsInteractionMode(this);
-  m_ThumbnailMode = new ThumbnailInteractionMode(this);
-  m_PopupButtonMode = new PopupButtonInteractionMode(this);
-
-  // The slice is not yet initialized
-  m_IsSliceInitialized = false;
-
-  // Initialize the Main image slice texture
-  m_MainTexture = new OpenGLSliceTexture(4, GL_RGBA);
-
-  // Initialize the Segmentation slice texture
-  m_LabelRGBTexture = new OpenGLSliceTexture(4, GL_RGBA);
-
-  // Initalize the margin
-  m_Margin = 2;
-
-  // Initialize the zoom management
-  m_ManagedZoom = false;
-
-  // No thumbnail
-  m_ThumbnailIsDrawing = false;
-
-  // Allow focus grabbing
-  m_Canvas->SetGrabFocusOnEntry(true);
-
-  // Register the sub-interaction modes
-  m_NavigationMode->Register();
-  m_ThumbnailMode->Register();
-  m_PopupButtonMode->Register();
-
-  // We have been registered
-  m_IsRegistered = true;
-}    
-
-GenericSliceWindow
-::~GenericSliceWindow()
-{
-  // Delete the interaction modes
-  delete m_NavigationMode;
-  delete m_ThumbnailMode;
-  delete m_PopupButtonMode;
-
-  // Delete textures
-  delete m_MainTexture;
-  delete m_LabelRGBTexture;
-}
-
-
-
-void 
-GenericSliceWindow
-::InitializeSlice(GenericImageData *imageData)
-{
-  // Register should have been called already
-  assert(m_IsRegistered);
-
-  // Store the image data pointer
-  m_ImageData = imageData;
-
-  // The main image should be loaded
-  if (imageData->IsMainLoaded())
-    {
-    // Initialize the Main image slice texture
-    m_MainTexture->SetImage(
-      m_ImageData->GetMain()->GetDisplaySlice(m_Id).GetPointer());
-    }
-  else
-    {
-    // If not
-    m_IsSliceInitialized = false;
-    ClearInteractionStack();
-    return;
-    }
-
-  // Initialize the segmentation slice texture
-  if (imageData->IsSegmentationLoaded())
-    {
-    m_LabelRGBTexture->SetImage(
-      m_ImageData->GetSegmentation()->GetDisplaySlice(m_Id).GetPointer());
-    }
-
-  // Initialize overlay slice
-  InitializeOverlaySlice(imageData);
-
-  // Store the transforms between the display and image spaces
-  m_ImageToDisplayTransform = 
-    imageData->GetImageGeometry().GetImageToDisplayTransform(m_Id);
-  m_DisplayToImageTransform =
-    imageData->GetImageGeometry().GetDisplayToImageTransform(m_Id);
-  m_DisplayToAnatomyTransform = 
-    imageData->GetImageGeometry().GetAnatomyToDisplayTransform(m_Id).Inverse();
-
-  // Get the volume extents & voxel scale factors
-  Vector3ui imageSizeInImageSpace = m_ImageData->GetVolumeExtents();
-  Vector3f imageScalingInImageSpace = to_float(m_ImageData->GetImageSpacing());
-
-  // Initialize quantities that depend on the image and its transform
-  for(unsigned int i = 0;i < 3;i++) 
-    {    
-    // Get the direction in image space that corresponds to the i'th
-    // direction in slice space
-    m_ImageAxes[i] = m_DisplayToImageTransform.GetCoordinateIndexZeroBased(i);
-
-    // Record the size and scaling of the slice
-    m_SliceSize[i] = imageSizeInImageSpace[m_ImageAxes[i]];
-    m_SliceSpacing[i] = imageScalingInImageSpace[m_ImageAxes[i]]; // TODO: Reverse sign by orientation?
-    }
-
-  // No information about the current slice available yet
-  m_ImageSliceIndex = -1;
-  m_DisplayAxisPosition = 0.0f;
-
-  // We have been initialized
-  m_IsSliceInitialized = true;
-
-  // If the is no current interaction mode, enter the crosshairs mode
-  if(GetInteractionModeCount() == 0)
-    PushInteractionMode(m_NavigationMode);
-
-  // setup default view - fit to window
-  ResetViewToFit();
-}
-
-void 
-GenericSliceWindow
-::InitializeOverlaySlice(GenericImageData *imageData)
-{
-  // Register should have been called already
-  assert(m_IsRegistered);
-
-  // The main image should be loaded
-  if (!imageData->IsMainLoaded())
-    {
-    // If not
-    m_IsSliceInitialized = false;
-    ClearInteractionStack();
-    return;
-    }
-
-  // Store the image data pointer
-  m_ImageData = imageData;
-
-  // Clear the overlay texture list
-  while (m_OverlayTextureList.size() > 0)
-    {
-    delete m_OverlayTextureList.front();
-    m_OverlayTextureList.pop_front();
-    }
-
-  // Initialize the overlay slice texture
-  if (imageData->IsOverlayLoaded())
-    {
-    std::list<ImageWrapperBase *>::iterator it = m_ImageData->GetOverlays()->begin();
-    while (it != m_ImageData->GetOverlays()->end())
-      {
-      OpenGLSliceTexture *texture = new OpenGLSliceTexture(4, GL_RGBA);
-      texture->SetImage((*it)->GetDisplaySlice(m_Id).GetPointer());
-	    m_OverlayTextureList.push_back(texture);
-      it++;
-    	 }
-    }
-
-}
-
-void
-GenericSliceWindow
-::ComputeOptimalZoom()
-{
-  // Should be fully initialized
-  assert(m_IsRegistered && m_IsSliceInitialized);
-
-  // Compute slice size in spatial coordinates
-  Vector2f worldSize(
-    m_SliceSize[0] * m_SliceSpacing[0],
-    m_SliceSize[1] * m_SliceSpacing[1]);
-
-  // Set the view position (position of the center of the image?)
-  m_ViewPosition = worldSize * 0.5f;
-
-  // Reduce the width and height of the slice by the margin
-  Vector2i szCanvas = 
-    Vector2i(m_Canvas->w(),m_Canvas->h()) - Vector2i(2 * m_Margin);
-  
-  // Compute the ratios of window size to slice size
-  Vector2f ratios(
-    szCanvas(0) / worldSize(0),
-    szCanvas(1) / worldSize(1));
-
-  // The zoom factor is the bigger of these ratios, the number of pixels 
-  // on the screen per millimeter in world space
-  m_OptimalZoom = ratios.min_value();
-}
-
-Vector2i 
-GenericSliceWindow
-::GetOptimalCanvasSize()
-{
-  // Compute slice size in spatial coordinates
-  Vector2i optSize(
-    (int) ceil(m_SliceSize[0] * m_SliceSpacing[0] * m_ViewZoom + 2 * m_Margin),
-    (int) ceil(m_SliceSize[1] * m_SliceSpacing[1] * m_ViewZoom + 2 * m_Margin));
-
-  return optSize;
-}
-
-void
-GenericSliceWindow
-::ResetViewToFit()
-{
-  // Should be fully initialized
-  assert(m_IsRegistered && m_IsSliceInitialized);
-
-  // Compute slice size in spatial coordinates
-  ComputeOptimalZoom();
-
-  // The zoom factor is the bigger of these ratios, the number of pixels 
-  // on the screen per millimeter in world space
-  m_ViewZoom = m_OptimalZoom;
-
-  // Cause a redraw of the window
-  m_Canvas->redraw();
-}
-
-Vector3f 
-GenericSliceWindow
-::MapSliceToImage(const Vector3f &xSlice) 
-{
-  assert(m_IsSliceInitialized);
-
-  // Get corresponding position in display space
-  return m_DisplayToImageTransform.TransformPoint(xSlice);
-}
-
-/**
- * Map a point in image coordinates to slice coordinates
- */
-Vector3f 
-GenericSliceWindow
-::MapImageToSlice(const Vector3f &xImage) 
-{
-  assert(m_IsSliceInitialized);
-
-  // Get corresponding position in display space
-  return  m_ImageToDisplayTransform.TransformPoint(xImage);
-}
-
-Vector2f 
-GenericSliceWindow
-::MapSliceToWindow(const Vector3f &xSlice)
-{
-  assert(m_IsSliceInitialized);
-
-  // Adjust the slice coordinates by the scaling amounts
-  Vector2f uvScaled(
-    xSlice(0) * m_SliceSpacing(0),xSlice(1) * m_SliceSpacing(1));
-
-  // Compute the window coordinates
-  Vector2f uvWindow = 
-    m_ViewZoom * (uvScaled - m_ViewPosition) + 
-    Vector2f(0.5f * m_Canvas->w(),0.5f * m_Canvas->h());
-  
-  // That's it, the projection matrix is set up in the scaled-slice coordinates
-  return uvWindow;
-}
-
-Vector3f 
-GenericSliceWindow
-::MapWindowToSlice(const Vector2f &uvWindow)
-{
-  assert(m_IsSliceInitialized && m_ViewZoom > 0);
-
-  // Compute the scaled slice coordinates
-  Vector2f winCenter(0.5f * m_Canvas->w(),0.5f * m_Canvas->h());
-  Vector2f uvScaled = 
-    m_ViewPosition + (uvWindow - winCenter) / m_ViewZoom;
-  
-  // The window coordinates are already in the scaled-slice units
-  Vector3f uvSlice(
-    uvScaled(0) / m_SliceSpacing(0),
-    uvScaled(1) / m_SliceSpacing(1),
-    m_DisplayAxisPosition);
-
-  // Return this vector
-  return uvSlice;
-}
-
-Vector2f 
-GenericSliceWindow
-::MapSliceToPhysicalWindow(const Vector3f &xSlice)
-{
-  assert(m_IsSliceInitialized);
-
-  // Compute the physical window coordinates
-  Vector2f uvPhysical;
-  uvPhysical[0] = xSlice[0] * m_SliceSpacing[0];
-  uvPhysical[1] = xSlice[1] * m_SliceSpacing[1];
-
-  return uvPhysical;
-}
-
-void
-GenericSliceWindow
-::OnDraw()
-{
-  // Set up the projection if necessary
-  if(!m_Canvas->valid()) 
-  {
-    // The window will have coordinates (0,0) to (w,h), i.e. the same as the window
-    // coordinates.
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    gluOrtho2D(0.0,m_Canvas->w(),0.0,m_Canvas->h());
-    glViewport(0,0,m_Canvas->w(),m_Canvas->h());
-
-    // Establish the model view matrix
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-
-    // Compute the optimal zoom
-    if(m_IsRegistered && m_IsSliceInitialized)
-      {
-      // If the zoom is set to fit, maintain the fit, otherwise, maintain the 
-      // optimal zoom level
-      if(!m_ManagedZoom && m_ViewZoom == m_OptimalZoom)
-        {
-        ComputeOptimalZoom();
-        m_ViewZoom = m_OptimalZoom;
-        }
-      else
-        {
-        ComputeOptimalZoom();
-        }
-      }
-  }
-
-  // Get the properties for the background color
-  Vector3d clrBack = 
-    m_ParentUI->GetAppearanceSettings()->GetUIElement(
-      SNAPAppearanceSettings::BACKGROUND_2D).NormalColor;
-
-  // Clear the display, using a blue shade when under focus
-  glClearColor(clrBack[0],clrBack[1],clrBack[2],1.0);
-  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    
-
-  // Slice should be initialized before display
-  if (!m_IsSliceInitialized) 
-    return;
-
-  // Compute the position of the cross-hairs in display space
-  Vector3ui cursorImageSpace = m_Driver->GetCursorPosition();
-  Vector3f cursorDisplaySpace = 
-    m_ImageToDisplayTransform.TransformPoint(
-      to_float(cursorImageSpace) + Vector3f(0.5f));
-
-  // Get the current slice number
-  m_ImageSliceIndex = cursorImageSpace[m_ImageAxes[2]];
-  m_DisplayAxisPosition = cursorDisplaySpace[2];
-
-  // Set up lighting attributes
-  glPushAttrib(GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT | 
-               GL_PIXEL_MODE_BIT | GL_TEXTURE_BIT );  
-  
-  glDisable(GL_LIGHTING);
-
-  // glDisable(GL_DEPTH);
-
-  // Prepare for overlay drawing.  The model view is set up to correspond
-  // to pixel coordinates of the slice
-  glPushMatrix();
-  glTranslated(0.5 * m_Canvas->w(),0.5 * m_Canvas->h(),0.0);
-  glScalef(m_ViewZoom,m_ViewZoom,1.0);
-  glTranslated(-m_ViewPosition(0),-m_ViewPosition(1),0.0);
-  glScalef(m_SliceSpacing[0],m_SliceSpacing[1],1.0);
-  
-  // Make the grey and segmentation image textures up-to-date
-  DrawMainTexture();
-  DrawOverlayTexture();
-  DrawSegmentationTexture();
-
-  // Draw the overlays
-  if(m_ParentUI->GetAppearanceSettings()->GetOverallVisibility())
-    {
-    DrawOverlays();
-
-    // Draw the zoom locator
-    if(IsThumbnailOn())
-      DrawThumbnail();
-    }
-
-
-  // Clean up the GL state
-  glPopMatrix();
-  glPopAttrib();
-
-  // Draw the little popup button
-  // m_PopupButtonMode->OnDraw();
-
-  // Display!
-  glFlush();
-}
-
-void 
-GenericSliceWindow
-::DrawMainTexture() 
-{
-  // We should have a slice to return
-  assert(m_ImageSliceIndex >= 0);
-
-  if (m_ImageData->IsMainLoaded())
-    {
-    // Get the color to use for background
-    Vector3d clrBackground = m_ThumbnailIsDrawing
-      ? m_ParentUI->GetAppearanceSettings()->GetUIElement(
-          SNAPAppearanceSettings::ZOOM_THUMBNAIL).NormalColor
-      : Vector3d(1.0);
-
-    // Set the interpolation mode to current default
-    m_MainTexture->SetInterpolation(
-      m_ParentUI->GetAppearanceSettings()->GetGreyInterpolationMode()
-      == SNAPAppearanceSettings::LINEAR ? GL_LINEAR : GL_NEAREST);
-
-    // Paint the grey texture with color as background
-    m_MainTexture->Draw(clrBackground);
-    }
-}
-
-void 
-GenericSliceWindow
-::DrawOverlayTexture() 
-{
-  // We should have a slice to return
-  assert(m_ImageSliceIndex >= 0);
-
-  // Get the color to use for background
-  Vector3d clrBackground = m_ThumbnailIsDrawing
-    ? m_ParentUI->GetAppearanceSettings()->GetUIElement(
-        SNAPAppearanceSettings::ZOOM_THUMBNAIL).NormalColor
-    : Vector3d(1.0);
-
-  OverlayTextureIterator textureIt = m_OverlayTextureList.begin();
-  std::list<ImageWrapperBase *>::iterator wrapperIt = m_ImageData->GetOverlays()->begin();
-  while (textureIt != m_OverlayTextureList.end())
-    {
-    // Set the interpolation mode to current default
-    OpenGLSliceTexture *texture = *textureIt;
-    ImageWrapperBase *wrapper = *wrapperIt;
-    texture->SetInterpolation(
-      m_ParentUI->GetAppearanceSettings()->GetGreyInterpolationMode()
-      == SNAPAppearanceSettings::LINEAR ? GL_LINEAR : GL_NEAREST);
-    texture->DrawTransparent(wrapper->GetAlpha());
-    textureIt++;
-    wrapperIt++;
-    }
-}
-
-void 
-GenericSliceWindow
-::DrawSegmentationTexture() 
-{
-  // We should have a slice to return
-  assert(m_ImageSliceIndex >= 0);
-
-  if (m_ImageData->IsSegmentationLoaded())
-    {
-    m_LabelRGBTexture->DrawTransparent(m_GlobalState->GetSegmentationAlpha());
-    }
-}
-
-void
-GenericSliceWindow
-::DrawThumbnail()
-{
-  // Get the thumbnail appearance properties
-  const SNAPAppearanceSettings::Element &elt = 
-    m_ParentUI->GetAppearanceSettings()->GetUIElement(
-      SNAPAppearanceSettings::ZOOM_THUMBNAIL);
-
-  // If thumbnail is not to be drawn, exit
-  if(!elt.Visible) return;
-
-  // Indicate the fact that we are currently drawing in thumbnail mode
-  m_ThumbnailIsDrawing = true;  
-  
-  // The dimensions of the canvas on which we are working, in pixels
-  Vector2i xCanvas( m_Canvas->w(), m_Canvas->h() );
-
-  // The thumbnail will occupy a specified fraction of the target canvas
-  float xFraction = 0.01f * 
-    m_ParentUI->GetAppearanceSettings()->GetZoomThumbnailSizeInPercent();
-
-  // But it must not exceed a predefined size in pixels in either dimension
-  float xThumbMax = 
-    m_ParentUI->GetAppearanceSettings()->GetZoomThumbnailMaximumSize();
-
-  // Recompute the fraction based on maximum size restriction
-  float xNewFraction = xFraction;
-  if( xCanvas[0] * xNewFraction > xThumbMax )
-    xNewFraction = xThumbMax * 1.0f / xCanvas[0];
-  if( xCanvas[1] * xNewFraction > xThumbMax )
-    xNewFraction = xThumbMax * 1.0f / xCanvas[1];
-
-  // Draw the little version of the image in the corner of the window
-  double w = m_SliceSize[0];
-  double h = m_SliceSize[1];
-
-  // Set the position and size of the thumbnail, in pixels
-  m_ThumbnailZoom = xNewFraction * m_OptimalZoom;
-  m_ThumbnailPosition.fill(5);
-  m_ThumbnailSize[0] = (int)(m_SliceSize[0] * m_SliceSpacing[0] * m_ThumbnailZoom);
-  m_ThumbnailSize[1] = (int)(m_SliceSize[1] * m_SliceSpacing[1] * m_ThumbnailZoom);
-  
-  glPushMatrix();
-  glLoadIdentity();
-  glTranslated((double) m_ThumbnailPosition[0], (double) m_ThumbnailPosition[1], 0.0);
-  glScaled(m_ThumbnailZoom, m_ThumbnailZoom, 1.0);
-
-  glPushMatrix();
-  glScalef(m_SliceSpacing[0],m_SliceSpacing[1],1.0);
-  // glTranslated(w * 0.1111, h * 0.1111, 0.0);
-
-  // Draw the Main image (the background will be picked automatically)
-  DrawMainTexture();
- 
-  // Draw the crosshairs and stuff
-  DrawOverlays();
-
-  // Apply the line settings
-  SNAPAppearanceSettings::ApplyUIElementLineSettings(elt);
-
-  // Draw the line around the image
-  glColor3dv(elt.NormalColor.data_block());
-  glBegin(GL_LINE_LOOP);
-  glVertex2d(0,0);
-  glVertex2d(0,h);
-  glVertex2d(w,h);
-  glVertex2d(w,0);
-  glEnd();
-
-  // Draw a box representing the current zoom level
-  glPopMatrix();
-  glTranslated(m_ViewPosition[0],m_ViewPosition[1],0.0);
-  w = m_Canvas->w() * 0.5 / m_ViewZoom;
-  h = m_Canvas->h() * 0.5 / m_ViewZoom;
-
-  glColor3dv(elt.ActiveColor.data_block());
-  glBegin(GL_LINE_LOOP);
-  glVertex2d(-w,-h);
-  glVertex2d(-w, h);
-  glVertex2d( w, h);
-  glVertex2d( w,-h);
-  glEnd();
-
-  glPopMatrix();
-
-  // Indicate the fact that we are not drawing in thumbnail mode
-  m_ThumbnailIsDrawing = false;  
-}
-
-void 
-GenericSliceWindow
-::DrawOverlays() 
-{
-  if(!m_ThumbnailIsDrawing) 
-    {
-    // Display the letters (RAI)
-    DrawOrientationLabels();
-
-    // Display the rulers
-    DrawRulers();
-
-    // Draw the zoom mode (does't really draw, repaints a UI widget)
-    m_NavigationMode->OnDraw();
-    }
-
-  m_NavigationMode->OnDraw();
-}
-
-void 
-GenericSliceWindow
-::DrawOrientationLabels()
-{
-  // The letter labels
-  static const char *letters[3][2] = {{"R","L"},{"A","P"},{"I","S"}};
-  const char *labels[2][2];
-
-  // Get the properties for the labels
-  const SNAPAppearanceSettings::Element &elt = 
-    m_ParentUI->GetAppearanceSettings()->GetUIElement(
-      SNAPAppearanceSettings::MARKERS);
-
-  // Leave if the labels are disabled
-  if(!elt.Visible) return;
-
-  // Repeat for X and Y directions
-  for(unsigned int i=0;i<2;i++) 
-    {
-    // Which axis are we on in anatomy space?
-    unsigned int anatomyAxis = 
-      m_DisplayToAnatomyTransform.GetCoordinateIndexZeroBased(i);
-
-    // Which direction is the axis facing (returns -1 or 1)
-    unsigned int anatomyAxisDirection = 
-      m_DisplayToAnatomyTransform.GetCoordinateOrientation(i);
-
-    // Map the direction onto 0 or 1
-    unsigned int letterIndex = (1 + anatomyAxisDirection) >> 1;
-
-    // Compute the two labels for this axis
-    labels[i][0] = letters[anatomyAxis][1-letterIndex];
-    labels[i][1] = letters[anatomyAxis][letterIndex];
-    }
-
-  glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
-  glPushMatrix();
-  glLoadIdentity();
-
-  if(elt.AlphaBlending)
-    {
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    }
-
-  glColor4d( elt.NormalColor[0], elt.NormalColor[1], elt.NormalColor[2], 1.0 );
-
-  gl_font(FL_COURIER_BOLD, elt.FontSize);
-  int offset = 4 + elt.FontSize * 2;
-  int margin = elt.FontSize / 3;
-  int w = m_Canvas->w(), h = m_Canvas->h();
-
-  gl_draw(labels[0][0],margin,0,offset,h,FL_ALIGN_LEFT);
-  gl_draw(labels[0][1],w - (offset+margin),0,offset,h,FL_ALIGN_RIGHT);
-  gl_draw(labels[1][0],0,0,w,offset,FL_ALIGN_BOTTOM);
-  gl_draw(labels[1][1],0,h - (offset+1),w,offset,FL_ALIGN_TOP);
-
-
-  glPopMatrix();
-  glPopAttrib();
-}
-
-void
-GenericSliceWindow
-::DrawRulers()
-{
-  // Get the properties for the labels
-  const SNAPAppearanceSettings::Element &elt = 
-    m_ParentUI->GetAppearanceSettings()->GetUIElement(
-      SNAPAppearanceSettings::RULER);
-
-  // Leave if the labels are disabled
-  if(!elt.Visible) return;  
-
-  glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
-  glPushMatrix();
-  glLoadIdentity();
-  
-  SNAPAppearanceSettings::ApplyUIElementLineSettings(elt);
-  glColor4d( elt.NormalColor[0], elt.NormalColor[1], elt.NormalColor[2], 1.0 );
-  gl_font(FL_HELVETICA, elt.FontSize);
-
-  // Pick the scale of the ruler 
-  int w = m_Canvas->w(), h = m_Canvas->h();
-
-  // The ruler bar should be as large as possible but less than one half
-  // of the screen width (not to go over the markers)
-  double maxw = 0.5 * w - 20.0;
-  maxw = maxw < 5 ? 5 : maxw;
-
-  double scale = 1.0;
-  while(m_ViewZoom * scale > maxw) scale /= 10.0;
-  while(m_ViewZoom * scale < 0.1 * maxw) scale *= 10.0;
-
-  // Draw a zoom bar
-  double bw = scale * m_ViewZoom;
-  glBegin(GL_LINES);
-  glVertex2d(5,h - 5);
-  glVertex2d(5,h - 20);
-  glVertex2d(5,h - 10);
-  glVertex2d(5 + bw,h - 10);
-  glVertex2d(5 + bw,h - 5);
-  glVertex2d(5 + bw,h - 20);
-  glEnd();
-
-  // Based on the log of the scale, determine the unit
-  string unit = "mm";
-  if(scale >= 10 && scale < 1000)
-    { unit = "cm"; scale /= 10; }
-  else if(scale >= 1000)
-    { unit = "m"; scale /= 1000; }
-  else if(scale < 1 && scale > 0.001)
-    { unit = "\xb5m"; scale *= 1000; }
-  else if(scale < 0.001)
-    { unit = "nm"; scale *= 1000000; }
-
-  ostringstream oss;
-  oss << scale << " " << unit;
-
-  // See if we can squeeze the label under the ruler
-  if(bw > elt.FontSize * 4)
-    gl_draw(oss.str().c_str(), 10, h - 30, (int) bw, 20, FL_ALIGN_TOP);
-  else
-    gl_draw(oss.str().c_str(), (int) bw+10, h - 20, (int) bw + elt.FontSize * 4+10, 15, FL_ALIGN_LEFT);
-
-
-  glPopMatrix();
-  glPopAttrib();
-}
-
-void 
-GenericSliceWindow
-::EnterInteractionMode(InteractionMode *mode)
-{
-  // Empty the stack
-  ClearInteractionStack();
-
-  // Push the crosshairs mode - last to get events
-  if(mode != m_NavigationMode)
-    {
-    // Navigation mode serves as a fallback, allowing crosshair editing with middle button
-    m_NavigationMode->SetInteractionStyle(
-      CrosshairsInteractionMode::ANY,
-      CrosshairsInteractionMode::NONE, 
-      CrosshairsInteractionMode::NONE);
-
-    PushInteractionMode(m_NavigationMode);
-    }
-
-  // Push the input mode
-  PushInteractionMode(mode);
-
-  // Push the thumbnail mode
-  PushInteractionMode(m_ThumbnailMode);
-
-  // Push the popup mode
-  // PushInteractionMode(m_PopupButtonMode);
-}
-  
-void 
-GenericSliceWindow
-::EnterCrosshairsMode()
-{
-  m_NavigationMode->SetInteractionStyle(
-    CrosshairsInteractionMode::LEFT,
-    CrosshairsInteractionMode::RIGHT, 
-    CrosshairsInteractionMode::MIDDLE);
-
-  EnterInteractionMode(m_NavigationMode);
-}
-
-void 
-GenericSliceWindow
-::EnterZoomPanMode()
-{
-  m_NavigationMode->SetInteractionStyle(
-    CrosshairsInteractionMode::MIDDLE,
-    CrosshairsInteractionMode::RIGHT, 
-    CrosshairsInteractionMode::LEFT);
-
-  EnterInteractionMode(m_NavigationMode);
-}
-
-void
-GenericSliceWindow
-::ResetViewPosition()
-{
-  // Compute slice size in spatial coordinates
-  Vector2f worldSize(
-    m_SliceSize[0] * m_SliceSpacing[0],
-    m_SliceSize[1] * m_SliceSpacing[1]);
-
-  // Set the view position (position of the center of the image?)
-  m_ViewPosition = worldSize * 0.5f;
-
-  m_Canvas->redraw();
-}
-
-void
-GenericSliceWindow
-::SetViewPositionRelativeToCursor(Vector2f offset)
-{
-  // Get the crosshair position
-  Vector3ui xCursorInteger = m_Driver->GetCursorPosition();
-
-  // Shift the cursor position by by 0.5 in order to have it appear
-  // between voxels
-  Vector3f xCursorImage = to_float(xCursorInteger) + Vector3f(0.5f);
-  
-  // Get the cursor position on the slice
-  Vector3f xCursorSlice = MapImageToSlice(xCursorImage);
-
-  // Subtract from the view position
-  Vector2f vp;
-  vp[0] = offset[0] + xCursorSlice[0] * m_SliceSpacing[0];
-  vp[1] = offset[1] + xCursorSlice[1] * m_SliceSpacing[1];
-  SetViewPosition(vp);
-}
-
-Vector2f 
-GenericSliceWindow
-::GetViewPositionRelativeToCursor()
-{
-  // Get the crosshair position
-  Vector3ui xCursorInteger = m_Driver->GetCursorPosition();
-
-  // Shift the cursor position by by 0.5 in order to have it appear
-  // between voxels
-  Vector3f xCursorImage = to_float(xCursorInteger) + Vector3f(0.5f);
-  
-  // Get the cursor position on the slice
-  Vector3f xCursorSlice = MapImageToSlice(xCursorImage);
-
-  // Subtract from the view position
-  Vector2f offset;
-  offset[0] = m_ViewPosition[0] - xCursorSlice[0] * m_SliceSpacing[0];
-  offset[1] = m_ViewPosition[1] - xCursorSlice[1] * m_SliceSpacing[1];
-
-  return offset;
-}
-
-void 
-GenericSliceWindow
-::SetViewZoom(float newZoom)
-{
-  // Update the zoom
-  m_ViewZoom = newZoom;  
-
-  // Repaint the window
-  m_Canvas->redraw();
-}
-
-GenericSliceWindow *
-GenericSliceWindow
-::GetNextSliceWindow()
-{
-  SliceWindowCoordinator *swc = m_ParentUI->GetSliceCoordinator();
-  return swc->GetWindow( (m_Id+1) % 3);
-}
-
-bool
-GenericSliceWindow
-::IsThumbnailOn()
-{ 
-  return m_ParentUI->GetAppearanceSettings()->GetFlagDisplayZoomThumbnail() 
-    && m_ViewZoom > m_OptimalZoom; 
-}
-
-GenericSliceWindow::EventHandler
-::EventHandler(GenericSliceWindow *parent) 
-: InteractionMode(parent->GetCanvas())
-{
-  m_Parent = parent;
-}
-
-void 
-GenericSliceWindow::EventHandler
-::Register() 
-{
-  m_Driver = m_Parent->m_Driver;
-  m_ParentUI = m_Parent->m_ParentUI;
-  m_GlobalState = m_Parent->m_GlobalState;
-}
-
-#include <itksys/SystemTools.hxx>
-
-int
-GenericSliceWindow::OnDragAndDrop(const FLTKEvent &event)
-{
-  // Check if it is a real file
-  if(event.Id == FL_PASTE)
-    {
-    if(itksys::SystemTools::FileExists(Fl::event_text(), true))
-      {
-      m_ParentUI->OpenDraggedContent(Fl::event_text(), true);
-      return 1;
-      }
-    return 0;
-    }
-  else
-    return 1;
-}
-
diff --git a/UserInterface/SliceWindow/GenericSliceWindow.h b/UserInterface/SliceWindow/GenericSliceWindow.h
deleted file mode 100644
index 9223063..0000000
--- a/UserInterface/SliceWindow/GenericSliceWindow.h
+++ /dev/null
@@ -1,361 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: GenericSliceWindow.h,v $
-  Language:  C++
-  Date:      $Date: 2010/10/12 17:57:11 $
-  Version:   $Revision: 1.28 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __GenericSliceWindow_h_
-#define __GenericSliceWindow_h_
-
-#if defined(_MSC_VER)
-#pragma warning ( disable : 4786 )
-#pragma warning ( disable : 4503 )
-#endif
-
-#include "FLTKCanvas.h"
-#include "SNAPCommonUI.h"
-#include "GreyImageWrapper.h"
-#include "RGBImageWrapper.h"
-#include "LabelImageWrapper.h"
-#include "RecursiveInteractionMode.h"
-
-// Forward references to parent classes
-class IRISApplication;
-class GenericImageData;
-class GlobalState;
-class UserInterfaceBase;  
-
-// Forward references to interaction modes that work with this window
-class CrosshairsInteractionMode;
-class ThumbnailInteractionMode;
-class PopupButtonInteractionMode;
-
-// Forward reference to Gl texture object
-class OpenGLSliceTexture;
-
-
-/**
- * \class GenericSliceWindow
- * \brief A window used to display a 2D slice either in SNAP or in IRIS mode.
- *
- * A generic slice window, that is neither fitted to IRIS nor to SNAP.  The
- * IRIS and SNAP windows are children of this slice window class.  This class
- * provides support for display space to image space transforms, for texture
- * display and management, and for interaction mode plugins.
- *
- * The generic window supports two types of interaction modes: crosshairs mode
- * and zoom/pan mode.  
- */
-class GenericSliceWindow : public RecursiveInteractionMode
-{
-public:
-
-  /**
-   * Register the window with its parent UI.  This method assigns an Id to 
-   * the window, which is equal to the coordinate direction in display space
-   * along which the window displays slices.
-   */
-  GenericSliceWindow(int id, UserInterfaceBase *parentUI, FLTKCanvas *inWindow);
-  virtual ~GenericSliceWindow();
-
-  /** Enter the cross-hairs mode of operation */
-  virtual void EnterCrosshairsMode();
-  
-  /** Enter the zoom/pan mode of operation */
-  virtual void EnterZoomPanMode();
-
-  /**
-   * Initialize the window's attributes (size, view position, etc.)
-   * This method should called when the image dimensions and transforms
-   * get updated.
-   */
-  virtual void InitializeSlice(GenericImageData *imageData);
-  virtual void InitializeOverlaySlice(GenericImageData *imageData);
-
-  /**
-   * Reset the view parameters of the window (zoom, view position) to
-   * defaults
-   */
-  virtual void ResetViewToFit();
-
-  /** The FLTK draw method (paints the window) */
-  void OnDraw();
-
-  /** Respond to drag and drop events */
-  int OnDragAndDrop(const FLTKEvent &event);
-
-  /**
-   * Map a point in window coordinates to a point in slice coordinates
-   * (Window coordinates are the ones stored in FLTKEvent.xSpace)
-   */
-  Vector3f MapWindowToSlice(const Vector2f &xWindow); 
-  
-  /**
-   * Map a point in slice coordinates to a point in window coordinates
-   * (Window coordinates are the ones stored in FLTKEvent.xSpace)
-   */
-  Vector2f MapSliceToWindow(const Vector3f &xSlice);
-  
-  /**
-   * Map a point in slice coordinates to a point in PHYISCAL window coordinates
-   */
-  Vector2f MapSliceToPhysicalWindow(const Vector3f &xSlice);
-
-  /**
-   * Map a point in slice coordinates to a point in the image coordinates
-   */
-  Vector3f MapSliceToImage(const Vector3f &xSlice);
-
-  /**
-   * Map a point in image coordinates to slice coordinates
-   */
-  Vector3f MapImageToSlice(const Vector3f &xImage);
-
-  /** Return the image axis along which this window shows slices */
-  size_t GetSliceDirectionInImageSpace()
-    { return m_ImageAxes[2]; }
-
-  /** Reset the view position to center of the image */
-  void ResetViewPosition ();
-
-  /** Set the zoom factor (number of pixels on the screen per millimeter in
-   * image space */
-  void SetViewZoom(float newZoom);
-
-  /** Return the offset from the center of the viewport to the cursor position
-   * in slice units (#voxels * spacing). This is used to synchronize panning
-   * across SNAP sessions */
-  Vector2f GetViewPositionRelativeToCursor();
-
-  /** Set the offset from the center of the viewport to the cursor position */
-  void SetViewPositionRelativeToCursor(Vector2f offset);
-
-
-  /** Get the zoom factor (number of pixels on the screen per millimeter in
-   * image space */
-  irisGetMacro(ViewZoom,float);
-
-  /** Compute the optimal zoom (best fit) */
-  irisGetMacro(OptimalZoom,float);
-
-  /** Set the zoom management flag */
-  irisSetMacro(ManagedZoom,bool);
-
-  /** Set the view position **/
-  irisSetMacro(ViewPosition, Vector2f);
-
-  /** Get the view position **/
-  irisGetMacro(ViewPosition, Vector2f);
-
-  /** Get the slice spacing in the display space orientation */
-  irisGetMacro(SliceSpacing,Vector3f);
-
-  /** Get the slice spacing in the display space orientation */
-  irisGetMacro(SliceSize,Vector3i);
-
-  irisGetMacro(Id, int);
-  irisGetMacro(ParentUI, UserInterfaceBase *); 
-
-  /** Compute the canvas size needed to display slice at current zoom factor */
-  Vector2i GetOptimalCanvasSize();
-  
-  /**
-   * A parent class from which all the Fl event handlers associated
-   * with this class should be derived
-   */
-  class EventHandler : public InteractionMode {
-  public:
-    EventHandler(GenericSliceWindow *parent);
-    void Register();
-
-  protected:
-    GenericSliceWindow *m_Parent;
-    GlobalState *m_GlobalState;
-    UserInterfaceBase *m_ParentUI;
-    IRISApplication *m_Driver;
-  };
-
-  // Allow friendly access by interactors
-  friend class EventHandler;
-  friend class BubblesInteractionMode;
-  friend class CrosshairsInteractionMode;
-  friend class RegionInteractionMode;
-  friend class PolygonInteractionMode;
-  friend class ThumbnailInteractionMode;
-  friend class PaintbrushInteractionMode;
-  friend class AnnotationInteractionMode;
-
-protected:
-
-  /** Pointer to the application driver for this UI object */
-  IRISApplication *m_Driver;
-
-  /** Pointer to the global state object (shorthand) */
-  GlobalState *m_GlobalState;
-
-  /** Pointer to GUI that contains this Window3D object */
-  UserInterfaceBase *m_ParentUI;   
-
-  /** The image data object that is displayed in this window */
-  GenericImageData *m_ImageData;
-
-  /** Interaction mode used to position the crosshairs (navigation mode) */
-  CrosshairsInteractionMode *m_NavigationMode;
-
-  /** Interaction mode used to control the zoom thumbnail. This mode is always
-   * on and at the top of the interaction stack */
-  ThumbnailInteractionMode *m_ThumbnailMode;
-
-  /** Interaction mode used to bring up a popup menu */
-  PopupButtonInteractionMode *m_PopupButtonMode;
-
-  /** Whether or not we have been registered with the parent UI */
-  bool m_IsRegistered;
-
-  /** 
-   * Whether or not the sizes have been initialized 
-   * (synched with the image data)
-   */
-  bool m_IsSliceInitialized;
-
-  // Window id, equal to the direction in display space along which the window
-  // shows slices
-  int m_Id;       
-
-  // Current slice number in image coordinates 
-  int m_ImageSliceIndex;
-
-  // The position of the slice on its z-axis, in the display coordinate space
-  float m_DisplayAxisPosition;
-
-  // The index of the image space axes corresponding to the u,v,w of the window
-  // (computed by applying a transform to the DisplayAxes)
-  int m_ImageAxes[3]; 
-
-  // The transform from image coordinates to display coordinates
-  ImageCoordinateTransform m_ImageToDisplayTransform;
-  
-  // The transform from display coordinates to image coordinates
-  ImageCoordinateTransform m_DisplayToImageTransform;
-
-  // The transform from display coordinates to patient coordinates
-  ImageCoordinateTransform m_DisplayToAnatomyTransform;
-
-  // Dimensions of the current slice (the third component is the size of the
-  // image in the slice direction)
-  Vector3i m_SliceSize;             
-
-  // Pixel dimensions for the slice.  (the thirs component is the pixel width
-  // in the slice direction)
-  Vector3f m_SliceSpacing;
-  
-  // Position of visible window in slice space coordinates
-  Vector2f m_ViewPosition;            
-
-  // The number of screen pixels per mm of image
-  float m_ViewZoom;  
-
-  // The zoom level at which the slice fits snugly into the window
-  float m_OptimalZoom;
-
-  // Flag indicating whether the window's zooming is managed externally by
-  // the SliceWindowCoordinator
-  bool m_ManagedZoom;
-
-  // The default screen margin (area into which we do not paint) at lest in 
-  // default zoom
-  unsigned int m_Margin;
-
-  // Main image texture object
-  OpenGLSliceTexture *m_MainTexture;
-
-  // Overlay texture objects
-  typedef std::list<OpenGLSliceTexture *> OverlayTextureList;
-  typedef OverlayTextureList::iterator OverlayTextureIterator;
-  typedef OverlayTextureList::const_iterator OverlayTextureConstIterator;
-  OverlayTextureList m_OverlayTextureList;
-
-  // Label texture object
-  OpenGLSliceTexture *m_LabelRGBTexture;
-
-  // Check whether the thumbnail should be draw or not
-  bool IsThumbnailOn();
-
-  // The position and size of the zoom thumbnail
-  Vector2i m_ThumbnailPosition, m_ThumbnailSize;
-
-  // Whether or not the thumbnail is being drawn at the moment
-  bool m_ThumbnailIsDrawing;
-
-  // The zoom level in the thumbnail
-  double m_ThumbnailZoom;
-
-  // Computes the zoom that gives the best fit for the window
-  void ComputeOptimalZoom();
-
-  // This method is called in draw() to paint the Main image slice
-  virtual void DrawMainTexture();
-
-  // This method is called in draw() to paint the overlay slice
-  virtual void DrawOverlayTexture();
-
-  // This method is called in draw() to paint the segmentation slice
-  virtual void DrawSegmentationTexture();
-
-  // This method is called after the grey and segmentation images have
-  // been drawn.  It calls the draw method of each of the interaction modes
-  virtual void DrawOverlays();
-
-  /** This method draws the RAI labels at the four sides of the slice */
-  void DrawOrientationLabels();
-
-  /** Draw a ruler for seeing distances on the screen */
-  void DrawRulers();
-
-  /** Draw a window that shows where in the image the zoom region is located */
-  void DrawThumbnail();
-
-  /** Access the next window in the slice pipeline */
-  GenericSliceWindow *GetNextSliceWindow();
-
-  /** Activate a given interaction mode */
-  virtual void EnterInteractionMode(InteractionMode *mode);
-};
-
-#endif // __GenericSliceWindow_h_
diff --git a/UserInterface/SliceWindow/IRISSliceWindow.cxx b/UserInterface/SliceWindow/IRISSliceWindow.cxx
deleted file mode 100644
index dac02ba..0000000
--- a/UserInterface/SliceWindow/IRISSliceWindow.cxx
+++ /dev/null
@@ -1,300 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: IRISSliceWindow.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/06/28 18:45:08 $
-  Version:   $Revision: 1.11 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "IRISSliceWindow.h"
-
-#include "GlobalState.h"
-#include "OpenGLSliceTexture.h"
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-#include "UserInterfaceBase.h"
-#include "AnnotationInteractionMode.h"
-#include "CrosshairsInteractionMode.h"
-#include "PolygonInteractionMode.h"
-#include "PaintbrushInteractionMode.h"
-#include "RegionInteractionMode.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <cstdlib>
-#include <cmath>
-#include <iostream>
-
-#include "itkOrientedImage.h"
-#include "itkImageRegionIteratorWithIndex.h"
-
-using namespace std;
-
-IRISSliceWindow
-::IRISSliceWindow(int id, UserInterfaceBase *parentUI, FLTKCanvas *canvas) 
-: GenericSliceWindow(id, parentUI, canvas)
-{
-  // Initialize the interaction modes
-  m_PolygonMode = new PolygonInteractionMode(this);
-  m_RegionMode = new RegionInteractionMode(this);
-  m_PaintbrushMode = new PaintbrushInteractionMode(this);
-  m_AnnotationMode = new AnnotationInteractionMode(this);
-
-  // Get a pointer to the drawing object
-  m_PolygonDrawing = m_PolygonMode->m_Drawing;
-  m_PolygonDrawing->SetFreehandFittingRate(parentUI->GetFreehandFittingRate());
-
-  // Initialize polygon slice canvas to NULL
-  m_PolygonSlice = NULL;
-
-  // Register the interaction modes
-  m_PolygonMode->Register();
-  m_RegionMode->Register();
-  m_PaintbrushMode->Register();
-  m_AnnotationMode->Register();
-
-}
-
-IRISSliceWindow
-::~IRISSliceWindow()
-{
-  delete m_PolygonMode;
-  delete m_RegionMode;
-  delete m_AnnotationMode;
-  delete m_PaintbrushMode;
-}
-
-void 
-IRISSliceWindow
-::InitializeSlice(GenericImageData *imageData)
-{
-  // Call the parent's version of this method
-  GenericSliceWindow::InitializeSlice(imageData);
-  if(!imageData->IsMainLoaded())
-	return;
-
-  // Reset the polygon drawing interface
-  m_PolygonDrawing->Reset();
-
-  // Initialize the polygon drawing canvas
-  itk::Size<2> imgSize;
-  imgSize[0] = m_SliceSize(0);
-  imgSize[1] = m_SliceSize(1);
-  m_PolygonSlice = PolygonSliceType::New();
-  m_PolygonSlice->SetRegions(imgSize);
-  m_PolygonSlice->Allocate();
-}
-
-void
-IRISSliceWindow
-::DrawOverlays()
-{
-  // Call the parent's version of this method
-  GenericSliceWindow::DrawOverlays();
-
-  // Draw the polygon
-  if(!m_ThumbnailIsDrawing)
-    m_PolygonMode->OnDraw();
-
-  // Draw the region of interest if selected
-  if(IsInteractionModeAdded(m_RegionMode))
-    m_RegionMode->OnDraw();
-
-  // Draw the paintbrush stuff if selected
-  if(IsInteractionModeAdded(m_PaintbrushMode) && !m_ThumbnailIsDrawing)
-    m_PaintbrushMode->OnDraw();
-
-  // Always draw annotations, whether active or not - but not in the thumbnail
-  if(!m_ThumbnailIsDrawing)
-    m_AnnotationMode->OnDraw();
-}
-
-void 
-IRISSliceWindow
-::EnterPolygonMode()
-{
-  EnterInteractionMode(m_PolygonMode);
-}
-
-void 
-IRISSliceWindow
-::EnterPaintbrushMode()
-{
-  EnterInteractionMode(m_PaintbrushMode);
-}
-
-void 
-IRISSliceWindow
-::EnterAnnotationMode()
-{
-  EnterInteractionMode(m_AnnotationMode);
-}
-
-void 
-IRISSliceWindow
-::EnterRegionMode()
-{
-  EnterInteractionMode(m_RegionMode);
-}
-
-bool 
-IRISSliceWindow
-::AcceptPolygon() 
-{
-  assert(m_IsRegistered && m_IsSliceInitialized);
-
-  // Make sure we are in editing mode
-  if (m_PolygonDrawing->GetState() != PolygonDrawing::EDITING_STATE) 
-    return false;
-
-#ifdef DRAWING_LOCK
-  if (m_GlobalState->GetDrawingLock(id)) {
-#endif /* DRAWING_LOCK */
-
-    // VERY IMPORTANT - makes GL state current!
-    m_Canvas->make_current(); 
-
-    // Have the polygon drawing object render the polygon slice
-    m_PolygonDrawing->AcceptPolygon(m_PolygonSlice);
-      
-    // take polygon rendered by polygon_drawing and merge with 
-    // segmentation slice; send changes to voxel data set
-    LabelType drawing_color = m_GlobalState->GetDrawingColorLabel();
-    LabelType overwrt_color = m_GlobalState->GetOverWriteColorLabel();
-    CoverageModeType mode = m_GlobalState->GetCoverageMode();
-
-    // Get the current slice from the segmentation image
-    LabelImageWrapper *seg = 
-        m_Driver->GetCurrentImageData()->GetSegmentation();
-    LabelImageWrapper::SlicePointer slice = seg->GetSlice(m_Id);
-    slice->Update();
-
-    // Create an iterator to iterate over the slice
-    typedef itk::ImageRegionIteratorWithIndex<PolygonSliceType> PolygonIterator;
-    PolygonIterator itPolygon(m_PolygonSlice,
-                              m_PolygonSlice->GetLargestPossibleRegion());
-
-    // Keep track of the number of pixels changed
-    unsigned int nUpdates = 0;
-
-    // Iterate
-    for (itPolygon.Begin(); !itPolygon.IsAtEnd(); ++itPolygon)
-    {
-      // Get the current polygon pixel      
-      PolygonSliceType::PixelType pxPolygon = itPolygon.Get();
-      
-      // Check for non-zero alpha of the pixel
-      if((pxPolygon != 0) ^  m_GlobalState->GetPolygonInvert())
-        {
-        // Get the corresponding segmentation image pixel
-        itk::Index<2> idx = itPolygon.GetIndex();
-        LabelType pxLabel = slice->GetPixel(idx);
-
-        // Check if we should be overriding that pixel
-        if (mode == PAINT_OVER_ALL ||
-            (mode == PAINT_OVER_ONE && pxLabel == overwrt_color) ||
-            (mode == PAINT_OVER_COLORS && pxLabel != 0))
-          {
-          // Get the index into the image that we'll be updating
-          Vector3f idxImageFloat = 
-            MapSliceToImage(Vector3f(idx[0]+0.5f,idx[1]+0.5f,m_DisplayAxisPosition));
-
-          // Convert to integer
-          Vector3ui idxImage = to_unsigned_int(idxImageFloat);
-          
-          // Set the value of the pixel in segmentation image
-          m_Driver->GetCurrentImageData()->SetSegmentationVoxel(
-            idxImage, drawing_color);
-
-          // Increment the counter
-          nUpdates++;
-          }
-        }
-      }
-
-#ifdef DRAWING_LOCK
-    m_GlobalState->ReleaseDrawingLock(m_Id);
-  }
-#endif /* DRAWING_LOCK */
-
-  return (nUpdates > 0);
-}
-
-void 
-IRISSliceWindow
-::PastePolygon()
-{
-  assert(m_IsRegistered && m_IsSliceInitialized);
-
-#ifdef DRAWING_LOCK
-  if (m_GlobalState->GetDrawingLock(m_Id)) 
-    {
-#endif /* DRAWING_LOCK */
-
-    if (m_PolygonDrawing->GetCachedPolygon()) 
-      {
-      m_PolygonDrawing->PastePolygon();
-      m_Canvas->redraw();
-      }
-
-#ifdef DRAWING_LOCK
-    } 
-  else 
-    {
-    m_GlobalState->ReleaseDrawingLock(m_Id);
-    }
-#endif /* DRAWING_LOCK */
-}
-
-void 
-IRISSliceWindow
-::ClearPolygon()
-{
-  m_PolygonDrawing->Delete();
-  m_Canvas->redraw();
-}
-
-void 
-IRISSliceWindow
-::DeleteSelectedPolygonPoints()
-{
-  m_PolygonDrawing->Delete();
-  m_Canvas->redraw();
-}
-
-void 
-IRISSliceWindow
-::InsertPolygonPoints()
-{
-  m_PolygonDrawing->Insert();
-  m_Canvas->redraw();
-}
-
-
-
diff --git a/UserInterface/SliceWindow/IRISSliceWindow.h b/UserInterface/SliceWindow/IRISSliceWindow.h
deleted file mode 100644
index 0978279..0000000
--- a/UserInterface/SliceWindow/IRISSliceWindow.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: IRISSliceWindow.h,v $
-  Language:  C++
-  Date:      $Date: 2009/10/26 16:00:56 $
-  Version:   $Revision: 1.7 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __IRISSliceWindow_h_
-#define __IRISSliceWindow_h_
-
-#include "GenericSliceWindow.h"
-#include "PolygonDrawing.h"
-
-// Forward references to interaction modes that work with this window
-class PolygonInteractionMode;
-class RegionInteractionMode;
-class PaintbrushInteractionMode;
-class AnnotationInteractionMode;
-
-/**
- * \class IRISSliceWindow
- * \brief 2D slice window used in the IRIS part of the application.
- * 
- * These windows allow polygon editing and region of interest selection.
- */
-class IRISSliceWindow : public GenericSliceWindow 
-{
-public:
-  
-  IRISSliceWindow(int id, UserInterfaceBase *parentUI, FLTKCanvas *canvas);
-  virtual ~IRISSliceWindow();
-
-  /** Enter the polygon editing mode of operation */
-  void EnterPolygonMode();
-
-  /** Enter the region of interest mode of operation */
-  void EnterRegionMode();
-
-  /** Enter the paintbrush mode of operation */
-  void EnterPaintbrushMode();
-
-  /** Enter the annotation mode of operation */
-  void EnterAnnotationMode();
-
-  /**
-   * The initialize method extends the parent's version, sets up some 
-   * polygon drawing attributes
-   */
-  void InitializeSlice(GenericImageData *imageData);
-
-  /**
-   * CachedPolygon()
-   *
-   * purpose:
-   * returns the m_CachedPolygon flag of the polygon drawing object
-   *
-   * post:
-   * return value is 1 if polygon drawing has a cached polygon, 0 otherwise
-   */
-  int  CachedPolygon();
-
-  /**
-   * AcceptPolygon()
-   *
-   * purpose:
-   * the gui calls this when the user presses the accept polygon button; this
-   * means the polygon that was being edited will be rasterized into the voxel
-   * data set according to the current drawing color and painting mode
-   *
-   * pre:
-   * Register() and InitializeSlice() have been called
-   * vox data has data with extents matching this window's width and height
-   *
-   * post:
-   * if drawing lock held and polygon_drawing state was EDITING_STATE,
-   *   voxels interior to polygon and "writable" are set with the current 
-   *   color obtained from m_GlobalState->GetDrawingColor(); the three coverage
-   *   modes determine which voxels inside the polygon are written over:
-   *   PAINT_OVER_ALL:    all voxels
-   *   PAINT_OVER_COLORS: all voxels that aren't labeled clear
-   *   PAINT_OVER_ONE:    all voxels of the color obtained from
-   *                      m_GlobalState->GetOverWriteColor()
-   *   drawing lock released and polygon_drawing state is INACTIVE_STATE
-   * else state not changed.
-   */
-  bool AcceptPolygon();
-
-  /**
-   * PastePolygon()
-   *
-   * purpose:
-   * brings the last drawn polygon back for reuse
-   *
-   * pre:
-   * Register() and InitializeSlice() have been called
-   *
-   * post:
-   * if polygon drawing state previously INACTIVE_STATE, drawing lock
-   * obtainable, & polygon_drawing has a cached polygon,
-   *   cached polygon becomes the edited polygon,
-   *   polygon drawing state is EDITING_STATE
-   *   drawing lock is held
-   * else state does not change
-   */
-  void PastePolygon();
-  
-  /** Clear the polygon currently being edited */
-  void ClearPolygon();
-
-  /** Delete currently selected polygon points */
-  void DeleteSelectedPolygonPoints();
-
-  /** Insert points between selected polygon points */
-  void InsertPolygonPoints();
-
-  /** Set the rate at which freehand is converted to polygons */
-  void SetFreehandFittingRate(double rate)
-    { 
-    m_PolygonDrawing->SetFreehandFittingRate(rate);
-    }
-
-  /** Get the polygon drawing object */
-  irisGetMacro(PolygonDrawing,PolygonDrawing *);
-
-  // Allow friendly access by interactors
-  friend class RegionInteractionMode;
-
-protected:
-
-  /** Interaction mode used to select the region of interest */
-  RegionInteractionMode *m_RegionMode;
-
-  /** Interaction mode used to position the crosshairs */
-  PolygonInteractionMode *m_PolygonMode;
-
-  /** Interaction mode for paintbrush tools */
-  PaintbrushInteractionMode *m_PaintbrushMode;
-
-  /** Annotation mode */
-  AnnotationInteractionMode *m_AnnotationMode;
-
-  /** polygon drawing object */
-  PolygonDrawing *m_PolygonDrawing;
-
-  // Type definition for the slice used for polygon rendering
-  typedef itk::Image<unsigned char,2> PolygonSliceType;
-  typedef itk::SmartPointer<PolygonSliceType> PolygonSlicePointer;
-  
-  /** Slice used for polygon drawing and merging */
-  PolygonSlicePointer m_PolygonSlice;
-
-  /** Draw the region and polygon interactors */
-  void DrawOverlays();
-};
-
-#endif
-
-
diff --git a/UserInterface/SliceWindow/OpenGLSliceTexture.cxx b/UserInterface/SliceWindow/OpenGLSliceTexture.cxx
deleted file mode 100755
index 02f23e3..0000000
--- a/UserInterface/SliceWindow/OpenGLSliceTexture.cxx
+++ /dev/null
@@ -1,238 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: OpenGLSliceTexture.cxx,v $
-  Language:  C++
-  Date:      $Date: 2009/08/25 19:44:25 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "OpenGLSliceTexture.h"
-
-
-OpenGLSliceTexture
-::OpenGLSliceTexture()
-{
-  // Set to -1 to force a call to 'generate'
-  m_IsTextureInitalized = false;
-
-  // Set the update time to -1
-  m_UpdateTime = 0;
-
-  // Init the GL settings to uchar, luminance defautls, which are harmless
-  m_GlComponents = 1;
-  m_GlFormat = GL_LUMINANCE;
-  m_GlType = GL_UNSIGNED_BYTE;
-  m_InterpolationMode = GL_NEAREST;
-
-  // Initialize the buffer pointer
-  m_Buffer = NULL;
-}
-
-OpenGLSliceTexture
-::OpenGLSliceTexture(GLuint components, GLenum format)
-{
-  // Set to -1 to force a call to 'generate'
-  m_IsTextureInitalized = false;
-
-  // Set the update time to -1
-  m_UpdateTime = 0;
-
-  // Init the GL settings to uchar, luminance defautls, which are harmless
-  m_GlComponents = components;
-  m_GlFormat = format;
-  m_GlType = GL_UNSIGNED_BYTE;
-  m_InterpolationMode = GL_NEAREST;
-
-  // Initialize the buffer pointer
-  m_Buffer = NULL;
-}
-
-OpenGLSliceTexture
-::~OpenGLSliceTexture()
-{
-  if(m_IsTextureInitalized)
-    glDeleteTextures(1,&m_TextureIndex);
-}
-
-void
-OpenGLSliceTexture
-::SetInterpolation(GLenum interp)
-{
-  assert(interp == GL_LINEAR || interp == GL_NEAREST);
-  if(interp != m_InterpolationMode)
-    {
-    m_InterpolationMode = interp;
-    m_UpdateTime = 0; // make it out-of-date
-    }
-}
-
-
-void
-OpenGLSliceTexture
-::Update()
-{
-  // Better have an image
-  assert(m_Image);
-
-  // Update the image (necessary?)
-  if(m_Image->GetSource())
-    m_Image->GetSource()->UpdateLargestPossibleRegion();
-
-  // Check if everything is up-to-date and no computation is needed
-  if (m_IsTextureInitalized && m_UpdateTime == m_Image->GetPipelineMTime())
-    return;
-
-  // Promote the image dimensions to powers of 2
-  itk::Size<2> szImage = m_Image->GetLargestPossibleRegion().GetSize();
-  m_TextureSize = Vector2ui(1);
-
-  // Use shift to quickly double the coordinates
-  for (unsigned int i=0;i<2;i++)
-    while (m_TextureSize(i) < szImage[i])
-      m_TextureSize(i) <<= 1;
-
-  // Create the texture index if necessary
-  if(!m_IsTextureInitalized)
-    {
-    // Generate one texture
-    glGenTextures(1,&m_TextureIndex);
-    m_IsTextureInitalized = true;
-    }
-
-  // Select the texture for pixel pumping
-  glBindTexture(GL_TEXTURE_2D,m_TextureIndex);
-
-  // Properties for the texture
-  glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
-  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_InterpolationMode );
-  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_InterpolationMode );
-
-  // Turn off modulo-4 rounding in GL
-  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-  glPixelStorei(GL_PACK_ALIGNMENT, 1);
-
-  // Allocate texture of slightly bigger size
-  glTexImage2D(GL_TEXTURE_2D, 0, m_GlComponents,
-    m_TextureSize(0), m_TextureSize(1),
-    0, m_GlFormat, m_GlType, NULL);
-
-  // Copy a subtexture of correct size into the image
-  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, szImage[0], szImage[1],
-    m_GlFormat, m_GlType, m_Buffer);
-
-  // Remember the image's timestamp
-  m_UpdateTime = m_Image->GetPipelineMTime();
-}
-
-
-void
-OpenGLSliceTexture
-::Draw(const Vector3d &clrBackground)
-{
-  // Update the texture
-  Update();
-
-  // Should have a texture number
-  assert(m_IsTextureInitalized);
-
-  // GL settings
-  glPushAttrib(GL_TEXTURE_BIT);
-  glEnable(GL_TEXTURE_2D);
-
-  // Select our texture
-  glBindTexture(GL_TEXTURE_2D,m_TextureIndex);
-
-  // Set the color to the background color
-  glColor3dv(clrBackground.data_block());
-
-  int w = m_Image->GetBufferedRegion().GetSize()[0];
-  int h = m_Image->GetBufferedRegion().GetSize()[1];
-  double tx = w * 1.0 / m_TextureSize(0);
-  double ty = h * 1.0 / m_TextureSize(1);
-
-  // Draw quad 
-  glBegin(GL_QUADS);
-  glTexCoord2d(0,0);
-  glVertex2d(0,0);
-  glTexCoord2d(0,ty);
-  glVertex2d(0,h);
-  glTexCoord2d(tx,ty);
-  glVertex2d(w,h);
-  glTexCoord2d(tx,0);
-  glVertex2d(w,0);
-  glEnd();
-
-  glPopAttrib();
-}
-
-
-void
-OpenGLSliceTexture
-::DrawTransparent(unsigned char alpha)
-{
-  // Update the texture
-  Update();
-
-  // Should have a texture number
-  assert(m_IsTextureInitalized);
-
-  // GL settings
-  glPushAttrib(GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
-  glEnable(GL_TEXTURE_2D);
-
-  // Turn on alpha blending
-  glEnable(GL_BLEND);
-  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
-
-  // Select our texture
-  glBindTexture(GL_TEXTURE_2D,m_TextureIndex);
-
-  // Set the color to white
-  glColor4ub(255,255,255,alpha);
-    
-  int w = m_Image->GetBufferedRegion().GetSize()[0];
-  int h = m_Image->GetBufferedRegion().GetSize()[1];
-  double tx = w * 1.0 / m_TextureSize(0);
-  double ty = h * 1.0 / m_TextureSize(1);
-
-  // Draw quad 
-  glBegin(GL_QUADS);
-  glTexCoord2d(0,0);
-  glVertex2d(0,0);
-  glTexCoord2d(0,ty);
-  glVertex2d(0,h);
-  glTexCoord2d(tx,ty);
-  glVertex2d(w,h);
-  glTexCoord2d(tx,0);
-  glVertex2d(w,0);
-  glEnd();
-
-  glPopAttrib();
-}
-
diff --git a/UserInterface/SliceWindow/OpenGLSliceTexture.h b/UserInterface/SliceWindow/OpenGLSliceTexture.h
deleted file mode 100644
index 8a2c1ae..0000000
--- a/UserInterface/SliceWindow/OpenGLSliceTexture.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: OpenGLSliceTexture.h,v $
-  Language:  C++
-  Date:      $Date: 2009/08/25 19:44:25 $
-  Version:   $Revision: 1.9 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __OpenGLSliceTexture_h_
-#define __OpenGLSliceTexture_h_
-
-#include "SNAPCommon.h"
-#include "SNAPOpenGL.h"
-
-#ifndef _WIN32
-#ifndef GLU_VERSION_1_2
-#define GLU_VERSION_1_2 1
-#endif
-#endif
-
-#include "itkOrientedImage.h"
-
-/**
- * \class OpenGLSliceTexture
- * \brief This class is used to turn a 2D ITK image of (arbitrary) type
- * into a GL texture.  
- *
- * The calls to Update will make sure that the texture is up to date.  
- */
-class OpenGLSliceTexture 
-{
-public:
-  // Image typedefs
-  typedef itk::ImageBase<2> ImageBaseType;
-  typedef itk::SmartPointer<ImageBaseType> ImageBasePointer;
-
-  /** Constructor, initializes the texture object */
-  OpenGLSliceTexture();
-  OpenGLSliceTexture(GLuint, GLenum);
-
-  /** Destructor, deallocates texture memory */
-  virtual ~OpenGLSliceTexture();
-  
-  /** Pass in a pointer to a 2D image */
-  template<class TPixel> void SetImage(itk::Image<TPixel,2> *inImage)
-    {
-    m_Image = inImage;
-    m_Image->GetSource()->UpdateLargestPossibleRegion();
-    m_Buffer = inImage->GetBufferPointer();
-    m_UpdateTime = 0;
-    }
-
-  /** Get the dimensions of the texture image, which are powers of 2 */
-  irisGetMacro(TextureSize,Vector2ui);
-
-  /** Get the GL texture number automatically allocated by this object */
-  irisGetMacro(TextureIndex,int);
-
-  /** Set the number of components used in call to glTextureImage */
-  irisSetMacro(GlComponents,GLuint);
-
-  /** Get the format (e.g. GL_LUMINANCE) in call to glTextureImage */
-  irisSetMacro(GlFormat,GLenum);
-
-  /** Get the type (e.g. GL_UNSIGNED_INT) in call to glTextureImage */
-  irisSetMacro(GlType,GLenum);
-
-  /**
-   * Make sure that the texture is up to date (reflects the image)
-   */
-  void Update();
-
-  /**
-   * Set the interpolation mode for the texture. If the interpolation mode
-   * is changed, Update() will be called on the next Draw() command. The value
-   * must be GL_NEAREST or GL_LINEAR
-   */
-  void SetInterpolation(GLenum newmode);
-
-  /**
-   * Draw the texture in the current OpenGL context on a polygon with vertices
-   * (0,0) - (size_x,size_y). Paramters are the background color of the polygon
-   */
-  void Draw(const Vector3d &clrBackground);
-
-  /**
-   * Draw the texture in transparent mode, with given level of alpha blending.
-   */
-  void DrawTransparent(unsigned char alpha);
-
-private:
-  
-  // The dimensions of the texture as stored in memory
-  Vector2ui m_TextureSize;
-
-  // The pointer to the image from which the texture is computed
-  ImageBasePointer m_Image;
-
-  // Pointer to the image's data buffer (this should have been provided by ImageBase)
-  void *m_Buffer;
-
-  // The texture number (index)
-  GLuint m_TextureIndex;
-
-  // Has the texture been initialized?
-  bool m_IsTextureInitalized;
-
-  // The pipeline time of the source image (vs. our pipeline time)
-  unsigned long m_UpdateTime;
-
-  // The number of components for Gl op
-  GLuint m_GlComponents;
-
-  // The format for Gl op
-  GLenum m_GlFormat;
-
-  // The type for Gl op
-  GLenum m_GlType;
-
-  // Interpolation mode
-  GLenum m_InterpolationMode;
-};
-
-#endif // __OpenGLSliceTexture_h_
diff --git a/UserInterface/SliceWindow/PaintbrushInteractionMode.cxx b/UserInterface/SliceWindow/PaintbrushInteractionMode.cxx
deleted file mode 100644
index a6e1b4e..0000000
--- a/UserInterface/SliceWindow/PaintbrushInteractionMode.cxx
+++ /dev/null
@@ -1,760 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PaintbrushInteractionMode.cxx,v $
-  Language:  C++
-  Date:      $Date: 2009/01/31 09:02:50 $
-  Version:   $Revision: 1.14 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "PaintbrushInteractionMode.h"
-
-#include "itkRegionOfInterestImageFilter.h"
-#include "itkGradientAnisotropicDiffusionImageFilter.h"
-#include "itkGradientMagnitudeImageFilter.h"
-#include "itkWatershedImageFilter.h"
-#include "GlobalState.h"
-#include "PolygonDrawing.h"
-#include "UserInterfaceBase.h"
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-#include "SNAPAppearanceSettings.h"
-#include <algorithm>
-
-using namespace std;
-
-
-class BrushWatershedPipeline
-{
-public:
-  typedef itk::OrientedImage<GreyType, 3> GreyImageType;
-  typedef itk::OrientedImage<LabelType, 3> LabelImageType;
-  typedef itk::OrientedImage<float, 3> FloatImageType;
-  typedef itk::Image<unsigned long, 3> WatershedImageType;
-  typedef WatershedImageType::IndexType IndexType;
-
-  BrushWatershedPipeline()
-    {
-    roi = ROIType::New();
-    adf = ADFType::New();
-    adf->SetInput(roi->GetOutput());
-    adf->SetConductanceParameter(0.5);
-    gmf = GMFType::New();
-    gmf->SetInput(adf->GetOutput());
-    wf = WFType::New();
-    wf->SetInput(gmf->GetOutput());
-    }
-
-  void PrecomputeWatersheds(
-    GreyImageType *grey, 
-    LabelImageType *label, 
-    itk::ImageRegion<3> region,
-    itk::Index<3> vcenter,
-    size_t smoothing_iter)
-    {
-    this->region = region;
-
-    // Get the offset of vcenter in the region
-    if(region.IsInside(vcenter))
-      for(size_t d = 0; d < 3; d++)
-        this->vcenter[d] = vcenter[d] - region.GetIndex()[d];
-    else
-      for(size_t d = 0; d < 3; d++)
-        this->vcenter[d] = region.GetSize()[d] / 2;
-
-    // Create a backup of the label image
-    LROIType::Pointer lroi = LROIType::New();
-    lroi->SetInput(label);
-    lroi->SetRegionOfInterest(region);
-    lroi->Update();
-    lsrc = lroi->GetOutput();
-    lsrc->DisconnectPipeline();
-
-    // Initialize the watershed pipeline
-    roi->SetInput(grey);
-    roi->SetRegionOfInterest(region);
-    adf->SetNumberOfIterations(smoothing_iter);
-
-    // Set the initial level to lowest possible - to get all watersheds
-    wf->SetLevel(1.0);
-    wf->Update();
-    }
-
-  void RecomputeWatersheds(double level)
-    {
-    // Reupdate the filter with new level
-    wf->SetLevel(level);
-    wf->Update();
-    }
-
-  bool IsPixelInSegmentation(IndexType idx)
-    {
-    // Get the watershed ID at the center voxel 
-    unsigned long wctr = wf->GetOutput()->GetPixel(vcenter);
-    unsigned long widx = wf->GetOutput()->GetPixel(idx);
-    return wctr == widx;
-    }
-
-  bool UpdateLabelImage(
-    LabelImageType *ltrg, 
-    CoverageModeType mode, 
-    LabelType drawing_color,
-    LabelType overwrt_color)
-    {
-    // Get the watershed ID at the center voxel 
-    unsigned long wid = wf->GetOutput()->GetPixel(vcenter);
-
-    // Keep track of changed voxels
-    bool flagChanged = false;
-
-    // Do the update 
-    typedef itk::ImageRegionConstIterator<WatershedImageType> WIter;
-    typedef itk::ImageRegionIterator<LabelImageType> LIter;
-    WIter wit(wf->GetOutput(), wf->GetOutput()->GetBufferedRegion());
-    LIter sit(lsrc, lsrc->GetBufferedRegion());
-    LIter tit(ltrg, region);
-    for(; !wit.IsAtEnd(); ++sit,++tit,++wit)
-      {
-      LabelType pxLabel = sit.Get();
-      if(wit.Get() == wid)
-        {
-        // Standard paint mode
-        if (mode == PAINT_OVER_ALL || 
-          (mode == PAINT_OVER_ONE && pxLabel == overwrt_color) ||
-          (mode == PAINT_OVER_COLORS && pxLabel != 0))
-          {
-          pxLabel = drawing_color;
-          }
-        }
-      if(pxLabel != tit.Get())
-        {
-        tit.Set(pxLabel);
-        flagChanged = true;
-        }
-      }
-
-    if(flagChanged)
-      ltrg->Modified();
-    return flagChanged;
-    }
-
-private:
-  typedef itk::RegionOfInterestImageFilter<GreyImageType, FloatImageType> ROIType;
-  typedef itk::RegionOfInterestImageFilter<LabelImageType, LabelImageType> LROIType;
-  typedef itk::GradientAnisotropicDiffusionImageFilter<FloatImageType,FloatImageType> ADFType;
-  typedef itk::GradientMagnitudeImageFilter<FloatImageType, FloatImageType> GMFType;
-  typedef itk::WatershedImageFilter<FloatImageType> WFType;
-  
-  ROIType::Pointer roi;  
-  ADFType::Pointer adf;
-  GMFType::Pointer gmf;
-  WFType::Pointer wf;
-
-  itk::ImageRegion<3> region;
-  LabelImageType::Pointer lsrc;
-  itk::Index<3> vcenter;
-};
-
-
-
-
-PaintbrushInteractionMode
-::PaintbrushInteractionMode(GenericSliceWindow *parent)
-: GenericSliceWindow::EventHandler(parent)
-{                
-  m_MouseInside = false;
-  m_Watershed = new BrushWatershedPipeline();
-}
-
-PaintbrushInteractionMode
-::~PaintbrushInteractionMode()
-{
-}
-
-bool
-PaintbrushInteractionMode::
-TestInside(const Vector2d &x, const PaintbrushSettings &ps)
-  {
-  return this->TestInside(Vector3d(x(0), x(1), 0.0), ps);
-  }
-
-bool
-PaintbrushInteractionMode::
-TestInside(const Vector3d &x, const PaintbrushSettings &ps)
-  {
-  // Determine how to scale the voxels   
-  Vector3d xTest = x;
-  if(ps.isotropic)
-    {
-    double xMinVoxelDim = m_Parent->m_SliceSpacing.min_value();
-    xTest(0) *= m_Parent->m_SliceSpacing(0) / xMinVoxelDim;
-    xTest(1) *= m_Parent->m_SliceSpacing(1) / xMinVoxelDim;
-    xTest(2) *= m_Parent->m_SliceSpacing(2) / xMinVoxelDim;
-    }
-
-  // Test inside/outside  
-  if(ps.mode == PAINTBRUSH_ROUND)
-    {
-    return xTest.squared_magnitude() <= (ps.radius-0.25) * (ps.radius-0.25);
-    }
-  else
-    {
-    return xTest.inf_norm() <= ps.radius - 0.25;
-    }
-  }
-
-void 
-PaintbrushInteractionMode::
-BuildBrush(const PaintbrushSettings &ps)
-{
-  // This is a simple 2D marching algorithm. At any given state of the 
-  // marching, there is a 'tail' and a 'head' of an arrow. To the right
-  // of the arrow is a voxel that's inside the brush and to the left a
-  // voxel that's outside. Depending on the two voxels that are 
-  // ahead of the arrow to the left and right (in in, in out, out out)
-  // at the next step the arrow turns right, continues straight or turns
-  // left. This goes on until convergence
-  
-  // Initialize the marching. This requires constructing the first arrow
-  // and marching it to the left until it is between out and in voxels.
-  // If the brush has even diameter, the arrow is from (0,0) to (1,0). If
-  // the brush has odd diameter (center at voxel center) then the arrow 
-  // is from (-0.5, -0.5) to (-0.5, 0.5)
-  Vector2d xTail, xHead;
-  if(fmod(ps.radius,1.0) == 0)
-    { xTail = Vector2d(0.0, 0.0); xHead = Vector2d(0.0, 1.0); }
-  else
-    { xTail = Vector2d(-0.5, -0.5); xHead = Vector2d(-0.5, 0.5); }
-
-  // Shift the arrow to the left until it is in position
-  while(TestInside(Vector2d(xTail(0) - 0.5, xTail(1) + 0.5),ps))
-    { xTail(0) -= 1.0; xHead(0) -= 1.0; }
-
-  // Record the starting point, which is the current tail. Once the head
-  // returns to the starting point, the loop is done
-  Vector2d xStart = xTail;
-
-  // Do the loop
-  m_Walk.clear();
-  size_t n = 0;
-  while((xHead - xStart).squared_magnitude() > 0.01 && (++n) < 10000)
-    {
-    // Add the current head to the loop
-    m_Walk.push_back(xHead);
-
-    // Check the voxels ahead to the right and left
-    Vector2d xStep = xHead - xTail;
-    Vector2d xLeft(-xStep(1), xStep(0));
-    Vector2d xRight(xStep(1), -xStep(0));
-    bool il = TestInside(xHead + 0.5 * (xStep + xLeft),ps);
-    bool ir = TestInside(xHead + 0.5 * (xStep + xRight),ps);
-
-    // Update the tail
-    xTail = xHead;
-
-    // Decide which way to go
-    if(il && ir)
-      xHead += xLeft;
-    else if(!il && ir)
-      xHead += xStep;
-    else if(!il && !ir)
-      xHead += xRight;
-    else 
-      assert(0);
-    }
-
-  // Add the last vertex
-  m_Walk.push_back(xStart);
-}
-
-/*
-void 
-PaintbrushInteractionMode::
-BuildBrush(const PaintbrushSettings &ps)
-{
-  Vector2d xFirstVox(0, 0);
-
-  // Shift in case the center of the brush falls at vertex center
-  
-  // Step left from the center in units of 0.5 until we are outside
-  // of the brush
-  while(TestInside(xFirstVox, ps))
-    xFirstVox(0) -= 1.0;
-
-  // Find the left-most voxel that is inside of the brush
-  // Vector2d xFirstVox(0, 0);
-  // while(TestInside(xFirstVox, ps))
-  //  xFirstVox(0) -= 1.0;
-
-  // Set the starting location
-  Vector2d xStart(xFirstVox(0) + 0.5, -0.5);
-  Vector2d xWalk(xFirstVox(0) + 0.5, 0.5);
-  Vector2d xStep(0, 1);
-
-  if(fmod(ps.radius, 1.0) == 0)
-    {
-    xStart = Vector2d(xFirstVox(0) + 1.0, 0.0);
-    xWalk = Vector2d(xFirstVox(0) + 1.0, 1.0);
-    }
-
-  int i = 0;
-  m_Walk.clear();
-  while((xStart - xWalk).squared_magnitude() > 0.01 && ++i < 10000)
-    {
-    // Add the current walk step
-    m_Walk.push_back(xWalk);
-
-    // Compute the walk direction
-    Vector2d xLeft(-xStep(1), xStep(0));
-    Vector2d xRight(xStep(1), -xStep(0));
-    if(TestInside(xWalk + 0.5 * (xStep + xLeft), ps))
-      xStep = xLeft;
-    else if(!TestInside(xWalk + 0.5 * (xStep + xRight), ps))
-      xStep = xRight;
-
-    // Update the walk
-    xWalk = xWalk + xStep;
-    }
-
-  // Push the last point on the walk
-  m_Walk.push_back(xStart);
-}
-*/
-
-void
-PaintbrushInteractionMode
-::OnDraw()
-{
-  // Leave if mouse outside of slice
-  if(!m_MouseInside) return;
-
-  // Draw the outline of the paintbrush
-  PaintbrushSettings pbs = 
-    m_ParentUI->GetDriver()->GetGlobalState()->GetPaintbrushSettings();
-
-  // Paint all the edges in the paintbrush definition
-  const SNAPAppearanceSettings::Element &elt = 
-    m_ParentUI->GetAppearanceSettings()->GetUIElement(
-    SNAPAppearanceSettings::PAINTBRUSH_OUTLINE);
-
-  // Build the mask edges
-  BuildBrush(pbs);
-
-  // Set line properties
-  glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
-
-  // Apply the line properties
-  glColor3dv(elt.NormalColor.data_block());
-  SNAPAppearanceSettings::ApplyUIElementLineSettings(elt);
-
-  // Get the brush position
-  Vector3f xPos;
-  if(fmod(pbs.radius,1.0) == 0)
-    xPos = m_Parent->MapImageToSlice(to_float(m_MousePosition));
-  else
-    xPos = m_Parent->MapImageToSlice(to_float(m_MousePosition) + Vector3f(0.5f));
-
-  // Refit matrix so that the lines are centered on the current pixel
-  glPushMatrix();
-  glTranslated( xPos(0), xPos(1), 0.0 );
-
-  // Draw the lines around the point
-  glBegin(GL_LINE_LOOP);
-  for(std::list<Vector2d>::iterator it = m_Walk.begin(); it != m_Walk.end(); ++it)
-    glVertex2d((*it)(0), (*it)(1));
-  glEnd();
-
-  // Pop the matrix
-  glPopMatrix();
-
-  // Pop the attributes
-  glPopAttrib();
-}
-
-/*
-#include "itkImageFileWriter.h"
-
-template<class ImageType> void
-DebugDumpImage(ImageType *img, const char *fname)
-{
-  typedef itk::ImageFileWriter<ImageType> WriterType;
-  WriterType::Pointer w = WriterType::New();
-  w->SetFileName(fname);
-  w->SetInput(img);
-  w->Update();
-}
-*/
-
-
-void
-PaintbrushInteractionMode
-::ApplyBrush(FLTKEvent const &event)
-{
-  // Get the segmentation image
-  LabelImageWrapper *imgLabel = m_Driver->GetCurrentImageData()->GetSegmentation();
-
-  // Get the paint properties
-  LabelType drawing_color = m_GlobalState->GetDrawingColorLabel();
-  LabelType overwrt_color = m_GlobalState->GetOverWriteColorLabel();
-  CoverageModeType mode = m_GlobalState->GetCoverageMode();
-
-  // Get the paintbrush properties
-  PaintbrushSettings pbs = 
-    m_ParentUI->GetDriver()->GetGlobalState()->GetPaintbrushSettings();
-
-  // Whether watershed filter is used (adaptive brush)
-  bool flagWatershed = (
-    pbs.mode == PAINTBRUSH_WATERSHED 
-    && event.Button == FL_LEFT_MOUSE 
-    && event.Id == FL_PUSH);
-
-  // Define a region of interest
-  LabelImageWrapper::ImageType::RegionType xTestRegion;
-  for(size_t i = 0; i < 3; i++)
-    {
-    if(i != imgLabel->GetDisplaySliceImageAxis(m_Parent->m_Id) || pbs.flat == false)
-      {
-      // For watersheds, the radius must be > 2
-      double rad = (flagWatershed && pbs.radius < 1.5) ? 1.5 : pbs.radius;
-      xTestRegion.SetIndex(i, (long) (m_MousePosition(i) - rad)); // + 1);
-      xTestRegion.SetSize(i, (long) (2 * rad + 1)); // - 1);
-      }
-    else
-      {
-      xTestRegion.SetIndex(i, m_MousePosition(i));
-      xTestRegion.SetSize(i, 1);
-      }
-    }
-
-  // Crop the region by the buffered region
-  xTestRegion.Crop(imgLabel->GetImage()->GetBufferedRegion());
-
-  // Flag to see if anything was changed
-  bool flagUpdate = false;
-
-  // Special code for Watershed brush
-  if(flagWatershed)
-    {
-    // Precompute the watersheds
-    m_Watershed->PrecomputeWatersheds(
-      m_Driver->GetCurrentImageData()->GetGrey()->GetImage(),
-      m_Driver->GetCurrentImageData()->GetSegmentation()->GetImage(),
-      xTestRegion, to_itkIndex(m_MousePosition), pbs.watershed.smooth_iterations);
-
-    m_Watershed->RecomputeWatersheds(pbs.watershed.level);
-    }
-
-  // Shift vector (different depending on whether the brush has odd/even diameter
-  Vector3f offset(0.0);
-  if(fmod(pbs.radius,1.0)==0)
-    {
-    offset.fill(0.5);
-    offset(m_Parent->m_ImageAxes[2]) = 0.0;
-    }
-
-  // Iterate over the region
-  LabelImageWrapper::Iterator it(imgLabel->GetImage(), xTestRegion);
-  for(; !it.IsAtEnd(); ++it)
-    {
-    // Check if we are inside the sphere
-    LabelImageWrapper::ImageType::IndexType idx = it.GetIndex();
-    Vector3f xDelta = offset + to_float(Vector3l(idx.GetIndex())) - to_float(m_MousePosition);
-
-    Vector3d xDeltaSliceSpace = to_double(
-      m_Parent->m_ImageToDisplayTransform.TransformVector(xDelta));
-
-    // Check if the pixel is inside
-    if(!TestInside(xDeltaSliceSpace, pbs))
-      continue;
-
-    // Check if the pixel is in the watershed
-    LabelImageWrapper::ImageType::IndexType idxoff = to_itkIndex(
-      Vector3l(idx.GetIndex()) - Vector3l(xTestRegion.GetIndex().GetIndex()));
-    if(flagWatershed && !m_Watershed->IsPixelInSegmentation(idxoff))
-      continue;
-
-    // if(pbs.shape == PAINTBRUSH_ROUND && xDelta.squared_magnitude() >= r2)
-    //  continue;
-
-    // Paint the pixel
-    LabelType pxLabel = it.Get();
-
-    // Standard paint mode
-    if(event.Button == FL_LEFT_MOUSE)
-      {
-      if (mode == PAINT_OVER_ALL || 
-        (mode == PAINT_OVER_ONE && pxLabel == overwrt_color) ||
-        (mode == PAINT_OVER_COLORS && pxLabel != 0))
-        {
-        it.Set(drawing_color);
-        if(pxLabel != drawing_color) flagUpdate = true;
-        }
-      }
-    // Background paint mode (clear label over current label)
-    else if(event.Button == FL_RIGHT_MOUSE)
-      {
-      if(drawing_color != 0 && pxLabel == drawing_color) 
-        {
-        it.Set(0);
-        if(pxLabel != 0) flagUpdate = true;
-        }
-      else if(drawing_color == 0 && mode == PAINT_OVER_ONE)
-        {
-        it.Set(overwrt_color);
-        if(pxLabel != overwrt_color) flagUpdate = true;
-        }
-      }
-    }         
-
-  // Image has been updated
-  if(flagUpdate)
-    {
-    imgLabel->GetImage()->Modified();
-    m_ParentUI->OnPaintbrushPaint();
-    m_ParentUI->RedrawWindows();
-    }
-  else
-    {
-    m_Parent->GetCanvas()->redraw();
-    }
-}
-
-int
-PaintbrushInteractionMode
-::OnMousePress(FLTKEvent const &event)
-{
-  // Get the paintbrush properties
-  PaintbrushSettings pbs = 
-    m_ParentUI->GetDriver()->GetGlobalState()->GetPaintbrushSettings();
-
-  // Check if the right button was pressed
-  if(event.Button == FL_LEFT_MOUSE || event.Button == FL_RIGHT_MOUSE)
-    {
-    // Scan convert the points into the slice
-    ApplyBrush(event);
-
-    // Record the event
-    m_LastMouseEvent = event;
-
-    // Eat the event unless cursor chasing is enabled
-    return pbs.chase ? 0 : 1;              
-    }
-  else return 0;
-}
-
-void 
-PaintbrushInteractionMode
-::ComputeMousePosition(const Vector3f &xEvent)
-  {   
-  // Get the paintbrush properties
-  PaintbrushSettings pbs = 
-    m_ParentUI->GetDriver()->GetGlobalState()->GetPaintbrushSettings();
-
-  // Find the pixel under the mouse
-  Vector3f xClick = m_Parent->MapWindowToSlice(xEvent.extract(2));
-
-  // Compute the new cross-hairs position in image space
-  Vector3f xCross = m_Parent->MapSliceToImage(xClick);
-
-  // Round the cross-hairs position down to integer
-  Vector3i xCrossInteger;
-  if(fmod(pbs.radius, 1.0) == 0.0)
-    {
-    Vector3f offset(0.5);
-    offset(m_Parent->m_ImageAxes[2]) = 0.0;
-    xCrossInteger = to_int(xCross + offset);
-    }
-  else
-    xCrossInteger = to_int(xCross);
-  
-  // Make sure that the cross-hairs position is within bounds by clamping
-  // it to image dimensions
-  Vector3i xSize = to_int(m_Driver->GetCurrentImageData()->GetVolumeExtents());
-  m_MousePosition = to_unsigned_int(
-    xCrossInteger.clamp(Vector3i(0),xSize - Vector3i(1)));
-  m_MouseInside = true;
-  }
-
-int
-PaintbrushInteractionMode
-::OnMouseMotion(FLTKEvent const &event)
-  {
-  // Find the pixel under the mouse
-  ComputeMousePosition(event.XSpace);
-
-  // Repaint
-  m_ParentUI->RedrawWindows();
-
-  return 1;
-  }
-
-int 
-PaintbrushInteractionMode
-::OnMouseEnter(const FLTKEvent &event)
-  {
-  // Find the pixel under the mouse
-  ComputeMousePosition(event.XSpace);
-
-  // Repaint
-  m_ParentUI->RedrawWindows();
-
-  // Record the event
-  m_LastMouseEvent = event;
-
-  return 0;  
-  }
-
-int 
-PaintbrushInteractionMode
-::OnMouseLeave(const FLTKEvent &event)
-  {  
-  // Repaint
-  m_MouseInside = false;
-  m_ParentUI->RedrawWindows();
-
-  // Record the event
-  m_LastMouseEvent = event;
-
-  return 0;
-  }
-
-int
-PaintbrushInteractionMode
-::DragReleaseHandler(FLTKEvent const &event, FLTKEvent const &pressEvent, bool drag)
-{
-  // Get the paintbrush properties
-  PaintbrushSettings pbs = 
-    m_ParentUI->GetDriver()->GetGlobalState()->GetPaintbrushSettings();
-
-  // The behavior is different for 'fast' regular brushes and adaptive brush. For the 
-  // adaptive brush, dragging is disabled.
-  if(pbs.mode == PAINTBRUSH_WATERSHED && event.Button == FL_LEFT_MOUSE)
-    {
-    if(event.Id == FL_RELEASE)
-      m_Parent->m_ParentUI->StoreUndoPoint("Drawing with paintbrush");
-    
-    return pbs.chase ? 0 : 1; 
-    }
-
-  else
-    {
-    // Check if the right button was pressed
-    if(event.Button == FL_LEFT_MOUSE || event.Button == FL_RIGHT_MOUSE)
-      {
-      // See how much we have moved since the last event
-      double delta = (event.XCanvas - m_LastMouseEvent.XCanvas).magnitude();
-      if(delta > pbs.radius)
-        {
-        size_t nSteps = (int)ceil(delta / pbs.radius);
-        for(size_t i = 0; i < nSteps; i++)
-          {
-          float t = (1.0 + i) / nSteps;
-          Vector3f X = t * m_LastMouseEvent.XSpace + (1.0f - t) * event.XSpace;
-          ComputeMousePosition(X);
-          ApplyBrush(event);
-          }
-        }
-      else
-        {
-        // Find the pixel under the mouse
-        ComputeMousePosition(event.XSpace);
-
-        // Scan convert the points into the slice
-        ApplyBrush(event);    
-
-        // Set an undo point if not in drag mode
-        if(!drag)
-          m_Parent->m_ParentUI->StoreUndoPoint("Drawing with paintbrush");
-        }
-
-      // Record the event
-      m_LastMouseEvent = event;
-
-      // Eat the event unless cursor chasing is enabled
-      return pbs.chase ? 0 : 1;                        
-      }
-    }
-
-  return 0;
-}
-
-int
-PaintbrushInteractionMode
-::OnMouseRelease(FLTKEvent const &event, FLTKEvent const &pressEvent)
-{
-  return DragReleaseHandler(event, pressEvent,false);
-}
-
-int
-PaintbrushInteractionMode
-::OnMouseDrag(FLTKEvent const &event, FLTKEvent const &pressEvent)
-{
-  return DragReleaseHandler(event, pressEvent,true);
-}
-
-int
-PaintbrushInteractionMode
-::OnKeyDown(FLTKEvent const &event)
-{
-  // Get the paintbrush properties
-  PaintbrushSettings pbs = 
-    m_ParentUI->GetDriver()->GetGlobalState()->GetPaintbrushSettings();
-
-  // The behavior is different for 'fast' regular brushes and adaptive brush. For the 
-  // adaptive brush, dragging affects parameter settings
-  if(pbs.mode == PAINTBRUSH_WATERSHED)  
-    {
-    double shift = 0.0;
-    if(event.Key == ',')
-      shift = -1.0;
-    else if(event.Key == '.')
-      shift = 1.0;
-    if(shift != 0.0)
-      {
-      pbs.watershed.level += shift * 0.05;
-      if(pbs.watershed.level < 0.0) pbs.watershed.level = 0.0;
-      if(pbs.watershed.level > 1.0) pbs.watershed.level = 1.0;
-
-      
-      m_ParentUI->GetDriver()->GetGlobalState()->SetPaintbrushSettings(pbs);
-      m_ParentUI->UpdatePaintbrushAttributes();
-
-      return 1;
-      }
-    }
-  return 0;
-}
-
-int
-PaintbrushInteractionMode
-::OnShortcut(FLTKEvent const &event)
-{
-  return 0;
-}
-
-
diff --git a/UserInterface/SliceWindow/PaintbrushInteractionMode.h b/UserInterface/SliceWindow/PaintbrushInteractionMode.h
deleted file mode 100644
index 483cce1..0000000
--- a/UserInterface/SliceWindow/PaintbrushInteractionMode.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PaintbrushInteractionMode.h,v $
-  Language:  C++
-  Date:      $Date: 2008/12/02 21:43:24 $
-  Version:   $Revision: 1.6 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __PaintbrushInteractionMode_h_
-#define __PaintbrushInteractionMode_h_
-
-#include "GenericSliceWindow.h"
-#include "GlobalState.h"
-
-// Reference to watershed filter object
-class BrushWatershedPipeline;
-
-/**
- * \class PaintbrushInteractionMode
- * \brief UI interaction mode that takes care of painting with a shaped mask (brush).
- *
- * \see GenericSliceWindow
- */
-class PaintbrushInteractionMode : public GenericSliceWindow::EventHandler 
-{
-public:
-  PaintbrushInteractionMode(GenericSliceWindow *parent);
-  virtual ~PaintbrushInteractionMode();
-
-  int OnMousePress(const FLTKEvent &event);
-  int OnKeyDown(const FLTKEvent &event);
-  int OnMouseRelease(const FLTKEvent &event, const FLTKEvent &pressEvent);
-  int OnMouseDrag(const FLTKEvent &event, const FLTKEvent &pressEvent);
-  int DragReleaseHandler(FLTKEvent const &event, const FLTKEvent &pressEvent, bool drag);
-  int OnShortcut(const FLTKEvent &event);
-  int OnMouseMotion(const FLTKEvent &event);             
-  int OnMouseEnter(const FLTKEvent &event);
-  int OnMouseLeave(const FLTKEvent &event);
-  void OnDraw();  
-private:
-
-  // The paintbrush shape (depends on the settings parameters)
-  typedef itk::Image<unsigned char, 2> MaskType;
-  MaskType::Pointer m_Mask;
-
-  // The edges in the paintbrush
-  typedef std::pair<Vector2d, Vector2d> EdgeType;
-  typedef std::list<EdgeType> EdgeList;
-  EdgeList m_MaskEdges;
-
-  std::list<Vector2d> m_Walk;
-
-  // Build a display list to represent the paint brush
-  void BuildBrush(const PaintbrushSettings &ps);
-  void ApplyBrush(const FLTKEvent &event);
-  void ComputeMousePosition(const Vector3f &xEvent);
-  bool TestInside(const Vector2d &x, const PaintbrushSettings &ps);
-  bool TestInside(const Vector3d &x, const PaintbrushSettings &ps);
-
-  Vector3ui m_MousePosition;
-  bool m_MouseInside;
-
-  // Watershed pipeline object
-  BrushWatershedPipeline *m_Watershed;
-
-  // Last FLTK event involving the mouse
-  FLTKEvent m_LastMouseEvent;
-
-  // The window handler needs to access our privates
-  friend class IRISSliceWindow;
-};
-
-
-
-#endif // __PaintbrushInteractionMode_h_
diff --git a/UserInterface/SliceWindow/PolygonDrawing.cxx b/UserInterface/SliceWindow/PolygonDrawing.cxx
deleted file mode 100644
index 534f699..0000000
--- a/UserInterface/SliceWindow/PolygonDrawing.cxx
+++ /dev/null
@@ -1,1399 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PolygonDrawing.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/13 17:01:08 $
-  Version:   $Revision: 1.15 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "PolygonDrawing.h"
-#include "PolygonScanConvert.h"
-#include "SNAPCommonUI.h"
-#include "GenericSliceWindow.h"
-#include "UserInterfaceBase.h"
-
-#include "SNAPOpenGL.h"
-#include <iostream>
-#include <cstdlib>
-#include <algorithm>
-#include <set>
-#include <vnl/vnl_random.h>
-#include "FL/Fl_Menu_Button.H"
-
-#include "itkOrientedImage.h"
-#include "itkPointSet.h"
-
-#include "itkBSplineScatteredDataPointSetToImageFilter.h"
-#include "SNAPAppearanceSettings.h"
-
-using namespace std;
-
-// glu Tess callbacks
-
-/*
-#ifdef WIN32
-typedef void (CALLBACK *TessCallback)();
-#else
-typedef void (*TessCallback)();
-#endif
-
-void 
-#ifdef WIN32
-CALLBACK 
-#endif
-BeginCallback(GLenum which)
-{
-  glBegin(which);
-}
-
-void 
-#ifdef WIN32
-CALLBACK 
-#endif
-EndCallback(void) 
-{
-  glEnd();
-}
-
-void 
-#ifdef WIN32
-CALLBACK
-#endif
-ErrorCallback(GLenum errorCode)
-{
-  const GLubyte *estring;
-
-  estring = gluErrorString(errorCode);
-  cerr << "Tesselation Error-Exiting: " << estring << endl;
-  exit(-1);
-}
-
-
-void 
-#ifdef WIN32
-CALLBACK 
-#endif
-CombineCallback(GLdouble coords[3], 
-                GLdouble **irisNotUsed(vertex_data),  
-                GLfloat *irisNotUsed(weight), 
-                GLdouble **dataOut) 
-{
-  GLdouble *vertex;
-
-  vertex = new GLdouble[3];
-  vertex[0] = coords[0];
-  vertex[1] = coords[1];
-  vertex[2] = coords[2];
-  *dataOut = vertex;
-}
-*/
-
-const float PolygonDrawing::m_DrawingModeColor[] = { 1.0f, 0.0f, 0.5f };
-const float PolygonDrawing::m_EditModeNormalColor[] = { 1.0f, 0.0f, 0.0f };
-const float PolygonDrawing::m_EditModeSelectedColor[] = { 0.0f, 1.0f, 0.0f };
-
-/**
- * PolygonDrawing()
- *
- * purpose: 
- * create initial vertex and m_Cache arrays, init GLUm_Tesselatorelator
- */
-PolygonDrawing
-::PolygonDrawing(GenericSliceWindow *parent)
-{
-  m_CachedPolygon = false;
-  m_State = INACTIVE_STATE;
-  m_SelectedVertices = false;
-  m_DraggingPickBox = false;
-  m_Parent = parent;
-}
-
-/**
- * ~PolygonDrawing()
- *
- * purpose: 
- * free arrays and GLUm_Tesselatorelator
- */
-PolygonDrawing
-::~PolygonDrawing()
-{
-
-}
-
-/**
- * ComputeEditBox()
- *
- * purpose: 
- * compute the bounding box around selected vertices
- * 
- * post:
- * if m_Vertices are selected, sets m_SelectedVertices to 1, else 0
- */
-void
-PolygonDrawing
-::ComputeEditBox() 
-{
-  VertexIterator it;
-
-  // Find the first selected vertex and initialize the selection box
-  m_SelectedVertices = false;
-  for (it = m_Vertices.begin(); it!=m_Vertices.end();++it) 
-    {
-    if (it->selected) 
-      {
-      m_EditBox[0] = m_EditBox[1] = it->x;
-      m_EditBox[2] = m_EditBox[3] = it->y;
-      m_SelectedVertices = true;
-      break;
-      }
-    }
-
-  // Continue only if a selection exists
-  if (!m_SelectedVertices) return;
-
-  // Grow selection box to fit all selected vertices
-  for(it = m_Vertices.begin(); it!=m_Vertices.end();++it)
-    {
-    if (it->selected) 
-      {
-      if (it->x < m_EditBox[0]) m_EditBox[0] = it->x;
-      else if (it->x > m_EditBox[1]) m_EditBox[1] = it->x;
-
-      if (it->y < m_EditBox[2]) m_EditBox[2] = it->y;
-      else if (it->y > m_EditBox[3]) m_EditBox[3] = it->y;
-      }
-    }
-}
-
-/**
- * Add()
- *
- * purpose:
- * to add a vertex to the existing contour
- * 
- * pre: 
- * m_NumberOfAllocatedVertices > 0
- */
-/*
-void
-PolygonDrawing
-::Add(float x, float y, int selected)
-{
-  // add a new vertex
-  Vertex vNew;
-  vNew.x = x; vNew.y = y; vNew.selected = selected;
-
-
-  m_Vertices[m_NumberOfUsedVertices].x = x;
-  m_Vertices[m_NumberOfUsedVertices].y = y;
-  m_Vertices[m_NumberOfUsedVertices].selected = selected;
-    
-  m_NumberOfUsedVertices++;
-}
-*/
-
-void
-PolygonDrawing
-::DropLastPoint()
-{
-  if(m_State == DRAWING_STATE)
-    {
-    if(m_Vertices.size())
-      m_Vertices.pop_back();
-    }
-}
-
-void
-PolygonDrawing
-::ClosePolygon()
-{
-  if(m_State == DRAWING_STATE)
-    {
-    m_State = EDITING_STATE;
-    m_SelectedVertices = true;
-
-    for(VertexIterator it = m_Vertices.begin(); it!=m_Vertices.end(); ++it)
-      it->selected = false;
-
-    ComputeEditBox();
-    }
-}
-
-/**
- * Delete()
- *
- * purpose: 
- * delete all vertices that are selected
- * 
- * post: 
- * if all m_Vertices removed, m_State becomes INACTIVE_STATE
- * length of m_Vertices array does not decrease
- */
-void
-PolygonDrawing
-::Delete() 
-{
-  VertexIterator it=m_Vertices.begin();
-  while(it!=m_Vertices.end())
-    {
-    if(it->selected)
-      it = m_Vertices.erase(it);
-    else ++it;
-    }
-  
-  if (m_Vertices.empty()) 
-    {
-    m_State = INACTIVE_STATE;
-    m_SelectedVertices = false;
-    }
-  
-  ComputeEditBox();
-}
-
-void 
-PolygonDrawing
-::Reset()
-{
-  m_State = INACTIVE_STATE;
-  m_Vertices.clear();
-  ComputeEditBox();
-}
-
-/**
- * Insert()
- *
- * purpose:
- * insert vertices between adjacent selected vertices
- * 
- * post: 
- * length of m_Vertices array does not decrease
- */
-void
-PolygonDrawing
-::Insert() 
-{
-  // Insert a vertex between every pair of adjacent vertices
-  VertexIterator it = m_Vertices.begin();
-  while(it != m_Vertices.end())
-    {
-    // Get the itNext iterator to point to the next point in the list
-    VertexIterator itNext = it;
-    if(++itNext == m_Vertices.end()) 
-      itNext = m_Vertices.begin();
-
-    // Check if the insertion is needed
-    if(it->selected && itNext->selected)
-      {
-      // Insert a new vertex
-      Vertex vNew(0.5 * (it->x + itNext->x), 0.5 * (it->y + itNext->y), true, true);
-      it = m_Vertices.insert(++it, vNew);
-      }
-
-    // On to the next point
-    ++it;
-    }
-}
-
-int 
-PolygonDrawing
-::GetNumberOfSelectedSegments()
-{
-  int isel = 0;
-  for(VertexIterator it = m_Vertices.begin(); it != m_Vertices.end(); it++)
-    {
-    // Get the itNext iterator to point to the next point in the list
-    VertexIterator itNext = it;
-    if(++itNext == m_Vertices.end()) 
-      itNext = m_Vertices.begin();
-
-    // Check if the insertion is needed
-    if(it->selected && itNext->selected)
-      isel++;
-    }
-  return isel;
-}
-
-void
-PolygonDrawing
-::ProcessFreehandCurve()
-{
-  // Special case: no fitting  
-  if(m_FreehandFittingRate == 0.0)
-    {
-    for(VertexIterator it = m_DragVertices.begin(); 
-      it != m_DragVertices.end(); ++it)
-      {
-      m_Vertices.push_back(*it);
-      }
-    m_DragVertices.clear();
-    return;
-    }
-
-  // We will fit a b-spline of the 0-th order to the freehand curve
-  if(m_Vertices.size() > 0)
-    {
-    // Prepend the last vertex before freehand drawing
-    m_DragVertices.push_front(m_Vertices.back());
-    m_Vertices.pop_back();
-    }
-
-  // Create a list of input points
-  typedef itk::Vector<double, 2> VectorType;
-  typedef itk::Image<VectorType, 1> ImageType;
-  typedef itk::PointSet<VectorType, 1> PointSetType;
-  PointSetType::Pointer pointSet = PointSetType::New();
-
-  double len = 0;
-  double t = 0, dt = 1.0 / (m_DragVertices.size());
-  size_t i = 0;
-  Vertex last;
-  for(VertexIterator it = m_DragVertices.begin(); 
-    it != m_DragVertices.end(); ++it)
-    {
-    PointSetType::PointType point;
-    point[0] = t;
-    pointSet->SetPoint(i,point);
-    VectorType v;
-    v[0] = it->x; v[1] = it->y;
-    pointSet->SetPointData(i, v);
-    t+=dt; i++;
-    if(it != m_DragVertices.begin())
-      {
-      double dx = last.x - it->x;
-      double dy = last.y - it->y;
-      len += sqrt(dx * dx + dy * dy);
-      }
-    last = *it;
-    }
-
-  // Compute the number of control points
-  size_t nctl = (size_t)ceil(len / m_FreehandFittingRate);
-  if(nctl < 3)
-    nctl = 3;
-
-  // Compute the number of levels and the control points at coarsest level
-  size_t nl = 1; size_t ncl = nctl;
-  while(ncl >= 8)
-    { ncl >>= 1; nl++; }
-  
-
-  // Create the scattered interpolator
-  typedef itk::BSplineScatteredDataPointSetToImageFilter<
-    PointSetType, ImageType> FilterType;
-  FilterType::Pointer filter = FilterType::New();
-
-  ImageType::SpacingType spacing; spacing.Fill( 0.001 );
-  ImageType::SizeType size; size.Fill((int)(1.0/spacing[0]));
-  ImageType::PointType origin; origin.Fill(0.0);
-  
-  filter->SetSize( size );
-  filter->SetOrigin( origin );
-  filter->SetSpacing( spacing );
-  filter->SetInput( pointSet );
-  filter->SetSplineOrder( 1 );
-  FilterType::ArrayType ncps;
-  ncps.Fill(ncl);
-  filter->SetNumberOfLevels(nl);
-  filter->SetNumberOfControlPoints(ncps);
-  filter->SetGenerateOutputImage(false);
-
-  // Run the filter
-  filter->Update();
-
-  ImageType::Pointer lattice = filter->GetPhiLattice();
-  size_t n = lattice->GetBufferedRegion().GetNumberOfPixels();
-  for(size_t i = 0; i < n; i++)
-    {
-    ImageType::IndexType idx;
-    idx.Fill(i);
-    VectorType v = lattice->GetPixel(idx);
-    m_Vertices.push_back(Vertex(v[0],v[1],false,true));
-    }
-
-  /*
-
-  // Get the control points?
-  double du = 1.0 / nctl;
-  for(double u = 0; u < 1.00001; u += du)
-    {
-    if(u > 1.0) u = 1.0;
-    PointSetType::PointType point;
-    point[0] = u;
-    VectorType v;
-    filter->Evaluate(point,v);
-    m_Vertices.push_back(Vertex(v[0],v[1],false));
-    }
-    */
-
-  // Empty the drag list
-  // m_DragVertices.clear();
-}
-
-bool PolygonVertexTest(const PolygonDrawing::Vertex &v1, const PolygonDrawing::Vertex &v2)
-{
-  return v1.x == v2.x && v1.y == v2.y;
-}
-
-/**
- * AcceptPolygon()
- *
- * purpose:
- * to rasterize the current polygon into a buffer & copy the edited polygon
- * into the polygon m_Cache
- *
- * parameters:
- * buffer - an array of unsigned chars interpreted as an RGBA buffer
- * width  - the width of the buffer
- * height - the height of the buffer 
- *
- * pre: 
- * buffer array has size width*height*4
- * m_State == EDITING_STATE
- *
- * post: 
- * m_State == INACTIVE_STATE
- */
-void 
-PolygonDrawing
-::AcceptPolygon(ByteImageType *image) 
-{
-  // Remove duplicates from the vertex array
-  VertexIterator itEnd = std::unique(m_Vertices.begin(), m_Vertices.end(), PolygonVertexTest);
-  m_Vertices.erase(itEnd, m_Vertices.end());
-
-  // There may still be duplicates in the array, in which case we should
-  // add a tiny offset to them. Thanks to Jeff Tsao for this bug fix! 
-  std::set< std::pair<float, float> > xVertexSet;
-  vnl_random rnd;
-  for(VertexIterator it = m_Vertices.begin(); it != m_Vertices.end(); ++it)
-    {
-    while(xVertexSet.find(make_pair(it->x, it->y)) != xVertexSet.end())
-      {
-      it->x += 0.0001 * rnd.drand32(-1.0, 1.0);
-      it->y += 0.0001 * rnd.drand32(-1.0, 1.0);
-      }
-    xVertexSet.insert(make_pair(it->x, it->y));
-    }
-
-
-  // Scan convert the points into the slice
-  typedef PolygonScanConvert<
-    unsigned char, GL_UNSIGNED_BYTE, VertexIterator> ScanConvertType;
-  
-  ScanConvertType::RasterizeFilled(
-    m_Vertices.begin(), m_Vertices.size(), image);
-
-  // Copy polygon into polygon m_Cache
-  m_CachedPolygon = true;
-  m_Cache = m_Vertices;
-
-  // Reset the vertex array for next time
-  m_Vertices.clear();
-  m_SelectedVertices = false;
-
-  // Set the state
-  m_State = INACTIVE_STATE;
-}
-
-/**
- * PastePolygon()
- *
- * purpose:
- * copy the m_Cached polygon to the edited polygon
- * 
- * pre: 
- * m_CachedPolygon == 1
- * m_State == INACTIVE_STATE
- * 
- * post: 
- * m_State == EDITING_STATE
- */
-void 
-PolygonDrawing
-::PastePolygon(void)
-{
-  // Copy the cache into the vertices
-  m_Vertices = m_Cache;
-
-  // Select everything
-  for(VertexIterator it = m_Vertices.begin(); it!=m_Vertices.end();++it)
-    it->selected = false;
-
-  // Set the state
-  m_SelectedVertices = false;
-  m_State = EDITING_STATE;
-  
-  // Compute the edit box
-  ComputeEditBox();
-}
-
-/**
- * Draw()
- *
- * purpose: 
- * draw the polyline being drawn or the polygon being edited
- *
- * parameters:
- * pixel_x - this is a width in the polygon's space that is a single 
- *           pixel width on screen
- * pixel_y - this is a height in the polygon's space that is a single 
- *           pixel height on screen
- *  
- * pre: none - expected to exit if m_State is INACTIVE_STATE
- */
-void
-PolygonDrawing
-::Draw(float pixel_x, float pixel_y)
-{
-  // Must be in active state
-  if (m_State == INACTIVE_STATE) return;
-
-  // Get a pointer to the appearance settings
-  SNAPAppearanceSettings *app = m_Parent->GetParentUI()->GetAppearanceSettings();
-  SNAPAppearanceSettings::Element &aeDraw = app->GetUIElement(SNAPAppearanceSettings::POLY_DRAW_MAIN);
-  SNAPAppearanceSettings::Element &aeClose = app->GetUIElement(SNAPAppearanceSettings::POLY_DRAW_CLOSE);
-  SNAPAppearanceSettings::Element &aeEdit = app->GetUIElement(SNAPAppearanceSettings::POLY_EDIT);
-
-  // Push the line state
-  glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);  
-
-  // set line and point drawing parameters
-  glPointSize(4);
-  // glLineWidth(2);
-  // glEnable(GL_LINE_SMOOTH);
-  // glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
-  // glEnable(GL_BLEND);
-  // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-  // Draw the line segments
-  VertexIterator it, itNext;
-  if (m_State == EDITING_STATE)
-  {
-    glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);  
-    SNAPAppearanceSettings::ApplyUIElementLineSettings(aeEdit);
-
-    glBegin(GL_LINES);
-    for(it = m_Vertices.begin(); it!=m_Vertices.end();++it)
-      {
-      // Point to the next vertex
-      itNext = it; ++itNext; 
-      if(itNext == m_Vertices.end())
-        itNext = m_Vertices.begin();
-
-      // Set the color based on the mode
-      if (it->selected && itNext->selected) 
-        glColor3dv(aeEdit.ActiveColor.data_block());
-      else 
-        glColor3dv(aeEdit.NormalColor.data_block());
-  
-      // Draw the line
-      glVertex3f(it->x, it->y,0);
-      glVertex3f(itNext->x, itNext->y, 0);
-    }
-    glEnd();
-
-    glPopAttrib();
-  }
-  // Not editing state
-  else 
-  {
-    glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
-    SNAPAppearanceSettings::ApplyUIElementLineSettings(aeDraw);
-
-    // Draw the vertices
-    glBegin(GL_LINE_STRIP);
-    glColor3dv(aeDraw.NormalColor.data_block());
-    for(it = m_Vertices.begin(); it!=m_Vertices.end();++it) 
-      glVertex3f(it->x, it->y, 0);
-    glEnd();
-
-    // Draw the drag vertices
-    if(m_DragVertices.size())
-      {
-      glBegin(GL_LINE_STRIP);
-      for(it = m_DragVertices.begin(); it!=m_DragVertices.end();++it) 
-        glVertex3f(it->x, it->y, 0);
-      glEnd();
-      }
-
-    glPopAttrib();
-
-    // Draw stippled line from last point to end point
-    if(m_DragVertices.size() + m_Vertices.size() > 2 && aeClose.Visible) 
-      {
-      glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
-      SNAPAppearanceSettings::ApplyUIElementLineSettings(aeClose);
-
-      glBegin(GL_LINES);
-      glColor3dv(aeClose.NormalColor.data_block());
-      if(m_DragVertices.size())
-        glVertex3f(m_DragVertices.back().x, m_DragVertices.back().y, 0);
-      else
-        glVertex3f(m_Vertices.back().x, m_Vertices.back().y, 0);
-      glVertex3f(m_Vertices.front().x, m_Vertices.front().y, 0);
-      glEnd();
-      glPopAttrib();
-      }
-  }
-    
-  // draw the vertices
-  glBegin(GL_POINTS);
-  glPushAttrib(GL_COLOR_BUFFER_BIT);
-  for(it = m_Vertices.begin(); it!=m_Vertices.end();++it) 
-  {
-    if(it->control)
-      {
-      if (it->selected) 
-        glColor3dv(aeEdit.ActiveColor.data_block());
-      else if (m_State == DRAWING_STATE)
-        glColor3dv(aeDraw.NormalColor.data_block());
-      else
-        glColor3dv(aeEdit.NormalColor.data_block());
-
-      glVertex3f(it->x,it->y,0.0f);
-      }
-  }
-
-  // Draw the last dragging vertex point
-  if(m_DragVertices.size())
-    {
-    Vertex last = m_DragVertices.back();
-    glColor3dv(aeEdit.ActiveColor.data_block());
-    glVertex3f(last.x, last.y, 0.0f);
-    }
-
-  glEnd();
-  glPopAttrib();
-
-  // draw edit or pick box
-  if (m_DraggingPickBox) 
-  {
-    glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
-    
-    glLineWidth(1);
-    glColor3dv(aeEdit.ActiveColor.data_block()); 
-    glBegin(GL_LINE_LOOP);
-    glVertex3f(m_SelectionBox[0],m_SelectionBox[2],0.0);
-    glVertex3f(m_SelectionBox[1],m_SelectionBox[2],0.0);
-    glVertex3f(m_SelectionBox[1],m_SelectionBox[3],0.0);
-    glVertex3f(m_SelectionBox[0],m_SelectionBox[3],0.0);
-    glEnd();    
-
-    glPopAttrib();
-  }
-  else if (m_SelectedVertices) 
-  {
-    glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
-    
-    glLineWidth(1);
-    glColor3dv(aeEdit.ActiveColor.data_block()); 
-
-    float border_x = (float) 4.0 * pixel_x;
-    float border_y = (float) 4.0 * pixel_y;
-    glLineWidth(1);
-    glColor3fv(m_EditModeSelectedColor);
-    glBegin(GL_LINE_LOOP);
-    glVertex3f(m_EditBox[0] - border_x,m_EditBox[2] - border_y,0.0);
-    glVertex3f(m_EditBox[1] + border_x,m_EditBox[2] - border_y,0.0);
-    glVertex3f(m_EditBox[1] + border_x,m_EditBox[3] + border_y,0.0);
-    glVertex3f(m_EditBox[0] - border_x,m_EditBox[3] + border_y,0.0);
-    glEnd();
-
-    glPopAttrib();
-  }
-
-  glPopAttrib();
-}
-
-/**
- * Handle()
- *
- * purpose:
- * handle events from the window that contains polygon drawing object:
- * if internal m_State is DRAWING_STATE
- *   left-click creates subsequent vertices of the polygon, 
- *   right-click closes polygon and puts polygon in EDITING_STATE
- * if internal m_State is EDITING_STATE
- *   shift-left-click on vertex adds vertex to selection
- *   shift-left-click off vertex begins dragging a rubber-band box
- *
- *   shift-right-click performs same actions but de-selects vertices
- *
- *   left-click in selection box begins dragging of selected vertices
- *   left-click outside selection box cancels selection, begins a 
- *   dragging of a rubber-band box
- *   
- *   left-release after dragging adds vertices inside rubber-band box
- *   to selection
- * 
- *   pressing the 'insert' key calls Insert()
- *   pressing the 'delete' key calls Delete()
- * 
- * parameters:
- * event   - an Fl event number
- * x       - the x of the point clicked in the space of the polygon
- * y       - the y of the point clicked in the space of the polygon
- * pixel_x - see Draw()
- * pixel_y - see Draw()
- *
- * pre: 
- * window that calls this has the drawing lock
- * 
- * post:
- * if event is used, 1 is returned, else 0
- */
-int
-PolygonDrawing
-::Handle(int event, int button, float x, float y, 
-         float pixel_x, float pixel_y)
-{
-  VertexIterator it, itNext;
-
-  switch (m_State) {
-  case INACTIVE_STATE:
-    if ((event == FL_PUSH) && (button == FL_LEFT_MOUSE)) 
-      {
-      m_State = DRAWING_STATE;
-      m_Vertices.push_back( Vertex(x, y, false, true) );
-      return 1;
-      }
-    else if ((event == FL_PUSH) && (button == FL_RIGHT_MOUSE))
-      {
-      // Show popup menu
-      Fl_Menu_Button menu(Fl::event_x_root(), Fl::event_y_root(), 80, 1);
-      menu.textsize(12);
-      menu.add("paste last polygon", FL_COMMAND + 'v', NULL);
-
-      // Disable some options
-      if(m_Cache.size() == 0)
-        {
-        const_cast<Fl_Menu_Item*>(menu.menu() + 0)->deactivate();
-        }
-
-      menu.popup();
-
-      // Branch based on the decision
-      if(menu.value() == 0)
-        {
-        m_Parent->GetParentUI()->OnPastePolygonAction(m_Parent->GetId());
-        }
-
-      return 1;
-      }
-    break;
-
-  case DRAWING_STATE:
-    if (event == FL_PUSH) 
-      {
-      m_DragVertices.clear();
-      if (button == FL_LEFT_MOUSE)
-        {
-        // Left click means to add a vertex to the polygon. However, for
-        // compatibility reasons, we must make sure that there are no duplicates
-        // in the polygon (otherwise, division by zero occurs).
-        if(m_Vertices.size() == 0 || 
-          m_Vertices.back().x != x || m_Vertices.back().y != y)
-          {
-          // Check if the user wants to close the polygon
-          if(m_Vertices.size() > 2)
-            {
-            Vector2d A(m_Vertices.front().x / pixel_x, m_Vertices.front().y / pixel_y);
-            Vector2d C(x / pixel_x, y / pixel_y);
-            if((A-C).inf_norm() < 4)
-              {
-              ClosePolygon();
-              return 1;
-              }
-            }
-          m_Vertices.push_back( Vertex(x, y, false, true) );
-          }
-        return 1;
-        } 
-      else if (button == FL_RIGHT_MOUSE) 
-        {
-        // Show popup menu
-        Fl_Menu_Button menu(Fl::event_x_root(), Fl::event_y_root(), 80, 1);
-        menu.textsize(12);
-        menu.add("close loop && edit",  FL_Enter, NULL);
-        menu.add("_close loop && accept", FL_COMMAND + FL_Enter, NULL);
-        menu.add("undo last point", FL_Delete, NULL);
-        menu.add("cancel drawing", FL_Escape, NULL);
-
-        // Disable some options
-        if(!CanClosePolygon())
-          {
-          const_cast<Fl_Menu_Item*>(menu.menu() + 0)->deactivate();
-          const_cast<Fl_Menu_Item*>(menu.menu() + 1)->deactivate();
-          }
-        if(!CanDropLastPoint())
-          {
-          const_cast<Fl_Menu_Item*>(menu.menu() + 2)->deactivate();
-          }
-
-        menu.popup();
-
-        // Branch based on the decision
-        if(menu.value() == 0)
-          {
-          ClosePolygon();
-          }
-        if(menu.value() == 1)
-          {
-          ClosePolygon();
-          m_Parent->GetParentUI()->OnAcceptPolygonAction(m_Parent->GetId());
-          }
-        else if(menu.value() == 2)
-          {
-          DropLastPoint();
-          }
-        else if(menu.value() == 3)
-          {
-          Reset();
-          }
-        
-        return 1;
-        }
-      }
-    else if (event == FL_DRAG)
-      {
-      if(m_Vertices.size() == 0)
-        {
-        m_Vertices.push_back(Vertex(x,y,false,true));
-        }
-      else 
-        {
-        if(m_FreehandFittingRate == 0)
-          {
-          m_Vertices.push_back(Vertex(x,y,false,false));
-          }
-        else
-          {
-          Vertex &v = m_Vertices.back();
-          double dx = (v.x-x) / pixel_x;
-          double dy = (v.y-y) / pixel_y;
-          double d = dx*dx+dy*dy;
-          if(d >= m_FreehandFittingRate * m_FreehandFittingRate)
-            m_Vertices.push_back(Vertex(x,y,false,true));
-          }
-        }
-
-      return 1;
-      }
-    else if (event == FL_RELEASE)
-      {
-      // If some dragging has been done, convert it to polygons
-      // if(m_DragVertices.size() > 0)
-      //  {
-      //  ProcessFreehandCurve();
-      //  }
-      if(m_Vertices.size() && m_Vertices.back().control == false)
-        m_Vertices.back().control = true;
-      return 1;
-      }
-    else if (event == FL_SHORTCUT)
-      {
-      if(Fl::test_shortcut(FL_COMMAND | FL_Enter))
-        {
-        if(CanClosePolygon())
-          {
-          ClosePolygon();
-          m_Parent->GetParentUI()->OnAcceptPolygonAction(m_Parent->GetId());
-          }
-        return 1;
-        }
-      else if(Fl::test_shortcut(FL_Enter))
-        {
-        if(CanClosePolygon())
-          ClosePolygon();
-        return 1;
-        }
-      else if(Fl::test_shortcut(FL_Delete) || Fl::test_shortcut(FL_BackSpace))
-        {
-        if(CanDropLastPoint())
-          DropLastPoint();
-        return 1;
-        }
-      else if(Fl::test_shortcut(FL_Escape))
-        {
-        Reset();
-        return 1;
-        }
-      }
-
-    break;
-
-  case EDITING_STATE:
-    switch (event) {
-    case FL_PUSH:
-      m_StartX = x;
-      m_StartY = y;
-
-      if (button == FL_LEFT_MOUSE) 
-        {
-
-        // if user is pressing shift key, add/toggle m_Vertices, or drag pick box
-        if (Fl::event_state(FL_SHIFT)) 
-          {
-          // check if vertex clicked
-          if(CheckClickOnVertex(x,y,pixel_x,pixel_y,4))
-            {
-            ComputeEditBox();
-            return 1;
-            }
-
-          // check if clicked near a line segment
-          if(CheckClickOnLineSegment(x,y,pixel_x,pixel_y,4))
-            {
-            ComputeEditBox();
-            return 1;
-            }
-
-          // otherwise start dragging pick box
-          m_DraggingPickBox = true;
-          m_SelectionBox[0] = m_SelectionBox[1] = x;
-          m_SelectionBox[2] = m_SelectionBox[3] = y;
-          return 1;
-          }
-
-        // user not holding shift key; if user clicked inside edit box, 
-        // edit box will be moved in drag event
-        if (m_SelectedVertices &&
-          (x >= (m_EditBox[0] - 4.0*pixel_x)) && 
-          (x <= (m_EditBox[1] + 4.0*pixel_x)) && 
-          (y >= (m_EditBox[2] - 4.0*pixel_y)) && 
-          (y <= (m_EditBox[3] + 4.0*pixel_y))) return 1;
-
-        // clicked outside of edit box & shift not held, this means the 
-        // current selection will be cleared
-        for(it = m_Vertices.begin(); it!=m_Vertices.end(); ++it) 
-          it->selected = false;
-        m_SelectedVertices = false;
-
-        // Check if clicked on a pixel
-        if(CheckClickOnVertex(x,y,pixel_x,pixel_y,4))
-          {
-          ComputeEditBox();
-          return 1;
-          }
-
-        // check if clicked near a line segment
-        if(CheckClickOnLineSegment(x,y,pixel_x,pixel_y,4))
-          {
-          ComputeEditBox();
-          return 1;
-          }
-
-        // didn't click a point - start dragging pick box
-        m_DraggingPickBox = true;
-        m_SelectionBox[0] = m_SelectionBox[1] = x;
-        m_SelectionBox[2] = m_SelectionBox[3] = y;
-        return 1;
-        }
-
-      // Popup menu business
-      else if(button == FL_RIGHT_MOUSE)
-        {
-        // If nothing is selected, select what's under the cursor
-        if(!m_SelectedVertices)
-          {
-          // Check if clicked on a pixel
-          if(CheckClickOnVertex(x,y,pixel_x,pixel_y,4))
-            {
-            ComputeEditBox();
-            m_Parent->GetParentUI()->RedrawWindows();
-            }
-
-          // check if clicked near a line segment
-          else if(CheckClickOnLineSegment(x,y,pixel_x,pixel_y,4))
-            {
-            ComputeEditBox();
-            m_Parent->GetParentUI()->RedrawWindows();
-            }
-          }
-
-        // Show popup menu
-        Fl_Menu_Button menu(Fl::event_x_root(), Fl::event_y_root(), 80, 1);
-        menu.textsize(12);
-        menu.add("_accept", FL_Enter, NULL);
-        menu.add("delete selected points", FL_Delete, NULL);
-        menu.add("_split selected segments", FL_Insert, NULL);
-        menu.add("clear", FL_Escape, NULL);
-
-        if(!CanInsertVertices())
-          const_cast<Fl_Menu_Item*>(menu.menu() + 2)->deactivate();
-
-        if(!m_SelectedVertices)
-          const_cast<Fl_Menu_Item*>(menu.menu() + 1)->deactivate();
-        
-        menu.popup();
-
-        // Branch based on the decision
-        if(menu.value() == 0)
-          {
-          m_Parent->GetParentUI()->OnAcceptPolygonAction(m_Parent->GetId());
-          }
-        if(menu.value() == 1)
-          {
-          m_Parent->GetParentUI()->OnDeletePolygonSelectedAction(m_Parent->GetId());
-          }
-        else if(menu.value() == 2)
-          {
-          m_Parent->GetParentUI()->OnInsertIntoPolygonSelectedAction(m_Parent->GetId());
-          }
-        else if(menu.value() == 3)
-          {
-          Reset();
-          }
-
-        return 1;
-        }
-      break;
-
-    case FL_DRAG:
-      if ((button == FL_LEFT_MOUSE) || (button == FL_RIGHT_MOUSE)) 
-        {
-        if (m_DraggingPickBox) 
-          {
-          m_SelectionBox[1] = x;
-          m_SelectionBox[3] = y;
-          } 
-        else 
-          {
-          if (button == FL_LEFT_MOUSE) 
-            {
-            m_EditBox[0] += (x - m_StartX);
-            m_EditBox[1] += (x - m_StartX);
-            m_EditBox[2] += (y - m_StartY);
-            m_EditBox[3] += (y - m_StartY);
-
-            // If the selection is bounded by control vertices, we simply shift it
-            for(it = m_Vertices.begin(); it!=m_Vertices.end(); ++it) 
-              {
-              if (it->selected) 
-                {
-                it->x += (x - m_StartX);
-                it->y += (y - m_StartY);
-                }
-              }
-
-            // If the selection is bounded by freehand vertices, we apply a smooth
-            m_StartX = x;
-            m_StartY = y;
-            }
-          }
-        return 1;
-        }
-      break;
-
-    case FL_RELEASE:
-      if ((button == FL_LEFT_MOUSE) || (button == FL_RIGHT_MOUSE)) 
-        {
-        if (m_DraggingPickBox) 
-          {
-          m_DraggingPickBox = false;
-
-          float temp;
-          if (m_SelectionBox[0] > m_SelectionBox[1]) 
-            {
-            temp = m_SelectionBox[0];
-            m_SelectionBox[0] = m_SelectionBox[1];
-            m_SelectionBox[1] = temp;
-            }
-          if (m_SelectionBox[2] > m_SelectionBox[3]) 
-            {
-            temp = m_SelectionBox[2];
-            m_SelectionBox[2] = m_SelectionBox[3];
-            m_SelectionBox[3] = temp;
-            }
-
-          for(it = m_Vertices.begin(); it!=m_Vertices.end(); ++it) 
-            {
-            if((it->x >= m_SelectionBox[0]) && (it->x <= m_SelectionBox[1]) 
-              && (it->y >= m_SelectionBox[2]) && (it->y <= m_SelectionBox[3]))
-              it->selected = (button == 1);
-            }
-          ComputeEditBox();
-          }
-        return 1;
-        }
-      break;
-
-    case FL_SHORTCUT:
-      if(Fl::test_shortcut(FL_Enter))
-        {
-        m_Parent->GetParentUI()->OnAcceptPolygonAction(m_Parent->GetId());
-        return 1;
-        }
-      else if(Fl::test_shortcut(FL_Delete) || Fl::test_shortcut(FL_BackSpace))
-        {
-        if(m_SelectedVertices)
-          m_Parent->GetParentUI()->OnDeletePolygonSelectedAction(m_Parent->GetId());
-        return 1;
-        }
-      else if(Fl::test_shortcut(FL_Insert))
-        {
-        if(CanInsertVertices())
-          m_Parent->GetParentUI()->OnInsertIntoPolygonSelectedAction(m_Parent->GetId());
-        return 1;
-        }
-      else if(Fl::test_shortcut(FL_Escape))
-        {
-        Reset();
-        return 1;
-        }
-
-      break;
-
-    default: break;
-    }
-    break;
-
-  default: cerr << "PolygonDrawing::Handle(): unknown m_State " << m_State << endl;
-  }
-
-  return 0;
-}
-
-/**
- * Check if a click is within k pixels of a vertex, if so select the vertices
- * of that line segment
- */
-bool
-PolygonDrawing
-::CheckClickOnVertex(
-  float x, float y, float pixel_x, float pixel_y, int k)
-{
-  // check if clicked within 4 pixels of a node (use closest node)
-  VertexIterator itmin = m_Vertices.end();
-  double distmin = k;
-  for(VertexIterator it = m_Vertices.begin(); it!=m_Vertices.end(); ++it)  
-    {
-    Vector2d A(it->x / pixel_x, it->y / pixel_y); 
-    Vector2d C(x / pixel_x, y / pixel_y);
-    double dist = (A-C).inf_norm();
-
-    if(distmin > dist)
-      {
-      distmin = dist;
-      itmin = it;
-      }
-    }
-
-  if(itmin != m_Vertices.end())
-    {
-    itmin->selected = true;
-    return true;
-    }
-  else return false;
-}
-
-/**
- * Check if a click is within k pixels of a line segment, if so select the vertices
- * of that line segment
- */
-bool
-PolygonDrawing
-::CheckClickOnLineSegment(
-  float x, float y, float pixel_x, float pixel_y, int k)
-{
-  // check if clicked near a line segment
-  VertexIterator itmin1 = m_Vertices.end(), itmin2 = m_Vertices.end();
-  double distmin = k;
-  for(VertexIterator it = m_Vertices.begin(); it!=m_Vertices.end(); ++it)  
-    {
-    VertexIterator itnext = it;
-    if(++itnext == m_Vertices.end())
-      itnext = m_Vertices.begin();
-
-    Vector2d A(it->x / pixel_x, it->y / pixel_y); 
-    Vector2d B(itnext->x / pixel_x, itnext->y / pixel_y); 
-    Vector2d C(x / pixel_x, y / pixel_y);
-
-    double ab = (A - B).squared_magnitude();
-    if(ab > 0)
-      {
-      double alpha = - dot_product(A-B, B-C) / ab;
-      if(alpha > 0 && alpha < 1)
-        {
-        double dist = (alpha * A + (1-alpha) * B - C).magnitude();
-        if(distmin > dist)
-          {
-          distmin = dist;
-          itmin1 = it;
-          itmin2 = itnext;
-          }
-        }
-      }
-    }
-
-  if(itmin1 != m_Vertices.end())
-    {
-    itmin1->selected = true;
-    itmin2->selected = true;
-    return true;
-    }
-  else return false;
-}
-
-/* Can the polygon be closed? */
-bool 
-PolygonDrawing
-::CanClosePolygon()
-{
-  return m_Vertices.size() > 2;
-}
-
-/* Can last point be dropped? */
-bool 
-PolygonDrawing
-::CanDropLastPoint()
-{
-  return m_Vertices.size() > 0;
-}
-
-/* Can edges be split? */
-bool 
-PolygonDrawing
-::CanInsertVertices()
-{
-  return GetNumberOfSelectedSegments() > 0;
-}
-
-
-
-/*
- *$Log: PolygonDrawing.cxx,v $
- *Revision 1.15  2010/10/13 17:01:08  pyushkevich
- *Fixing warnings
- *
- *Revision 1.14  2010/10/09 04:20:08  pyushkevich
- *Added customization to polygon drawing appearance;ability to export/import appearance settings
- *
- *Revision 1.13  2010/06/15 16:27:44  pyushkevich
- *build errors fixed
- *
- *Revision 1.12  2010/05/27 11:16:22  pyushkevich
- *Further improved polygon drawing interface
- *
- *Revision 1.11  2010/05/27 07:29:36  pyushkevich
- *New popup menu for polygon drawing, other improvements to polygon tool
- *
- *Revision 1.10  2009/01/23 20:09:38  pyushkevich
- *FIX: 3D rendering now takes place in Nifti(RAS) world coordinates, rather than the VTK (x spacing + origin) coordinates. As part of this, itk::OrientedImage is now used for 3D images in SNAP. Still have to fix cut plane code in Window3D
- *
- *Revision 1.9  2008/10/24 12:52:08  pyushkevich
- *FIX: Bug on ITK 3.8 with level set being inverted
- *FIX: Bug with NIFTI orientation
- *ENH: Clean up itk extras directory
- *
- *Revision 1.8  2008/01/10 18:00:51  pyushkevich
- *took out test.png from Polygon drawing
- *
- *Revision 1.7  2007/12/30 04:43:03  pyushkevich
- *License/Packaging updates
- *
- *Revision 1.6  2007/12/25 15:46:23  pyushkevich
- *Added undo/redo functionality to itk-snap
- *
- *Revision 1.5  2007/10/01 00:13:15  pyushkevich
- *Polygon Drawing updates
- *
- *Revision 1.4  2007/09/18 18:42:40  pyushkevich
- *Added tablet drawing to polygon mode
- *
- *Revision 1.3  2007/09/04 16:56:13  pyushkevich
- *tablet support 1
- *
- *Revision 1.2  2006/12/06 01:26:07  pyushkevich
- *Preparing for 1.4.1. Seems to be stable in Windows but some bugs might be still there
- *
- *Revision 1.1  2006/12/02 04:22:27  pyushkevich
- *Initial sf checkin
- *
- *Revision 1.1.1.1  2006/09/26 23:56:18  pauly2
- *Import
- *
- *Revision 1.10  2005/12/19 03:43:12  pauly
- *ENH: SNAP enhancements and bug fixes for 1.4 release
- *
- *Revision 1.9  2005/12/08 18:20:46  hjohnson
- *COMP:  Removed compiler warnings from SGI/linux/MacOSX compilers.
- *
- *Revision 1.8  2004/07/22 19:22:50  pauly
- *ENH: Large image support for SNAP. This includes being able to use more screen real estate to display a slice, a fix to the bug with manual segmentation of images larger than the window size, and a thumbnail used when zooming into the image.
- *
- *Revision 1.7  2004/01/27 17:49:47  pauly
- *FIX: MAC OSX Compilation fixes
- *
- *Revision 1.6  2003/10/09 22:45:15  pauly
- *EMH: Improvements in 3D functionality and snake parameter preview
- *
- *Revision 1.5  2003/10/02 14:55:53  pauly
- *ENH: Development during the September code freeze
- *
- *Revision 1.1  2003/09/11 13:51:01  pauly
- *FIX: Enabled loading of images with different orientations
- *ENH: Implemented image save and load operations
- *
- *Revision 1.4  2003/08/28 14:37:09  pauly
- *FIX: Clean 'unused parameter' and 'static keyword' warnings in gcc.
- *FIX: Label editor repaired
- *
- *Revision 1.3  2003/08/27 14:03:23  pauly
- *FIX: Made sure that -Wall option in gcc generates 0 warnings.
- *FIX: Removed 'comment within comment' problem in the cvs log.
- *
- *Revision 1.2  2003/08/27 04:57:47  pauly
- *FIX: A large number of bugs has been fixed for 1.4 release
- *
- *Revision 1.1  2003/07/12 04:46:50  pauly
- *Initial checkin of the SNAP application into the InsightApplications tree.
- *
- *Revision 1.1  2003/07/11 23:28:10  pauly
- **** empty log message ***
- *
- *Revision 1.3  2003/06/08 23:27:56  pauly
- *Changed variable names using combination of ctags, egrep, and perl.
- *
- *Revision 1.2  2003/04/29 14:01:42  pauly
- *Charlotte Trip
- *
- *Revision 1.1  2003/03/07 19:29:47  pauly
- *Initial checkin
- *
- *Revision 1.2  2002/12/16 16:40:19  pauly
- **** empty log message ***
- *
- *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
- *Started the project repository
- *
- *
- *Revision 1.2  2002/03/08 14:06:30  moon
- *Added Header and Log tags to all files
- **/
diff --git a/UserInterface/SliceWindow/PolygonDrawing.h b/UserInterface/SliceWindow/PolygonDrawing.h
deleted file mode 100644
index 6cf0af9..0000000
--- a/UserInterface/SliceWindow/PolygonDrawing.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PolygonDrawing.h,v $
-  Language:  C++
-  Date:      $Date: 2010/05/27 11:16:22 $
-  Version:   $Revision: 1.7 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __PolygonDrawing_h_
-#define __PolygonDrawing_h_
-
-#include <FL/Fl.H>
-#include "SNAPOpenGL.h"
-
-#include <iostream>
-#include <list>
-#include "SNAPCommonUI.h"
-
-class GenericSliceWindow;
-
-namespace itk {
-  template <class TPixel, unsigned int VDimensions> class Image;
-};
-
-
-/**
- * \class PolygonDrawing
- * \brief Code for drawing and editing polygons
- */
-class PolygonDrawing
-{
-public:
-  // Type of image passed in for rasterization
-  typedef itk::Image<unsigned char, 2> ByteImageType;
-
-  /** States that the polygon drawing is in */
-  enum PolygonState { INACTIVE_STATE, DRAWING_STATE, EDITING_STATE };
-
-  /** Vertex structure */
-  struct Vertex 
-    { 
-    float x, y; 
-    bool selected;
-    bool control;
-    Vertex(float x_, float y_, bool on_, bool ctl_) 
-      : x(x_), y(y_), selected(on_), control(ctl_) {}
-    Vertex() : x(0.0f), y(0.0f), selected(false), control(true) {}
-    float &operator[](unsigned int i) 
-      { return (i==0) ? x : y; }
-    };
-
-  PolygonDrawing(GenericSliceWindow *parent);
-  virtual ~PolygonDrawing();
-  
-  void AcceptPolygon(ByteImageType *slice);
-  void PastePolygon(void);
-  void Draw(float pixel_x, float pixel_y);
-  int  Handle(int event, int button, float x, float y, float pixel_x, float pixel_y);
-
-  void Delete();
-  void Insert();
-  void Reset();
-
-  /* In drawing mode, remove the last point drawn */
-  void DropLastPoint();
-
-  /* In drawing mode, close the polygon (same as RMB) */
-  void ClosePolygon();
-
-  /* Can the polygon be closed? */
-  bool CanClosePolygon();
-
-  /* Can last point be dropped? */
-  bool CanDropLastPoint();
-
-  /* Can edges be split? */
-  bool CanInsertVertices();
-
-  /** Get the current state of the polygon editor */
-  irisGetMacro(State, PolygonState);
-  
-  /** How many vertices are selected */
-  irisGetMacro(SelectedVertices,bool);
-
-  /** How many vertices are selected */
-  irisGetMacro(CachedPolygon,bool);
-
-  /** Set the accuracy of freehand curve fitting */
-  irisGetMacro(FreehandFittingRate, double);
-  irisSetMacro(FreehandFittingRate, double);
-
-private:
-  // Array of vertices, cached vertices from last operation
-  typedef std::list<Vertex> VertexList;
-  typedef VertexList::iterator VertexIterator;
-  typedef VertexList::reverse_iterator VertexRIterator;
-  VertexList m_Vertices, m_Cache;
-  VertexList m_DragVertices;
-
-  // State of the system
-  PolygonState m_State;
-
-  bool m_CachedPolygon;
-  bool m_SelectedVertices;
-  bool m_DraggingPickBox;
-
-  // contains selected points
-  float m_EditBox[4];         
-
-  // box the user drags to select new points
-  float m_SelectionBox[4];         
-
-  float m_StartX, m_StartY;
-
-  void ComputeEditBox();
-  void Add(float x, float y, int selected);
-  void ProcessFreehandCurve();
-
-  bool CheckClickOnVertex(float x, float y, float pixel_x, float pixel_y, int k);
-  bool CheckClickOnLineSegment(float x, float y, float pixel_x, float pixel_y, int k);
-  int GetNumberOfSelectedSegments();
-
-  double m_FreehandFittingRate;
-
-  // Colors used to draw polygon
-  const static float 
-    m_DrawingModeColor[], m_EditModeSelectedColor[], m_EditModeNormalColor[];
-
-  // Parent object
-  GenericSliceWindow *m_Parent;
-};
-
-#endif // __PolygonDrawing_h_
-
-/*
- *$Log: PolygonDrawing.h,v $
- *Revision 1.7  2010/05/27 11:16:22  pyushkevich
- *Further improved polygon drawing interface
- *
- *Revision 1.6  2010/05/27 07:29:36  pyushkevich
- *New popup menu for polygon drawing, other improvements to polygon tool
- *
- *Revision 1.5  2007/12/30 04:05:28  pyushkevich
- *GPL License
- *
- *Revision 1.4  2007/12/25 15:46:23  pyushkevich
- *Added undo/redo functionality to itk-snap
- *
- *Revision 1.3  2007/10/01 00:13:15  pyushkevich
- *Polygon Drawing updates
- *
- *Revision 1.2  2007/09/18 18:42:40  pyushkevich
- *Added tablet drawing to polygon mode
- *
- *Revision 1.1  2006/12/02 04:22:27  pyushkevich
- *Initial sf checkin
- *
- *Revision 1.1.1.1  2006/09/26 23:56:18  pauly2
- *Import
- *
- *Revision 1.12  2005/12/19 03:43:12  pauly
- *ENH: SNAP enhancements and bug fixes for 1.4 release
- *
- *Revision 1.11  2005/02/04 17:01:09  lorensen
- *COMP: last of gcc 2.96 changes (I hope).
- *
- *Revision 1.10  2005/02/04 14:17:10  lorensen
- *COMP: gcc 2.96 problems.
- *
- *Revision 1.8  2004/07/22 19:22:51  pauly
- *ENH: Large image support for SNAP. This includes being able to use more screen real estate to display a slice, a fix to the bug with manual segmentation of images larger than the window size, and a thumbnail used when zooming into the image.
- *
- *Revision 1.7  2004/01/27 17:34:00  pauly
- *FIX: Compiling on Mac OSX, issue with GLU include file
- *
- *Revision 1.6  2003/10/09 22:45:15  pauly
- *EMH: Improvements in 3D functionality and snake parameter preview
- *
- *Revision 1.5  2003/10/02 20:57:46  pauly
- *FIX: Made sure that the previous check-in compiles on Linux
- *
- *Revision 1.4  2003/10/02 14:55:53  pauly
- *ENH: Development during the September code freeze
- *
- *Revision 1.1  2003/09/11 13:51:01  pauly
- *FIX: Enabled loading of images with different orientations
- *ENH: Implemented image save and load operations
- *
- *Revision 1.3  2003/08/27 14:03:23  pauly
- *FIX: Made sure that -Wall option in gcc generates 0 warnings.
- *FIX: Removed 'comment within comment' problem in the cvs log.
- *
- *Revision 1.2  2003/08/27 04:57:47  pauly
- *FIX: A large number of bugs has been fixed for 1.4 release
- *
- *Revision 1.1  2003/07/12 04:46:51  pauly
- *Initial checkin of the SNAP application into the InsightApplications tree.
- *
- *Revision 1.4  2003/07/12 01:34:18  pauly
- *More final changes before ITK checkin
- *
- *Revision 1.3  2003/07/11 23:28:10  pauly
- **** empty log message ***
- *
- *Revision 1.2  2003/06/08 23:27:56  pauly
- *Changed variable names using combination of ctags, egrep, and perl.
- *
- *Revision 1.1  2003/03/07 19:29:47  pauly
- *Initial checkin
- *
- *Revision 1.2  2002/12/16 16:40:19  pauly
- **** empty log message ***
- *
- *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
- *Started the project repository
- *
- *
- *Revision 1.2  2002/03/08 14:06:30  moon
- *Added Header and Log tags to all files
- **/
diff --git a/UserInterface/SliceWindow/PolygonInteractionMode.cxx b/UserInterface/SliceWindow/PolygonInteractionMode.cxx
deleted file mode 100644
index fd28e82..0000000
--- a/UserInterface/SliceWindow/PolygonInteractionMode.cxx
+++ /dev/null
@@ -1,113 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PolygonInteractionMode.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/05/27 07:29:36 $
-  Version:   $Revision: 1.8 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
-     PURPOSE.  See the above copyright notices for more information.
-=========================================================================*/
-#include "PolygonInteractionMode.h"
-
-#include "GlobalState.h"
-#include "PolygonDrawing.h"
-#include "UserInterfaceBase.h"
-#include "IRISApplication.h"
-
-PolygonInteractionMode
-::PolygonInteractionMode(GenericSliceWindow *parent)
-: GenericSliceWindow::EventHandler(parent)
-{
-  m_Drawing = new PolygonDrawing(parent);
-}
-
-PolygonInteractionMode
-::~PolygonInteractionMode()
-{
-  delete m_Drawing;
-}
-
-int
-PolygonInteractionMode
-::OnEitherEvent(const FLTKEvent &event, 
-                const FLTKEvent &irisNotUsed(pressEvent))
-{
-
-  // We'll need these shorthands
-  int id = m_Parent->m_Id;
-
-#ifdef DRAWING_LOCK
-  if (!m_GlobalState->GetDrawingLock(id)) break;
-#endif /* DRAWING_LOCK */
-
-  // Compute the dimension of a pixel on the screen
-  Vector2f pixelSize = GetPixelSizeVector();
-
-  // Masquerade keypress events as mouse-clicks at the cursor position
-  int rc;
-  if(event.Key == ' ') 
-    {
-    // Map the cursor position into slice coordinates
-    Vector3f xEvent = m_Parent->MapImageToSlice(
-      to_float(m_Driver->GetCursorPosition()));
-
-    // Get the event state based on shift-ctrl
-    int fakeButton = (event.State & FL_SHIFT) ? FL_RIGHT_MOUSE : FL_LEFT_MOUSE;
-
-    // Handle the event
-    rc = m_Drawing->Handle(FL_PUSH, fakeButton, xEvent(0), xEvent(1),
-                      pixelSize(0),pixelSize(1));
-    }
-  else
-    {
-    // Map the event into slice coordinates 
-    Vector3f xEvent = m_Parent->MapWindowToSlice(event.XSpace.extract(2));
-
-    // Handle the event
-    rc = m_Drawing->Handle(event.Id,event.SoftButton,xEvent(0),xEvent(1),
-                      pixelSize(0),pixelSize(1));
-    }
-
-#ifdef DRAWING_LOCK
-  m_GlobalState->ReleaseDrawingLock(id);
-#endif /* DRAWING_LOCK */
-  
-  // Update the display
-  m_Parent->GetCanvas()->redraw();
-  
-  // Let the parent UI know that the polygon state has changed
-  m_ParentUI->OnPolygonStateUpdate(id);
-
-  // Even though no action may have been performed, we don't want other handlers
-  // to get the left and right mouse button events
-  return rc;
-}
-
-Vector2f 
-PolygonInteractionMode
-::GetPixelSizeVector()
-{
-  Vector3f x = 
-    m_Parent->MapWindowToSlice(Vector2f(1.0f)) - 
-    m_Parent->MapWindowToSlice(Vector2f(0.0f));
-
-  return Vector2f(x[0],x[1]);
-}
-
-                          
-void
-PolygonInteractionMode
-::OnDraw()
-{
-  // Compute the dimension of a pixel on the screen
-  Vector2f pixelSize = GetPixelSizeVector();
-
-  // Call the poly's draw method
-  m_Drawing->Draw(pixelSize(0),pixelSize(1));
-}
-
diff --git a/UserInterface/SliceWindow/PolygonInteractionMode.h b/UserInterface/SliceWindow/PolygonInteractionMode.h
deleted file mode 100644
index 55e3526..0000000
--- a/UserInterface/SliceWindow/PolygonInteractionMode.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PolygonInteractionMode.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:43:03 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __PolygonInteractionMode_h_
-#define __PolygonInteractionMode_h_
-
-#include "GenericSliceWindow.h"
-#include "PolygonDrawing.h"
-
-/**
- * \class PolygonInteractionMode
- * \brief UI interaction mode that takes care of polygon drawing and editing.
- *
- * \see GenericSliceWindow
- */
-class PolygonInteractionMode : public GenericSliceWindow::EventHandler 
-{
-public:
-  PolygonInteractionMode(GenericSliceWindow *parent);
-  virtual ~PolygonInteractionMode();
-
-  int OnMousePress(const FLTKEvent &event)
-  {
-    return OnEitherEvent(event,event);
-  }
-
-  int OnKeyDown(const FLTKEvent &event)
-  {
-    return OnEitherEvent(event,event);
-  }
-
-  int OnMouseRelease(const FLTKEvent &event, const FLTKEvent &pressEvent)
-  {
-    return OnEitherEvent(event,pressEvent);
-  }
-
-  int OnMouseDrag(const FLTKEvent &event, const FLTKEvent &pressEvent)
-  {
-    return OnEitherEvent(event,pressEvent);
-  }
-
-  int OnShortcut(const FLTKEvent &event)
-  {
-    return OnEitherEvent(event,event);
-  }
-
-
-
-  void OnDraw();  
-private:
-
-  /**
-   * The polygon handling object
-   */
-  PolygonDrawing *m_Drawing;
-
-  /** Handler that gets envoked regardless of the event */
-  int OnEitherEvent(const FLTKEvent &event, const FLTKEvent &pressEvent);
-
-  /** Get a vector that represents the size of the pixel on the screen */
-  Vector2f GetPixelSizeVector();
-
-  // The window handler needs to access our privates
-  friend class IRISSliceWindow;
-};
-
-
-
-#endif // __PolygonInteractionMode_h_
diff --git a/UserInterface/SliceWindow/PolygonScanConvert.cxx b/UserInterface/SliceWindow/PolygonScanConvert.cxx
deleted file mode 100644
index 39db51c..0000000
--- a/UserInterface/SliceWindow/PolygonScanConvert.cxx
+++ /dev/null
@@ -1,177 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PolygonScanConvert.cxx,v $
-  Language:  C++
-  Date:      $Date: 2009/01/23 20:09:38 $
-  Version:   $Revision: 1.8 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "PolygonScanConvert.h"
-#include "SNAPCommon.h"
-#include "itkOrientedImage.h"
-
-#include <iostream>
-
-// Typecast for the callback functions
-#ifdef WIN32
-typedef void (CALLBACK *TessCallback)();
-#elif defined (__APPL__)
-typedef GLvoid (*TessCallback)(...);
-#else
-typedef void (*TessCallback)();
-#endif
-
-void 
-PolygonScanConvertBase
-::RasterizeFilled(double *vArray, unsigned int nVertices, 
-  unsigned int width, unsigned int height, GLenum glType, void *buffer)
-{
-  // Push the GL attributes to preserve everything
-  glPushAttrib(GL_ALL_ATTRIB_BITS);
-
-  // Tesselate the polygon and save the tesselation as a display list
-  GLint dl = glGenLists(1);
-  glNewList(dl, GL_COMPILE);
-
-  // Set the background to black
-  glClearColor(0,0,0,1);
-  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-  // Paint in white
-  glColor3d(1.0, 1.0, 1.0);
-
-  // Start the tesselation
-  GLUtesselator *tess = gluNewTess();
-  gluTessCallback(tess,(GLenum) GLU_TESS_VERTEX, (TessCallback) &glVertex3dv);
-  gluTessCallback(tess,(GLenum) GLU_TESS_BEGIN, (TessCallback) &glBegin); 
-  gluTessCallback(tess,(GLenum) GLU_TESS_END, (TessCallback) &glEnd);
-  gluTessCallback(tess,(GLenum) GLU_TESS_ERROR, 
-    (TessCallback) &PolygonScanConvertBase::ErrorCallback);     
-  gluTessCallback(tess,(GLenum) GLU_TESS_COMBINE, 
-    (TessCallback) &PolygonScanConvertBase::CombineCallback);
-  gluTessProperty(tess,(GLenum) GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);  
-  gluTessNormal(tess,0.0,0.0,1.0);
-
-  gluTessBeginPolygon(tess,NULL);
-  gluTessBeginContour(tess);
-
-  // Add the vertices
-  for(unsigned int i=0; i < nVertices; i++)
-    { gluTessVertex(tess, vArray + 3*i, vArray + 3*i); }
-    
-  // End the tesselation
-  gluTessEndContour(tess);
-  gluTessEndPolygon(tess);
-
-  // End the display list
-  glEndList();
-
-  // Draw polygon into back buffer - back buffer should get redrawn
-  // anyway before it gets swapped to the screen.
-  glDrawBuffer(GL_BACK);
-  glReadBuffer(GL_BACK);
-
-  // We will perform a tiled drawing, because the backbuffer may be smaller
-  // than the size of the image. First get the viewport size, i.e., tile size
-  GLint xViewport[4]; glGetIntegerv(GL_VIEWPORT, xViewport);
-  unsigned int wTile = (unsigned int) xViewport[2];
-  unsigned int hTile = (unsigned int) xViewport[3];
-
-  // Figure out the number of tiles in x and y dimension
-  unsigned int nTilesX = (unsigned int) ceil( width * 1.0 / wTile );
-  unsigned int nTilesY = (unsigned int) ceil( height * 1.0 / hTile );
-
-  // Draw and retrieve each tile
-  for(unsigned int iTileX = 0; iTileX < nTilesX; iTileX++)
-    {
-    for(unsigned int iTileY = 0; iTileY < nTilesY; iTileY++)
-      {
-      // Get the corner of the tile
-      unsigned int xTile = iTileX * wTile, yTile = iTileY * hTile;
-
-      // Set the projection matrix
-      glMatrixMode(GL_PROJECTION);
-      glPushMatrix();
-      glLoadIdentity();
-      gluOrtho2D(xTile, xTile + wTile, yTile, yTile + hTile);
-
-      // Set the model view matrix
-      glMatrixMode(GL_MODELVIEW);
-      glPushMatrix();
-      glLoadIdentity();
-
-      // Draw the triangles
-      glCallList(dl);
-
-      // Figure out the size of the data chunk to copy
-      unsigned int wCopy = width - xTile < wTile ? width - xTile : wTile;
-      unsigned int hCopy = height - yTile < hTile ? height - yTile : hTile;
-      
-      // Set up the copy so that the strides are correct
-      glPixelStorei(GL_PACK_ALIGNMENT, 1);
-      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-      glPixelStorei(GL_PACK_ROW_LENGTH, width);
-      glPixelStorei(GL_PACK_SKIP_PIXELS, xTile);
-      glPixelStorei(GL_PACK_SKIP_ROWS, yTile);
-
-      // Copy the pixels to the buffer
-      glReadPixels(0, 0, wCopy, hCopy, GL_RED, glType, buffer);
-
-      // Restore the GL state
-      glPopMatrix();
-      glMatrixMode(GL_PROJECTION);
-      glPopMatrix();
-      }
-    }
-
-  // Get rid of the display list
-  glDeleteLists(dl,1);
-
-  // Delete the tesselator
-  gluDeleteTess(tess);
-
-  // Restore the GL state
-  glPopAttrib();
-}
-
-void PolygonScanConvertBase::ErrorCallback(GLenum errorCode)
-{ 
-  std::cerr << "Tesselation Error: " << gluErrorString(errorCode) << std::endl; 
-}
-
-void PolygonScanConvertBase::CombineCallback(GLdouble coords[3], 
-                GLdouble **vertex_data,  
-                GLfloat *weight, 
-                GLdouble **dataOut) 
-{
-  GLdouble *vertex = new GLdouble[3];
-  vertex[0] = coords[0]; vertex[1] = coords[1]; vertex[2] = coords[2];
-  *dataOut = vertex;
-}
-
diff --git a/UserInterface/SliceWindow/PolygonScanConvert.h b/UserInterface/SliceWindow/PolygonScanConvert.h
deleted file mode 100644
index 6102dd6..0000000
--- a/UserInterface/SliceWindow/PolygonScanConvert.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PolygonScanConvert.h,v $
-  Language:  C++
-  Date:      $Date: 2009/01/23 20:09:38 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __PolygonScanConvert_h_
-#define __PolygonScanConvert_h_
-
-#include "SNAPOpenGL.h"
-#include "itkOrientedImage.h"
-
-class PolygonScanConvertBase
-{
-public:
-  // Private version of the method, takes a flattened array of coordinates
-  // and is not templated
-  static void RasterizeFilled(
-    double *vArray, unsigned int nVertices, 
-    unsigned int width, unsigned int height, 
-    GLenum glType, void *buffer);
-
-  // Callbacks for tesselation
-  static void ErrorCallback(GLenum errorCode);
-  static void CombineCallback(
-    GLdouble coords[3], GLdouble **vertex_data,  
-    GLfloat *weight, GLdouble **dataOut);
-};
-
-template<class TPixel, GLenum VGlPixelType, class TVertexIterator>
-class PolygonScanConvert : public PolygonScanConvertBase
-{
-public:
-  typedef itk::Image<TPixel, 2> ImageType;
-
-  /** 
-   * This method uses OpenGL to scan-convert a polygonal curve. The input is a pair 
-   * of iterators (begin, end) to a list/array of double arrays or vectors, i.e., 
-   * objects for which indices [0] and [1] are supported.
-   */
-  static void RasterizeFilled(
-    TVertexIterator first, unsigned int n, ImageType *image)
-    {
-    double *vArray = new double[3 * (n + 1)], *vPointer = vArray;
-    for (unsigned int i = 0; i < n; ++i, ++first)
-      {
-      *vPointer++ = (double) (*first)[0];
-      *vPointer++ = (double) (*first)[1];
-      *vPointer++ = 0.0;
-      }
-  
-    // Set up the image properties
-    unsigned int width  = image->GetBufferedRegion().GetSize()[0];
-    unsigned int height = image->GetBufferedRegion().GetSize()[1];
-    PolygonScanConvertBase::RasterizeFilled(
-      vArray, n, width, height, VGlPixelType, image->GetBufferPointer());
-    delete vArray;
-    }
-
-private:
-
-
-};
-
-#endif
-
diff --git a/UserInterface/SliceWindow/PopupButtonInteractionMode.cxx b/UserInterface/SliceWindow/PopupButtonInteractionMode.cxx
deleted file mode 100644
index beaa70f..0000000
--- a/UserInterface/SliceWindow/PopupButtonInteractionMode.cxx
+++ /dev/null
@@ -1,120 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PopupButtonInteractionMode.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/12 16:02:05 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "PopupButtonInteractionMode.h"
-#include "SNAPOpenGL.h"
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-#include "SNAPAppearanceSettings.h"
-#include "UserInterfaceBase.h"
-#include "SliceWindowCoordinator.h"
-#include "UserInterfaceLogic.h"
-
-PopupButtonInteractionMode
-::PopupButtonInteractionMode(GenericSliceWindow *parent)
-: GenericSliceWindow::EventHandler(parent)
-{
-}
-
-#include <FL/Fl_Menu_Button.H>
-#include <FL/Fl_Menu_Bar.H>
-
-int 
-PopupButtonInteractionMode
-::OnMousePress (const FLTKEvent &event)
-{
-  // Only draw when UI is not visible
-  DisplayLayout dl = m_ParentUI->GetDisplayLayout();
-  if(dl.show_main_ui)
-    return 0;
-  
-  // Get the coordiantes of the mouse click
-  int w = this->GetCanvas()->w();
-  int h = this->GetCanvas()->h();
-  int x = event.XCanvas[0], y = event.XCanvas[1];
-
-  if(x <= w-5 && x >= w-15 && y <= h-5 && y >= h-15 
-    && (x - (w-15)) > ((h-5) - y))
-    {
-    // Dynamically create menu, pop it up
-    Fl_Menu_Button menu(Fl::event_x_root(), Fl::event_y_root(), 80, 1);
-    Fl_Menu_Bar *bar = m_ParentUI->GetMainMenuBar();
-    menu.copy(bar->menu());
-
-    // Put the menu so that it's as deep in the widget hierarchy as the main menubar
-    Fl_Group g1(Fl::event_x_root(), Fl::event_y_root(), 80, 1);
-    Fl_Group g2(Fl::event_x_root(), Fl::event_y_root(), 80, 1);
-    m_ParentUI->GetMainWindow()->add(g1);
-    g1.add(g2);
-    g2.add(menu);
-
-    // Popup
-    menu.popup();
-    m_ParentUI->GetMainWindow()->remove(g1);
-    g1.remove(g2);
-    g2.remove(menu);
-
-    // Eat up the event
-    return 1;
-    }
-
-  return 0;
-}
-
-void
-PopupButtonInteractionMode
-::OnDraw()
-{
-  // Only draw when UI is not visible
-  DisplayLayout dl = m_ParentUI->GetDisplayLayout();
-  if(dl.show_main_ui)
-    return;
-  
-  // Set line properties
-  glPushAttrib(GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT);
-
-  glColor3d(0.0, 0.75, 0.0);
-
-  int w = this->GetCanvas()->w();
-  int h = this->GetCanvas()->h();
-
-  glDisable(GL_LIGHTING);
-  glBegin(GL_TRIANGLES);
-  glVertex2f(w-5,  h-5);
-  glVertex2f(w-5,  h-15);
-  glVertex2f(w-15, h-5);
-  glEnd();
-
-  glPopAttrib();
-}
diff --git a/UserInterface/SliceWindow/PopupButtonInteractionMode.h b/UserInterface/SliceWindow/PopupButtonInteractionMode.h
deleted file mode 100644
index 42dcb06..0000000
--- a/UserInterface/SliceWindow/PopupButtonInteractionMode.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: PopupButtonInteractionMode.h,v $
-  Language:  C++
-  Date:      $Date: 2010/05/27 07:29:36 $
-  Version:   $Revision: 1.1 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __PopupButtonInteractionMode_h_
-#define __PopupButtonInteractionMode_h_
-
-#include "GenericSliceWindow.h"
-#include "GlobalState.h"
-
-/**
- * \class PopupButtonInteractionMode
- * \brief UI interaction mode that takes care of crosshair positioning.
- *
- * \see GenericSliceWindow
- */
-class PopupButtonInteractionMode : public GenericSliceWindow::EventHandler {
-public:
-
-  PopupButtonInteractionMode(GenericSliceWindow *parent);
-  void OnDraw(); 
-  int OnMousePress(const FLTKEvent &event);
-};
-
-#endif // __PopupButtonInteractionMode_h_
-
diff --git a/UserInterface/SliceWindow/RegionInteractionMode.cxx b/UserInterface/SliceWindow/RegionInteractionMode.cxx
deleted file mode 100644
index 728db4b..0000000
--- a/UserInterface/SliceWindow/RegionInteractionMode.cxx
+++ /dev/null
@@ -1,350 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: RegionInteractionMode.cxx,v $
-  Language:  C++
-  Date:      $Date: 2008/02/10 23:55:22 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "RegionInteractionMode.h"
-
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-#include "IRISSliceWindow.h"
-#include "UserInterfaceBase.h"
-#include "IRISVectorTypesToITKConversion.h"
-#include "SNAPAppearanceSettings.h"
-
-#include <assert.h>
-#include <cmath>
-
-// The click detection radius (delta)
-const unsigned int RegionInteractionMode::m_PixelDelta = 4;
-
-RegionInteractionMode
-::RegionInteractionMode(GenericSliceWindow *parent)
-:GenericSliceWindow::EventHandler(parent)
-{
-  // Initialize the edges
-  for(unsigned int dir=0;dir<2;dir++) 
-  {
-    for(unsigned int i=0;i<2;i++) 
-    {
-      m_EdgeHighlighted[dir][i] = false;
-    }
-  }
-}
-
-void 
-RegionInteractionMode
-::GetEdgeVertices(unsigned int direction,unsigned int index,
-                  Vector2f &x0,Vector2f &x1, 
-                  const Vector3f corner[2])
-{
-  x0(direction) = corner[0](direction);
-  x1(direction) = corner[1](direction);
-  x0(1-direction) = x1(1-direction) = corner[index](1-direction);
-}
-
-float
-RegionInteractionMode
-::GetEdgeDistance(unsigned int direction,
-                  unsigned int index,
-                  const Vector2f &x,
-                  const Vector3f corner[2])
-{
-  // Compute the vertices of the edge
-  Vector2f x0,x1;
-  GetEdgeVertices(direction,index,x0,x1,corner);
-  
-  // Compute the squared distance between the vertices
-  float l2 = (x1-x0).squared_magnitude();
-  float l = sqrt(l2);
-  
-  // Compute the projection of x onto x1-x0
-  float p = dot_product(x-x0,x1-x0) / sqrt(l2);
-  float p2 = p*p;
-  
-  // Compute the squared distance to the line of the edge
-  float q2 = (x-x0).squared_magnitude() - p2;
-
-  // Compute the total distance
-  float d = sqrt(q2 + (p < 0 ? p2 : 0) + (p > l ? (p-l)*(p-l) : 0));
-
-  // Return this distance
-  return d;
-}
-
-int RegionInteractionMode
-::OnMousePress(const FLTKEvent &event)
-{
-  // Flag indicating whether we respond to this event or not
-  m_IsAnyEdgeHighlighted = false;
-  
-  // Convert the event location into slice u,v coordinates
-  Vector3f xSlice = m_Parent->MapWindowToSlice(event.XSpace.extract(2));    
-  Vector2f uvSlice(xSlice(0),xSlice(1));
-  
-  // Record the system's corners at the time of drag start
-  GetSystemROICorners(m_CornerDragStart);
-    
-  // Repeat for vertical and horizontal edges
-  for(unsigned int dir=0;dir<2;dir++) 
-  {
-    // Variables used to find the closest edge that's within delta
-    int iClosest = -1;
-    float dToClosest = m_PixelDelta;
-
-    // Search for the closest edge
-    for(unsigned int i=0;i<2;i++) 
-    {
-      float d = GetEdgeDistance(dir,i,uvSlice,m_CornerDragStart);
-      if(d < dToClosest) 
-      {
-        dToClosest = d;
-        iClosest = i;
-      }
-    }
-
-    // Highlight the selected edge
-    if(iClosest >= 0) 
-      {
-      m_EdgeHighlighted[dir][iClosest] = true;
-      m_IsAnyEdgeHighlighted = true;
-      }      
-  }
-
-  // If nothing was highlighted, then return and let the next handler process
-  // the event
-  if(!m_IsAnyEdgeHighlighted)
-    return 0;
-
-  // Event has been handled
-  return 1;
-}
-
-void RegionInteractionMode
-::GetSystemROICorners(Vector3f corner[2])
-{
-  // Get the region of interest in image coordinates  
-  GlobalState::RegionType roi = m_GlobalState->GetSegmentationROI();
-
-  // Get the lower-valued corner
-  Vector3l ul(roi.GetIndex().GetIndex());
-  
-  // Get the higher valued corner
-  Vector3ul sz(roi.GetSize().GetSize());
-
-  // Remap to slice coordinates
-  corner[0] = m_Parent->MapImageToSlice(to_float(ul));
-  corner[1] = m_Parent->MapImageToSlice(to_float(ul+to_long(sz)));
-}
-
-void RegionInteractionMode
-::UpdateCorners(const FLTKEvent &event, const FLTKEvent &pressEvent)
-{
-  // Compute the corners in slice coordinates
-  Vector3f corner[2];
-  GetSystemROICorners(corner);
-
-  // Convert the location of the events into slice u,v coordinates
-  Vector3f uvSliceNow = 
-    m_Parent->MapWindowToSlice(event.XSpace.extract(2));
-  Vector3f uvSlicePress = 
-    m_Parent->MapWindowToSlice(pressEvent.XSpace.extract(2));
-
-  // Get the current bounds and extents of the region of interest 
-  Vector3f xCornerImage[2] = 
-  {
-    m_Parent->MapSliceToImage(corner[0]),
-    m_Parent->MapSliceToImage(corner[1])
-  };
-
-  // TODO: For dragging entire region, the clamps should be just image extents
-  // Compute the clamps for each of the corners
-  Vector3f clamp[2][2] = 
-  {
-    {
-      Vector3f(0.0f,0.0f,0.0f),
-      xCornerImage[1] - Vector3f(1.0f,1.0f,1.0f)
-    },
-    {
-      xCornerImage[0] + Vector3f(1.0f,1.0f,1.0f),
-      to_float( m_Driver->GetCurrentImageData()->GetVolumeExtents())
-    }
-  };
-
-  // For each highlighted edge, update the coordinates of the affected vertex
-  // by clamping to the maximum range
-  for (unsigned int dir=0;dir<2;dir++)
-    {
-    for (unsigned int i=0;i<2;i++)
-      {
-      if (m_EdgeHighlighted[dir][i])
-        {
-        // Horizontal edge affects the y of the vertex and vice versa
-        corner[i](1-dir) =
-          m_CornerDragStart[i](1-dir) + uvSliceNow(1-dir) - uvSlicePress(1-dir);
-
-        // Map the affected vertex to image space
-        Vector3f vImage = m_Parent->MapSliceToImage(corner[i]);
-
-        // Clamp the affected vertex in image space
-        Vector3f vImageClamped = vImage.clamp(clamp[i][0],clamp[i][1]);
-
-        // Map the affected vertex back into slice space
-        corner[i] = m_Parent->MapImageToSlice(vImageClamped);
-        }
-      }
-    }
-
-  // Update the region of interest in the system
-  Vector3i xImageLower = to_int(m_Parent->MapSliceToImage(corner[0]));
-  Vector3i xImageUpper = to_int(m_Parent->MapSliceToImage(corner[1]));
-
-  // Create a region based on the corners
-  GlobalState::RegionType roiCorner(
-    to_itkIndex(xImageLower),to_itkSize(xImageUpper-xImageLower));
-
-  // Get the system's region of interest
-  GlobalState::RegionType roiSystem = m_GlobalState->GetSegmentationROI();
-
-  // The slice z-direction index and size in the ROI should retain the system's
-  // previous value because we are only manipulating the slice in 2D
-  unsigned int idx = m_Parent->m_ImageAxes[2];
-  roiCorner.SetIndex(idx,roiSystem.GetIndex(idx));
-  roiCorner.SetSize(idx,roiSystem.GetSize(idx));
-
-  // Update the system's ROI
-  m_GlobalState->SetSegmentationROI(roiCorner);
-
-  // Cause a system redraw
-  m_ParentUI->RedrawWindows();
-}
-
-int RegionInteractionMode
-::OnMouseDrag(const FLTKEvent &event, const FLTKEvent &pressEvent)
-{
-  // Only do something if there is a highlight
-  if(m_IsAnyEdgeHighlighted)
-    {
-    // Update the corners in response to the dragging
-    UpdateCorners(event,pressEvent);
-    
-    // Event has been handled
-    return 1;
-    }
-  
-  return 0;
-}
-
-int RegionInteractionMode
-::OnMouseRelease(const FLTKEvent &event, const FLTKEvent &pressEvent)
-{
-  // Only do something if there is a highlight
-  if(m_IsAnyEdgeHighlighted)
-    {
-    // Update the corners in response to the dragging
-    UpdateCorners(event,pressEvent);
-    
-    // Clear highlights of the connected edges
-    for(unsigned int i=0;i<2;i++)
-      m_EdgeHighlighted[0][i] = m_EdgeHighlighted[1][i] = false;
-
-    // Clear the summary highlight flag
-    m_IsAnyEdgeHighlighted = false;
-    
-    // Event has been handled
-    return 1;
-    }
-  
-  // Event has not been handled
-  return 0;
-}
-
-void
-RegionInteractionMode
-::OnDraw()
-{
-  // The region of interest should be in effect
-  assert(m_GlobalState->GetIsValidROI());
-
-  // Compute the corners in slice coordinates
-  Vector3f corner[2];
-  GetSystemROICorners(corner);
-
-  // Check that the current slice is actually within the bounding box
-  // int slice = m_Parent->m_SliceIndex;
-  int dim = m_Parent->m_ImageAxes[2];
-  int slice = m_Driver->GetCursorPosition()[dim];
-  int bbMin = m_GlobalState->GetSegmentationROI().GetIndex(dim);
-  int bbMax = bbMin + m_GlobalState->GetSegmentationROI().GetSize(dim);
-
-  // And if so, return without painting anything
-  if(bbMin > slice || bbMax <= slice)
-    return;
-
-  // Get the line color, thickness and dash spacing
-  const SNAPAppearanceSettings::Element &elt = 
-    m_ParentUI->GetAppearanceSettings()->GetUIElement(
-    SNAPAppearanceSettings::ROI_BOX);
-
-  // Set line properties
-  glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT);
-
-  // Apply the line properties
-  SNAPAppearanceSettings::ApplyUIElementLineSettings(elt);
-
-  // Start drawing the lines
-  glBegin(GL_LINES);
-  
-  // Draw each of the edges
-  for(unsigned int dir=0;dir<2;dir++)
-  {
-    for(unsigned int i=0;i<2;i++)
-    {
-    // Select color according to edge state
-    glColor3dv( m_EdgeHighlighted[dir][i] ? 
-      elt.ActiveColor.data_block() : elt.NormalColor.data_block() );
-
-    // Compute the vertices of the edge
-    Vector2f x0,x1;
-    GetEdgeVertices(dir,i,x0,x1,corner);
-
-    // Draw the line
-    glVertex2f(x0[0],x0[1]);
-    glVertex2f(x1[0],x1[1]);
-    }
-  }
-
-  glEnd();
-  glPopAttrib();
-}
-
-
diff --git a/UserInterface/SliceWindow/RegionInteractionMode.h b/UserInterface/SliceWindow/RegionInteractionMode.h
deleted file mode 100644
index e52d9ec..0000000
--- a/UserInterface/SliceWindow/RegionInteractionMode.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: RegionInteractionMode.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:28 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __RegionInteractionMode_h_
-#define __RegionInteractionMode_h_
-
-#include "GenericSliceWindow.h"
-
-/**
- * \class RegionInteractionMode
- * \brief UI interaction mode that takes care of ROI positioning.
- *
- * \see GenericSliceWindow
- */
-class RegionInteractionMode : public GenericSliceWindow::EventHandler {
-public:
-  RegionInteractionMode(GenericSliceWindow *parent);
-  int OnMousePress(const FLTKEvent &event);
-  int OnMouseRelease(const FLTKEvent &event, const FLTKEvent &pressEvent);    
-  int OnMouseDrag(const FLTKEvent &event, const FLTKEvent &pressEvent);
-  void OnDraw();
-
-private:  
-
-  // The click detection radius (delta)
-  static const unsigned int m_PixelDelta;
-
-  // Four vertices in the region box (correspond to the two corners 
-  // of the 3D region of interest
-  Vector3f m_CornerDragStart[2];
-
-  /**
-   * The four edges in the rectangle, ordered first by orientation
-   * (0 = horizontal), (1 = vertical) and then by adjacency to the 
-   * first or second vertex of the cardinal cube defining the region
-   * of interest (0 = closest to 0,0,0), (1 = closest to sx,sy,sz)
-   */
-  bool m_EdgeHighlighted[2][2];
-
-  /**
-   * Is any one of the edges highlighted?
-   */
-  bool m_IsAnyEdgeHighlighted;
-
-  /** Map from system's ROI in image coordinates to 2D slice coords */
-  void GetSystemROICorners(Vector3f corner[2]);
-
-  /** Compute the slice-space vertices corresponding to an edge */
-  void GetEdgeVertices(unsigned int direction,
-    unsigned int index,Vector2f &x0,Vector2f &x1,const Vector3f corner[2]);
-
-  /** Compute a distance to an edge */
-  float GetEdgeDistance(unsigned int direction,
-    unsigned int index,const Vector2f &point,const Vector3f corner[2]);
-
-  /**
-   * Update the region of interest in response to the dragging or release
-   * operations.
-   */
-  void UpdateCorners(const FLTKEvent &event,const FLTKEvent &pressEvent);
-};
-
-#endif // __RegionInteractionMode_h_
diff --git a/UserInterface/SliceWindow/SNAPSliceWindow.cxx b/UserInterface/SliceWindow/SNAPSliceWindow.cxx
deleted file mode 100644
index 90c0642..0000000
--- a/UserInterface/SliceWindow/SNAPSliceWindow.cxx
+++ /dev/null
@@ -1,179 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SNAPSliceWindow.cxx,v $
-  Language:  C++
-  Date:      $Date: 2009/08/25 21:38:16 $
-  Version:   $Revision: 1.7 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-// Borland compiler is very lazy so we need to instantiate the template
-//  by hand 
-#if defined(__BORLANDC__)
-#include <itkCommand.h>
-#include <itkSmartPointer.h>
-typedef itk::SmartPointer<itk::Command> SNAPSliceWindowDummyCommandSPType;
-#include "SNAPBorlandDummyTypes.h"
-#endif
-
-#include "SNAPSliceWindow.h"
-
-#include "BubblesInteractionMode.h"
-#include "GlobalState.h"
-#include "SNAPImageData.h"
-#include "SNAPAppearanceSettings.h"
-#include "OpenGLSliceTexture.h"
-#include "UserInterfaceBase.h"
-
-SNAPSliceWindow
-::SNAPSliceWindow(int id, UserInterfaceBase *parentUI, FLTKCanvas *canvas) 
-: GenericSliceWindow(id, parentUI, canvas)
-{
-  // Initialize the texture for displaying the speed image
-  m_SpeedTexture = new OpenGLSliceTexture;
-  m_SpeedTexture->SetGlComponents(4);
-  m_SpeedTexture->SetGlFormat(GL_RGBA);
-  m_SpeedTexture->SetGlType(GL_UNSIGNED_BYTE);
-
-  // Initialize the snake image texture
-  m_SnakeTexture = new OpenGLSliceTexture;
-  m_SnakeTexture->SetGlComponents(4);
-  m_SnakeTexture->SetGlFormat(GL_RGBA);
-  m_SnakeTexture->SetGlType(GL_UNSIGNED_BYTE);
-
-  // Initialize the overlay texture
-  m_OverlayTexture = new OpenGLSliceTexture;
-  m_OverlayTexture->SetGlComponents(4);
-  m_OverlayTexture->SetGlFormat(GL_RGBA);
-  m_OverlayTexture->SetGlType(GL_UNSIGNED_BYTE);
-
-  // Initialize the bubbles interaction mode
-  m_BubblesMode = new BubblesInteractionMode(this);
-
-  // Register the interaction modes
-  m_BubblesMode->Register();
-}
-
-SNAPSliceWindow
-::~SNAPSliceWindow()
-{
-  delete m_SpeedTexture;
-}
-
-void 
-SNAPSliceWindow
-::InitializeSlice(GenericImageData *imageData)
-{
-  // Call parent's init
-  GenericSliceWindow::InitializeSlice(imageData);
-  if(!imageData->IsMainLoaded())
-	return;
-
-  // Set the pointer to the SNAP data
-  m_ImageData = dynamic_cast<SNAPImageData *>(imageData);
-
-  // Test that the cast worked
-  assert(m_ImageData);
-}
-
-void SNAPSliceWindow
-::DrawMainTexture()
-{
-  // The preprocessing image is shown when the corresponding flag is set and 
-  // the display mode is not set to overlay
-  if(m_GlobalState->GetShowSpeed() && !m_GlobalState->GetSpeedViewZero())
-    {
-    // We should have a slice to draw
-    assert(m_ImageData->IsSpeedLoaded() && m_ImageSliceIndex >= 0);
-
-    // Get the color to use for background
-    Vector3d clrBackground = m_ThumbnailIsDrawing
-      ? m_ParentUI->GetAppearanceSettings()->GetUIElement(
-          SNAPAppearanceSettings::ZOOM_THUMBNAIL).NormalColor
-      : Vector3d(1.0);
-
-    // Make sure the correct image is pointed to
-    m_SpeedTexture->SetImage(m_ImageData->GetSpeed()->GetDisplaySlice(m_Id).GetPointer());
-
-    // Paint the grey texture
-    m_SpeedTexture->Draw(clrBackground);
-    }
-  else
-    {
-    GenericSliceWindow::DrawMainTexture();
-    }
-}
-
-void SNAPSliceWindow
-::DrawSegmentationTexture()
-{
-  // First check if we are in overlay drawing mode
-  if(m_GlobalState->GetSpeedViewZero())
-    {
-    // We should have a slice to draw
-    assert(m_ImageData->IsSpeedLoaded() && m_ImageSliceIndex >= 0);
-    
-    // Make sure that the right image is there
-    m_OverlayTexture->SetImage(m_ImageData->GetSpeed()->GetOverlaySlice(m_Id));
-
-    // Paint the grey texture
-    m_OverlayTexture->DrawTransparent(m_GlobalState->GetSegmentationAlpha());
-    }
-
-  // Otherwize draw the snake
-  else if(m_GlobalState->GetSnakeActive())
-    {
-    // We should have a slice to draw
-    assert(m_ImageData->IsSnakeLoaded() && m_ImageSliceIndex >= 0);
-
-    // Make sure that the right image is there
-    m_SnakeTexture->SetImage(m_ImageData->GetSnake()->GetDisplaySlice(m_Id).GetPointer());
-
-    // Paint the grey texture
-    m_SnakeTexture->DrawTransparent(m_GlobalState->GetSegmentationAlpha());
-    }
-
-  // Otherwize use the parent's method
-  else
-    {
-    // Call the parent's method    
-    GenericSliceWindow::DrawSegmentationTexture();
-    }
-}
-
-void SNAPSliceWindow
-::DrawOverlays()
-{
-  // Call the parent's code
-  GenericSliceWindow::DrawOverlays();
-
-  // Draw the bubbles
-  if(!m_ThumbnailIsDrawing)
-    m_BubblesMode->OnDraw();
-}
-
diff --git a/UserInterface/SliceWindow/SNAPSliceWindow.h b/UserInterface/SliceWindow/SNAPSliceWindow.h
deleted file mode 100644
index b5e4c04..0000000
--- a/UserInterface/SliceWindow/SNAPSliceWindow.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SNAPSliceWindow.h,v $
-  Language:  C++
-  Date:      $Date: 2009/08/25 19:46:18 $
-  Version:   $Revision: 1.5 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SNAPSliceWindow_h_
-#define __SNAPSliceWindow_h_
-
-#include "GenericSliceWindow.h"
-
-// Forward references
-class SNAPImageData;
-class BubblesInteractionMode;
- 
-/**
- * \class SNAPSliceWindow
- * \brief The window used to display slices in SnAP part of the application.  
- *
- * SnAP not only has the original greyscale image, but also a floating 
- * point preprocessing image.  The overlays for SnAP include bubble display.
- */
-class SNAPSliceWindow : public GenericSliceWindow
-{
-public:
-
-  SNAPSliceWindow(int id,UserInterfaceBase *parentUI, FLTKCanvas *canvas);
-  ~SNAPSliceWindow();
-
-  /** Overrides the parent's method */
-  void InitializeSlice(GenericImageData *imageData);
-
-protected:
-
-  // The interaction mode for bubble drawing
-  BubblesInteractionMode *m_BubblesMode;
-  
-  // SNAP image data object displayed in this window (overrides parent's 
-  // m_ImageData
-  SNAPImageData *m_ImageData;
-
-  // Preprocessed slice texture object
-  OpenGLSliceTexture *m_SpeedTexture;
-
-  // Segmentation slice texture object
-  OpenGLSliceTexture *m_SnakeTexture;
-
-  // The overlay texture object
-  OpenGLSliceTexture *m_OverlayTexture;
-
-  // Overlay and texture drawing are customized in this class
-  void DrawOverlays();
-  void DrawMainTexture();
-  void DrawSegmentationTexture();  
-};
-
-#endif // SNAP Slice Window
diff --git a/UserInterface/SliceWindow/SliceWindowCoordinator.cxx b/UserInterface/SliceWindow/SliceWindowCoordinator.cxx
deleted file mode 100644
index 41d908b..0000000
--- a/UserInterface/SliceWindow/SliceWindowCoordinator.cxx
+++ /dev/null
@@ -1,239 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SliceWindowCoordinator.cxx,v $
-  Language:  C++
-  Date:      $Date: 2010/10/12 17:57:11 $
-  Version:   $Revision: 1.5 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "SliceWindowCoordinator.h"
-
-#include "GlobalState.h"
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-#include "OpenGLSliceTexture.h"
-#include "UserInterfaceBase.h"
-
-SliceWindowCoordinator
-::SliceWindowCoordinator()
-{
-  m_Window[0] = m_Window[1] = m_Window[2] = NULL;
-  m_Canvas[0] = m_Canvas[1] = m_Canvas[2] = NULL;
-  m_LinkedZoom = false;
-  m_WindowsRegistered = false;
-}
-
-SliceWindowCoordinator
-::~SliceWindowCoordinator()
-{
-}
-
-void
-SliceWindowCoordinator
-::RegisterWindows(GenericSliceWindow *windows[3])
-{
-  for(unsigned int i=0;i<3;i++)
-    {
-    m_Window[i] = windows[i];
-    m_Canvas[i] = m_Window[i]->GetCanvas();
-    m_Window[i]->SetManagedZoom(m_LinkedZoom);
-    }
-  m_WindowsRegistered = true;
-}
-
-void 
-SliceWindowCoordinator
-::SetLinkedZoom(bool flag)
-{
-  m_LinkedZoom = flag;
-
-  if(m_WindowsRegistered)
-    {
-    // Tell the windows whether they are managed or not
-    for(unsigned int i=0;i<3;i++)
-      m_Window[i]->SetManagedZoom(m_LinkedZoom);
-    
-    // Set the common zoom
-    if(m_LinkedZoom)
-      SetCommonZoomToSmallestWindowZoom();
-    }
-}
-
-void
-SliceWindowCoordinator
-::ResetViewToFitInAllWindows()
-{
-  // Only if initialized
-  assert(m_WindowsRegistered);
-  
-  // Set each zoom to optimal value for that window
-  for(unsigned int i=0;i<3;i++)
-    {
-    m_Window[i]->ResetViewToFit();
-    }
-
-  // If linked, zoom back to smallest zoom
-  if(m_LinkedZoom)
-    SetCommonZoomToSmallestWindowZoom();
-}
-
-void 
-SliceWindowCoordinator
-::SetZoomFactorAllWindows(float factor)
-{
-  // First, fit all windows
-  ResetViewToFitInAllWindows();
-
-  // Now scale the zoom in each window
-  for(unsigned int i=0;i<3;i++)
-    {
-    m_Window[i]->SetViewZoom(m_Window[i]->GetViewZoom() * factor);
-    }
-}
-
-void
-SliceWindowCoordinator
-::SetZoomLevelAllWindows(float level)
-{
-  // Now scale the zoom in each window
-  for(unsigned int i=0;i<3;i++)
-    {
-    m_Window[i]->SetViewZoom(level);
-    }
-}
-
-
-
-void
-SliceWindowCoordinator
-::ResetViewToFitInOneWindow(unsigned int window)
-{
-  // Only if initialized
-  assert(m_WindowsRegistered);
-
-  // Reset zoom to fit in the current window
-  m_Window[window]->ResetViewToFit();
-
-  if(m_LinkedZoom)
-    SetZoomLevelAllWindows(m_Window[window]->GetViewZoom());
-}
-
-void
-SliceWindowCoordinator
-::OnZoomUpdateInWindow(unsigned int irisNotUsed(window), float zoom)
-{
-  // Only if initialized
-  assert(m_WindowsRegistered);
-  
-  if(m_LinkedZoom)
-    {
-    for(unsigned int i=0;i<3;i++) 
-      {
-      m_Window[i]->SetViewZoom(zoom);
-      }
-    }
-}
-
-void
-SliceWindowCoordinator
-::OnWindowResize()
-{
-  if(m_LinkedZoom)
-    SetCommonZoomToSmallestWindowZoom();
-}
-
-void
-SliceWindowCoordinator
-::SetCommonZoomToSmallestWindowZoom()
-{
-  // Compute the minimum zoom
-  float minZoom = m_Window[0]->GetViewZoom();
-  for(unsigned int i=1;i<3;i++)
-    {
-    if(minZoom > m_Window[i]->GetViewZoom())
-      minZoom = m_Window[i]->GetViewZoom();
-    }
-
-  // Assign the minimum zoom
-  for(unsigned int j=0;j<3;j++)
-    {
-    m_Window[j]->SetViewZoom(minZoom);
-    }
-}
-
-
-float
-SliceWindowCoordinator
-::GetCommonZoomLevel()
-{
-  assert(m_LinkedZoom && m_WindowsRegistered);
-  return m_Window[0]->GetViewZoom();
-}
-
-float
-SliceWindowCoordinator
-::GetCommonOptimalFitZoomLevel()
-{
-  assert(m_LinkedZoom && m_WindowsRegistered);
-  return m_Window[0]->GetOptimalZoom();
-}
-
-float
-SliceWindowCoordinator
-::ClampZoom(unsigned int window,float zoom)
-{
-  assert(m_WindowsRegistered);
-
-  float maxZoom = 0.0f;
-  float minZoom = 0.0f;
-
-  for(unsigned int i=0;i<3;i++)
-    {
-    if(m_LinkedZoom || window == i)
-      {
-      // Maximum zoom is constrained by the requirement that at least four
-      // pixels are visible in at least one dimensions
-      float zMax1 = 0.25 * m_Canvas[i]->w() / m_Window[i]->GetSliceSpacing()[0];
-      float zMax2 = 0.25 * m_Canvas[i]->h() / m_Window[i]->GetSliceSpacing()[1];
-      float zMax = zMax1 > zMax2 ? zMax1 : zMax2;
-      maxZoom = (maxZoom == 0.0f || maxZoom < zMax) ? zMax : maxZoom;
-
-      // Minimum zoom is just 0.25 of the optimal zoom
-      float zMin = 0.25 * m_Window[i]->GetOptimalZoom();
-      minZoom = (minZoom == 0.0f || minZoom > zMin) ? zMin : minZoom;
-      }
-    }
-
-  // Apply the clamp
-  if(zoom < minZoom)
-    return minZoom;
-  if(zoom > maxZoom)
-    return maxZoom;
-  return zoom;
-}
diff --git a/UserInterface/SliceWindow/SliceWindowCoordinator.h b/UserInterface/SliceWindow/SliceWindowCoordinator.h
deleted file mode 100644
index adb8415..0000000
--- a/UserInterface/SliceWindow/SliceWindowCoordinator.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: SliceWindowCoordinator.h,v $
-  Language:  C++
-  Date:      $Date: 2009/05/04 20:15:57 $
-  Version:   $Revision: 1.5 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __SliceWindowCoordinator_h_
-#define __SliceWindowCoordinator_h_
-
-#include "GenericSliceWindow.h"
-
-/**
- * \class SliceWindowCoordinator
- * \brief Coordinates the zoom (and perhaps other) aspects of behavior between
- * three orthogonal slice windows.
- *
- * Helps manage linked zoom (the concept that 1 mm in image space is always the
- * same number of pixels in each slice view).
- */
-class SliceWindowCoordinator 
-{
-public:
-
-  /** Constructor */
-  SliceWindowCoordinator();
-
-  /** Virtual destructor */
-  virtual ~SliceWindowCoordinator();
-
-  /** Assigns three windows for the coordinator to manage */
-  void RegisterWindows(GenericSliceWindow *windows[3]);
-
-  /** Specify whether the coordinator should maintain linked zoom
-   * in the three slice windows */
-  void SetLinkedZoom(bool flag);
-
-  /** Specify whether the coordinator should maintain linked zoom
-   * in the three slice windows */
-  irisGetMacro(LinkedZoom,bool);  
-  
-  /** Set the zoom to a fraction of the optimal zoom.  This makes 
-   * the most sense when the zoom level is linked, but can be performed 
-   * regardless */
-  void SetZoomFactorAllWindows(float factor);
-
-  /** Set the zoom to an absolute value in all windows */
-  void SetZoomLevelAllWindows(float level);
-
-  /** Reset the zoom in all windows to an optimal value, ie, such a zoom
-   * that the image fits into each of the windows.  Depending on whether 
-   * the zoom is linked or not, this will either zoom each slice as much
-   * as possible, or zoom the largest of the 3 slices as much as possible */
-  void ResetViewToFitInAllWindows();
-
-  /** Reset the zoom in one window to optimal value.  When linked zoom is
-   * maintained, this has the same effect as ResetViewToFitInAllWindows, 
-   * and if not, it only affects the given window */
-  void ResetViewToFitInOneWindow(unsigned int window);
-
-  /** When one of the windows wants to change the zoom w.r.t. a user
-   * action, this class will adjust, if necessary, the zoom in the other
-   * windows */
-  void OnZoomUpdateInWindow(unsigned int window, float zoom);
-
-  /** React to a resizing of the windows.  This will try to maintain the current view
-   * depending on the state.  If the zooms are in 'reset' state, this will keep
-   * them in the reset state, and otherwise, it will maintain the zoom levels */
-  void OnWindowResize();
-
-  /** Get the common zoom factor */
-  float GetCommonZoomLevel();
-
-  /** Get the zoom factor that will fit all three slices optimally */
-  float GetCommonOptimalFitZoomLevel();
-
-  /** Constrain a zoom factor to reasonable limits */
-  float ClampZoom(unsigned int window,float zoom);
-
-  /** Get the window number n */
-  GenericSliceWindow *GetWindow(unsigned int window)
-    { return m_Window[window]; }
-
-protected:
-
-  /** Pointer to the application driver for this UI object */
-  //IRISApplication *m_Driver;
-
-  /** Pointer to the global state object (shorthand) */
-  //GlobalState *m_GlobalState;
-
-  /** Pointer to GUI that contains this Window3D object */
-  //UserInterfaceBase *m_ParentUI;   
-
-  /** The image data object that is displayed in this window */
-  //GenericImageData *m_ImageData;
-
-  /** The pointers to three window interactors managed by this class */
-  GenericSliceWindow *m_Window[3];
-
-  /** The pointers to the windows managed by the interactors */
-  FLTKCanvas *m_Canvas[3];
-
-  /** Whether or not linked zoom is maintained */
-  bool m_LinkedZoom;
-
-  /** Whether the windows have been registered */
-  bool m_WindowsRegistered;
-
-  /** Method that sets all the zooms to a common value */
-  void SetCommonZoomToSmallestWindowZoom();
-};
-
-#endif // __SliceWindowCoordinator_h_
diff --git a/UserInterface/SliceWindow/ThumbnailInteractionMode.cxx b/UserInterface/SliceWindow/ThumbnailInteractionMode.cxx
deleted file mode 100644
index bb0eb3d..0000000
--- a/UserInterface/SliceWindow/ThumbnailInteractionMode.cxx
+++ /dev/null
@@ -1,124 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ThumbnailInteractionMode.cxx,v $
-  Language:  C++
-  Date:      $Date: 2009/06/16 19:05:37 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "ThumbnailInteractionMode.h"
-#include "IRISApplication.h"
-#include "IRISImageData.h"
-#include "UserInterfaceBase.h"
-
-ThumbnailInteractionMode
-::ThumbnailInteractionMode(GenericSliceWindow *parent) 
-: GenericSliceWindow::EventHandler(parent)
-{
-  m_PanFlag = false;  
-}
-
-int
-ThumbnailInteractionMode
-::OnMousePress(const FLTKEvent &event)
-{
-  // Clear the pan flag
-  m_PanFlag = false;
-
-  // Only react to left mouse button presses
-  if(event.SoftButton == FL_LEFT_MOUSE)
-    {
-    // Check if the event is inside of the thumbnail boundaries
-    Vector2i xThumb = m_Parent->m_ThumbnailPosition;
-    Vector2i sThumb = m_Parent->m_ThumbnailSize;
-    if(m_Parent->IsThumbnailOn() &&
-      event.XCanvas[0] > xThumb[0] && 
-      event.XCanvas[0] < xThumb[0] + sThumb[0] &&
-      event.XCanvas[1] > xThumb[1] && 
-      event.XCanvas[1] < xThumb[1] + sThumb[1])
-      {
-      // Set the panning flag
-      m_PanFlag = true;
-
-      // Store the starting view position
-      m_StartViewPosition = m_Parent->m_ViewPosition;
-
-      // Return success
-      return 1;
-      }
-    }
-
-  // Pass the event on
-  return 0;
-}
-
-int
-ThumbnailInteractionMode
-::OnMouseRelease(const FLTKEvent &event, 
-                 const FLTKEvent &pressEvent)
-{
-  // Call the drag code
-  return OnMouseDrag(event, pressEvent);
-}
-
-int
-ThumbnailInteractionMode
-::OnMouseDrag(const FLTKEvent &event, 
-              const FLTKEvent &pressEvent)
-{
-  // Must be in pan mode
-  if(m_PanFlag && event.SoftButton == FL_LEFT_MOUSE)
-    {
-    // Get the number of pixels that the thumbnail was moved by
-    Vector2i xMoved = pressEvent.XCanvas - event.XCanvas;
-
-    // Figure out how this movement translates to space units
-    Vector2f xOffset(
-      xMoved[0] / m_Parent->m_ThumbnailZoom,
-      xMoved[1] / m_Parent->m_ThumbnailZoom);
-
-    // Add to the position
-    m_Parent->m_ViewPosition = m_StartViewPosition - xOffset;
-    m_Parent->m_ParentUI->OnViewPositionsUpdate();
-
-    // Tell parent to repaint
-    m_Parent->GetCanvas()->redraw();
-
-    // The event's been handled
-    return 1;
-    }
-  else return 0;
-}
-
-void 
-ThumbnailInteractionMode::
-OnDraw()
-{
-}
-
diff --git a/UserInterface/SliceWindow/ThumbnailInteractionMode.h b/UserInterface/SliceWindow/ThumbnailInteractionMode.h
deleted file mode 100644
index 016f9ce..0000000
--- a/UserInterface/SliceWindow/ThumbnailInteractionMode.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ThumbnailInteractionMode.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:29 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __ThumbnailInteractionMode_h_
-#define __ThumbnailInteractionMode_h_
-
-#include "GenericSliceWindow.h"
-#include "GlobalState.h"
-
-/**
- * \class ThumbnailInteractionMode
- * \brief UI interaction mode that takes care of the zoom thumbnail shown in the
- * bottom left corner of the window
- *
- * \see GenericSliceWindow
- */
-class ThumbnailInteractionMode : public GenericSliceWindow::EventHandler {
-public:
-  ThumbnailInteractionMode(GenericSliceWindow *parent);
-
-  void OnDraw(); 
-  int OnMousePress(const FLTKEvent &event);
-  int OnMouseRelease(const FLTKEvent &event, 
-                     const FLTKEvent &irisNotUsed(pressEvent));
-  int OnMouseDrag(const FLTKEvent &event, 
-                  const FLTKEvent &irisNotUsed(pressEvent));
-
-private:
-  bool m_PanFlag;
-  Vector2f m_StartViewPosition;
-};
-
-#endif // __ThumbnailInteractionMode_h_
diff --git a/UserInterface/SliceWindow/ZoomPanInteractionMode.cxx b/UserInterface/SliceWindow/ZoomPanInteractionMode.cxx
deleted file mode 100644
index d4c24d5..0000000
--- a/UserInterface/SliceWindow/ZoomPanInteractionMode.cxx
+++ /dev/null
@@ -1,137 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ZoomPanInteractionMode.cxx,v $
-  Language:  C++
-  Date:      $Date: 2009/05/04 20:15:57 $
-  Version:   $Revision: 1.3 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "ZoomPanInteractionMode.h"
-#include "UserInterfaceBase.h"
-#include "SliceWindowCoordinator.h"
-
-#include <cmath>
-#include <iostream>
-
-ZoomPanInteractionMode
-::ZoomPanInteractionMode(GenericSliceWindow *parent)
-: GenericSliceWindow::EventHandler(parent)
-{
-  m_NeedUIUpdateOnRepaint = false;
-}
-
-int
-ZoomPanInteractionMode
-::OnMousePress(const FLTKEvent &event)
-{
-  if(event.SoftButton == FL_LEFT_MOUSE || event.SoftButton == FL_RIGHT_MOUSE)
-    {
-    // Record the current zoom and view position
-    m_StartViewZoom = m_Parent->GetViewZoom();
-    m_StartViewPosition = m_Parent->m_ViewPosition;
-
-    // Done
-    return 1;
-    }
-  else return 0;
-}
-
-int 
-ZoomPanInteractionMode
-::OnMouseDrag(const FLTKEvent &event,const FLTKEvent &dragEvent)
-{
-  if (dragEvent.SoftButton == FL_LEFT_MOUSE)
-    {
-    // Compute the start and end point in slice coordinates
-    Vector3f xStart = m_Parent->MapWindowToSlice(dragEvent.XSpace.extract(2));
-    Vector3f xEnd = m_Parent->MapWindowToSlice(event.XSpace.extract(2));
-    Vector2f xOffset(xEnd[0] - xStart[0],xEnd[1] - xStart[1]);
-
-    // Remove the scaling by spacing
-    xOffset(0) *= m_Parent->m_SliceSpacing(0);
-    xOffset(1) *= m_Parent->m_SliceSpacing(1);
-
-    // Under the left button, the tool changes the view_pos by the
-    // distance traversed
-    m_Parent->SetViewPosition(m_StartViewPosition - xOffset);
-    m_ParentUI->OnViewPositionsUpdate();
-    } 
-  else if (dragEvent.SoftButton == FL_RIGHT_MOUSE)
-    {
-    // Under the right button, the tool causes us to zoom based on the vertical
-    // motion
-    float zoom = 
-    m_StartViewZoom * 
-    pow(1.02f,(float)(event.XSpace(1) - dragEvent.XSpace(1)));
-
-    // Clamp the zoom factor to reasonable limits
-    zoom = m_ParentUI->GetSliceCoordinator()->ClampZoom(m_Parent->m_Id,zoom);
-
-    // Make sure the zoom factor is an integer fraction
-    zoom = m_Parent->GetOptimalZoom() * 
-           ((int)(zoom / m_Parent->GetOptimalZoom() * 100)) / 100.0f;
-
-    // Set the zoom factor using the window coordinator
-    m_Parent->SetViewZoom(zoom);
-    m_ParentUI->GetSliceCoordinator()->OnZoomUpdateInWindow(m_Parent->m_Id,zoom);
-
-    // Schedule an update of the zoom percentage display in the parent
-    m_NeedUIUpdateOnRepaint = true;
-    } 
-  else return 0;
-
-  // Redraw the screen
-  m_Parent->GetCanvas()->redraw();
-
-  // Nothing to do here.
-  return 1;
-}
-
-int 
-ZoomPanInteractionMode
-::OnMouseRelease(const FLTKEvent &event,
-                 const FLTKEvent &irisNotUsed(dragEvent))
-{
-  // Eat the left and right buttons
-  if(event.SoftButton == FL_LEFT_MOUSE || event.SoftButton == FL_RIGHT_MOUSE)
-    return 1;
-  else return 0;
-}
-
-void
-ZoomPanInteractionMode
-::OnDraw()
-{
-  if(m_NeedUIUpdateOnRepaint)
-    {
-    m_ParentUI->OnZoomUpdate();
-    m_NeedUIUpdateOnRepaint = false;
-    }   
-}
-
diff --git a/UserInterface/SliceWindow/ZoomPanInteractionMode.h b/UserInterface/SliceWindow/ZoomPanInteractionMode.h
deleted file mode 100644
index c897b85..0000000
--- a/UserInterface/SliceWindow/ZoomPanInteractionMode.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: ZoomPanInteractionMode.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:29 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __ZoomPanInteractionMode_h_
-#define __ZoomPanInteractionMode_h_
-
-#include "GenericSliceWindow.h"
-
-/**
- * \class ZoomPanInteractionMode
- * \brief UI interaction mode that takes care of zooming and panning.
- *
- * \see GenericSliceWindow
- */
-class ZoomPanInteractionMode : public GenericSliceWindow::EventHandler {
-public:
-  ZoomPanInteractionMode(GenericSliceWindow *parent);
-
-  int OnMousePress(const FLTKEvent &event);
-  int OnMouseRelease(const FLTKEvent &event, const FLTKEvent &pressEvent);    
-  int OnMouseDrag(const FLTKEvent &event, const FLTKEvent &pressEvent);
-  void OnDraw();
-  
-  // void OnDraw();
-protected:
-  /** The starting point for panning */
-  Vector2f m_StartViewPosition;
-
-  /** The starting zoom level */
-  float m_StartViewZoom;
-
-  /** Used to schedule UI repaint updates */
-  bool m_NeedUIUpdateOnRepaint;
-};
-
-#endif // __ZoomPanInteractionMode_h_
diff --git a/UserInterface/Window3D/Trackball.h b/UserInterface/Window3D/Trackball.h
deleted file mode 100644
index 8fca898..0000000
--- a/UserInterface/Window3D/Trackball.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: Trackball.h,v $
-  Language:  C++
-  Date:      $Date: 2007/12/30 04:05:29 $
-  Version:   $Revision: 1.2 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __Trackball_h_
-#define __Trackball_h_
-
-#include <FL/gl.h>
-
-/**
- * \class Trackball
- * \brief Virtual trackball for the 3D window
- *
- * \sa Window3D
- */
-class Trackball  
-{
-private:
-  GLboolean m_TrackingMotion;
-  float m_Angle;
-  float m_Axis[3];
-  float m_LastPosition[3];
-  GLfloat m_RotationMatrix[4][4];
-  GLfloat m_Zoom, m_OldZoom;
-  GLfloat m_PanX, m_PanY;
-  GLfloat m_OldPanX, m_OldPanY;
-  
-  void PToV( int x, int y, int width, int height, float v[3] );
-
-public:
-  Trackball();
-  Trackball( const Trackball& T );
-  ~Trackball();
-
-  void Reset();
-  void StartPan( int x, int y );
-  void StopPan();
-  void TrackPan( int x, int y, int w, int h, float ratew, float rateh );
-  void StartZoom( int y );
-  void StopZoom();
-  void TrackZoom( int y );
-  void StartRot( int x, int y, int w, int h );
-  void StopRot();
-  void TrackRot( int x, int y, int w, int h );
-  inline GLfloat *GetRot() { return( (GLfloat*) m_RotationMatrix ); };
-  inline GLfloat GetZoom() { return( m_Zoom ); };
-  inline GLfloat GetPanX() { return( m_PanX ); };
-  inline GLfloat GetPanY() { return( m_PanY ); };
-};
-
-#endif // __Trackball_h_
-
-/*
- *$Log: Trackball.h,v $
- *Revision 1.2  2007/12/30 04:05:29  pyushkevich
- *GPL License
- *
- *Revision 1.1  2006/12/02 04:22:27  pyushkevich
- *Initial sf checkin
- *
- *Revision 1.1.1.1  2006/09/26 23:56:17  pauly2
- *Import
- *
- *Revision 1.5  2004/08/26 18:29:20  pauly
- *ENH: New user interface for configuring the UI options
- *
- *Revision 1.4  2003/10/02 14:55:53  pauly
- *ENH: Development during the September code freeze
- *
- *Revision 1.1  2003/09/11 13:51:15  pauly
- *FIX: Enabled loading of images with different orientations
- *ENH: Implemented image save and load operations
- *
- *Revision 1.3  2003/08/27 14:03:24  pauly
- *FIX: Made sure that -Wall option in gcc generates 0 warnings.
- *FIX: Removed 'comment within comment' problem in the cvs log.
- *
- *Revision 1.2  2003/08/27 04:57:47  pauly
- *FIX: A large number of bugs has been fixed for 1.4 release
- *
- *Revision 1.1  2003/07/12 04:46:51  pauly
- *Initial checkin of the SNAP application into the InsightApplications tree.
- *
- *Revision 1.3  2003/07/12 01:34:18  pauly
- *More final changes before ITK checkin
- *
- *Revision 1.2  2003/07/11 23:25:33  pauly
- **** empty log message ***
- *
- *Revision 1.1  2003/03/07 19:29:48  pauly
- *Initial checkin
- *
- *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
- *Started the project repository
- *
- *
- *Revision 1.2  2002/03/08 14:06:32  moon
- *Added Header and Log tags to all files
- **/
diff --git a/UserInterface/Window3D/Window3D.cxx b/UserInterface/Window3D/Window3D.cxx
deleted file mode 100644
index ed88ebc..0000000
--- a/UserInterface/Window3D/Window3D.cxx
+++ /dev/null
@@ -1,1551 +0,0 @@
-/*=========================================================================
-
-  Program:   Insight Segmentation & Registration Toolkit
-  Module:    $RCSfile: Window3D.cxx,v $
-  Language:  C++
-  Date:      $Date: 2009/10/26 16:40:19 $
-  Version:   $Revision: 1.13 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#include "Window3D.h"
-#include "IRISImageData.h"
-#include "SNAPImageData.h"
-#include "UserInterfaceBase.h"
-#include "GlobalState.h"
-#include <iostream>
-#include "IRISApplication.h"
-#include "ImageRayIntersectionFinder.h"
-#include "SNAPAppearanceSettings.h"
-#include "FLTKCanvas.h"
-#include "GenericSliceWindow.h"
-
-#include <FL/glut.H>
-#include <FL/fl_ask.H>
-
-#include <vxl_version.h>
-#if VXL_VERSION_DATE_FULL > 20040406
-# include <vnl/vnl_cross.h>
-# define itk_cross_3d vnl_cross_3d
-#else
-# define itk_cross_3d cross_3d
-#endif
-
-#include <vnl/vnl_det.h>
-
-/** These classes are used internally for m_Ray intersection testing */
-class LabelImageHitTester 
-{
-public:
-  LabelImageHitTester(const ColorLabelTable *table = NULL)
-  {
-    m_LabelTable = table;
-  }
-
-  int operator()(LabelType label) const
-  {
-    assert(m_LabelTable);
-    const ColorLabel &cl = m_LabelTable->GetColorLabel(label);
-    return (cl.IsValid() && cl.IsVisible() && cl.IsVisibleIn3D()) ? 1 : 0;
-  }
-
-private:
-  const ColorLabelTable *m_LabelTable;
-};
-
-class SnakeImageHitTester 
-{
-public:
-  int operator()(float levelSetValue) const
-  {
-    return levelSetValue <= 0 ? 1 : 0;
-  }
-};
-
-/**
- * \class Trackball3DInteractionMode
- * \brief 3D interaction mode that takes care of 3D rotation and zoom
- *
- * \see Window3D
- */
-class Trackball3DInteractionMode : public Window3D::EventHandler {
-public:
-  Trackball3DInteractionMode(Window3D *parent) : 
-    Window3D::EventHandler(parent) {}
-
-  int OnMousePress(const FLTKEvent &event);
-  int OnMouseRelease(const FLTKEvent &event, const FLTKEvent &pressEvent);    
-  int OnMouseDrag(const FLTKEvent &event, const FLTKEvent &pressEvent);
-};
-
-int 
-Trackball3DInteractionMode
-::OnMousePress(const FLTKEvent &event)
-{
-  int x = event.XCanvas[0];
-  int y = event.XCanvas[1];
-
-  switch (event.SoftButton)
-    {
-    case FL_LEFT_MOUSE:   m_Parent->OnRotateStartAction(x,y);break;
-    case FL_MIDDLE_MOUSE: m_Parent->OnPanStartAction(x,y);break;
-    case FL_RIGHT_MOUSE:  m_Parent->OnZoomStartAction(x,y);break;
-    default: return 0;
-    }
-
-  return 1;
-}
-
-int 
-Trackball3DInteractionMode
-::OnMouseRelease(const FLTKEvent &irisNotUsed(event),
-                 const FLTKEvent &irisNotUsed(startEvent))
-{
-  m_Parent->OnTrackballStopAction();
-  return 1;
-}
-
-int 
-Trackball3DInteractionMode
-::OnMouseDrag(const FLTKEvent &event,
-              const FLTKEvent &irisNotUsed(startEvent))
-{
-  m_Parent->OnTrackballDragAction(event.XCanvas[0],event.XCanvas[1]);
-  return 1;
-}
-
-/**
- * \class Crosshair3DInteractionMode
- * \brief 3D interaction mode that takes care of 3D crosshair interaction
- *
- * \see Window3D
- */
-class Crosshairs3DInteractionMode : public Window3D::EventHandler {
-public:
-  Crosshairs3DInteractionMode(Window3D *parent) : 
-    Window3D::EventHandler(parent) {}
-
-  int OnMousePress(const FLTKEvent &event);
-};
-
-int 
-Crosshairs3DInteractionMode
-::OnMousePress(const FLTKEvent &event)
-{
-  if(event.SoftButton == FL_LEFT_MOUSE)
-    {
-    m_Parent->OnCrosshairClickAction(event.XCanvas[0],event.XCanvas[1]);
-    return 1;
-    }
-  else return 0;
-}
-
-/**
- * \class Scalpel3DInteractionMode
- * \brief 3D interaction mode that takes care of cutting 3D view in two
- *
- * \see Window3D
- */
-class Scalpel3DInteractionMode : public Window3D::EventHandler {
-public:
-  Scalpel3DInteractionMode(Window3D *parent) : 
-    Window3D::EventHandler(parent) 
-  { 
-    m_Started = false;
-    m_Inside = false;
-  }
-
-  int OnMousePress(const FLTKEvent &event);
-  int OnMouseMotion(const FLTKEvent &event);    
-  int OnMouseEnter(const FLTKEvent &event);
-  int OnMouseExit(const FLTKEvent &event);
-
-  irisGetMacro(Started,bool);
-  irisGetMacro(Inside,bool);
-  irisGetMacro(StartPoint,Vector2i);
-  irisGetMacro(EndPoint,Vector2i);
-
-protected:
-  bool m_Inside;
-  bool m_Started;
-  Vector2i m_StartPoint;
-  Vector2i m_EndPoint;
-};
-
-int 
-Scalpel3DInteractionMode
-::OnMousePress(const FLTKEvent &event)
-{
-  if(!m_Started)
-    {
-    // Only for left button
-    if(event.SoftButton != FL_LEFT_MOUSE) return 0;
-
-    // Record the starting and ending points
-    m_StartPoint = event.XCanvas;
-    m_EndPoint = event.XCanvas;
-    m_Started = true;
-    m_Inside = true;
-    }
-  else
-    {
-    // This is the second click, after the user finished dragging
-    m_EndPoint = event.XCanvas;
-    m_Started = false;
-
-    // If the user clicks another button, disengage, otherwise
-    // draw the plane in the parent
-    if(event.SoftButton == FL_LEFT_MOUSE)
-      m_Parent->OnScalpelPointPairAction(
-        m_StartPoint[0],m_StartPoint[1],m_EndPoint[0],m_EndPoint[1]);    
-    }
-
-  // Redraw the parent
-  m_Canvas->redraw();
-
-  // Eat the event
-  return 1;
-}
-
-int 
-Scalpel3DInteractionMode::
-OnMouseMotion(const FLTKEvent &event)
-{
-  // Only valid if drawing has started
-  if(!m_Started) return 0;
-  
-  // Record the end point
-  m_EndPoint = event.XCanvas;
-
-  // Redraw the parent
-  m_Canvas->redraw();
-
-  // Eat the event
-  return 1;
-}
-
-int 
-Scalpel3DInteractionMode
-::OnMouseEnter(const FLTKEvent &event)
-{
-  // Only valid if drawing has started
-  if(!m_Started) return 0;
-  
-  // Record that we're inside
-  m_Inside = true;
-  
-  // Record the end point
-  m_EndPoint = event.XCanvas;
-
-  // Redraw the parent
-  m_Canvas->redraw();
-
-  // Eat the event
-  return 1;
-}
-
-int 
-Scalpel3DInteractionMode
-::OnMouseExit(const FLTKEvent &irisNotUsed(event))
-{
-  // Only valid if drawing has started
-  if(!m_Started) return 0;
-  
-  // Record that we're inside
-  m_Inside = false;
-  
-  // Redraw the parent
-  m_Canvas->redraw();
-
-  // Eat the event
-  return 1;
-}
-
-
-/**
- * \class Spraypaint3DInteractionMode
- * \brief 3D interaction mode that takes care of spraying on top of the 3D view
- *
- * \see Window3D
- */
-class Spraypaint3DInteractionMode : public Window3D::EventHandler {
-public:
-  Spraypaint3DInteractionMode(Window3D *parent) : 
-    Window3D::EventHandler(parent) {}
-
-  int OnMousePress(const FLTKEvent &event);
-  int OnMouseDrag(const FLTKEvent &event, const FLTKEvent &pressEvent);
-};
-
-
-int 
-Spraypaint3DInteractionMode
-::OnMousePress(const FLTKEvent &event)
-{
-  if(event.SoftButton == FL_LEFT_MOUSE)
-    {
-    m_Parent->OnSpraypaintClickAction(event.XCanvas[0],event.XCanvas[1]);
-    return 1;
-    }
-  else return 0;
-}
-
-int 
-Spraypaint3DInteractionMode
-::OnMouseDrag(const FLTKEvent &event,
-              const FLTKEvent &irisNotUsed(startEvent))
-{
-  if(event.SoftButton == FL_LEFT_MOUSE)
-    {
-    m_Parent->OnSpraypaintClickAction(event.XCanvas[0],event.XCanvas[1]);
-    return 1;
-    }
-  else return 0;
-}
-
-
-Window3D
-::Window3D(UserInterfaceBase *parentUI, FLTKCanvas *canvas)
-: RecursiveInteractionMode(canvas)
-{
-  // Copy parent pointers
-  m_ParentUI = parentUI;
-  m_Driver = m_ParentUI->GetDriver();
-  m_GlobalState = m_Driver->GetGlobalState();    
-
-  // Pass parent pointer to the mesh object
-  this->m_Mesh.Initialize(m_Driver);
-
-  // Make sure FLTK canvas does not flip the Y coordinate
-  m_Canvas->SetFlipYCoordinate(false);
-  m_Canvas->SetGrabFocusOnEntry(true);
-  
-  // Clear the flags
-  m_NeedsInitialization = 1;
-  m_CursorVisible = 0;
-  m_Mode = WIN3D_NONE;
-  m_Plane.valid = -1;
-
-  // Reset the vectors to zero
-  m_WorldMatrix.set_identity();
-  m_ImageSize.fill(0);
-  m_Center.fill(0);
-  m_DefaultHalf.fill(0);
-  m_ViewHalf.fill(0);
-
-  // Initialize the interaction modes
-  m_CrosshairsMode = new Crosshairs3DInteractionMode(this); 
-  m_TrackballMode = new Trackball3DInteractionMode(this);
-  m_SpraypaintMode = new Spraypaint3DInteractionMode(this);
-  m_ScalpelMode = new Scalpel3DInteractionMode(this);
-  
-  // Start with the trackball mode, which is prevailing
-  PushInteractionMode(m_TrackballMode);
-}
-
-
-/** Enter the cross-hairs mode of operation */
-void 
-Window3D
-::EnterCrosshairsMode()
-{
-  PopInteractionMode();
-  PushInteractionMode(m_CrosshairsMode);
-}
-
-/** Enter the trackball mode of operation */
-void 
-Window3D
-::EnterTrackballMode()
-{
-  PopInteractionMode();
-  PushInteractionMode(m_TrackballMode);
-}
-
-/** Enter the scalpel mode of operation */
-void 
-Window3D
-::EnterScalpelMode()
-{
-  PopInteractionMode();
-  PushInteractionMode(m_ScalpelMode);
-}
-
-/** Enter the spraypaint mode of operation */
-void 
-Window3D
-::EnterSpraypaintMode()
-{
-  PopInteractionMode();
-  PushInteractionMode(m_SpraypaintMode);
-}
-
-Window3D
-::~Window3D()
-{
-  delete m_CrosshairsMode;
-  delete m_TrackballMode;
-  delete m_SpraypaintMode;
-  delete m_ScalpelMode;
-}
-
-
-/* Initializes lightning and other basic GL-state for the window */
-void 
-Window3D
-::Initialize()
-{
-  glClearColor(0.0, 0.0, 0.0, 0.0);
-  glEnable( GL_DEPTH_TEST );
-
-  // Set up the materials
-  GLfloat light0Pos[4] = { 0.0, 0.0, 1.0, 0.0};
-  GLfloat matAmb[4] = { 0.01, 0.01, 0.01, 1.00};
-  GLfloat matDiff[4] = { 0.65, 0.65, 0.65, 1.00};
-  GLfloat matSpec[4] = { 0.30, 0.30, 0.30, 1.00};
-  GLfloat matShine = 10.0;
-  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmb);
-  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiff);
-  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpec);
-  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, matShine);
-  glEnable(GL_COLOR_MATERIAL);
-
-  // Setup Lighting
-  glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
-  glEnable(GL_LIGHT0);
-  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
-  glEnable(GL_LIGHTING);
-}
-
-void 
-Window3D
-::ClearScreen()
-{
-  // Hide the crosshairs.
-  m_CursorVisible = 0;  
-
-  // Hide the mesh.
-  m_Mesh.Reset(); 
-}
-
-void 
-Window3D
-::ResetView()
-{
-  // Reset the trackball
-  m_Trackball.Reset();
-
-  // Rotate a little bit, so we see the three axes
-  m_Trackball.StartRot(12,10,20,20);
-  m_Trackball.TrackRot(10,8,20,20);
-  m_Trackball.StopRot();
-
-  if (m_Driver->GetCurrentImageData()->IsMainLoaded())
-    {
-    // data dimensions
-    m_ImageSize = m_Driver->GetCurrentImageData()->GetVolumeExtents();  
-
-    // world transform
-    m_WorldMatrix = m_Driver->GetCurrentImageData()->GetMain()->GetNiftiSform();
-
-    // Volume size
-    m_VolumeSize = vector_multiply_mixed<double,unsigned int,3>(
-      m_Driver->GetCurrentImageData()->GetImageSpacing(),
-      m_ImageSize);
-    } 
-  else
-    {
-    m_ImageSize.fill(0);
-    m_WorldMatrix.set_identity();
-    m_VolumeSize.fill(0.0);
-    }
-
-  // Compute the maximum extent of the image cube
-  float xMaxDim = m_VolumeSize.max_value();
-  
-  m_DefaultHalf[X] = m_DefaultHalf[Y] = m_DefaultHalf[Z] = xMaxDim * 0.7 + 1.0;
-  m_DefaultHalf[Z] *= 4.0;
-
-  m_CursorVisible = 1;  // Show the crosshairs.
-  m_Plane.valid = -1; // Resets the Cut m_Plane
-  
-  m_Samples.clear();
-
-  // Fire 3D view update event
-  m_ParentUI->OnTrackballUpdate();
-}
-
-void 
-Window3D
-::UpdateMesh(itk::Command *command)
-{
-  // make_current();
-  try 
-    {
-    m_Mesh.GenerateMesh(command);
-    }
-  catch(vtkstd::bad_alloc &)
-    {
-    fl_alert("Out of memory error when generating 3D mesh.");
-    }
-  m_Canvas->redraw();
-}
-
-void 
-Window3D
-::Accept()
-{
-  // Get the current drawing color
-  unsigned char colorid = m_GlobalState->GetDrawingColorLabel();  
-
-  // Apply the spraypaint samples to the image
-  for(SampleListIterator it=m_Samples.begin();it!=m_Samples.end();++it)
-    {
-    m_Driver->GetCurrentImageData()->SetSegmentationVoxel(
-      to_unsigned_int(*it), colorid );
-    }
-  
-  // Clear the list of samples
-  m_Samples.clear();
-  
-  // If the plane is valid, apply it for relabeling
-  if (1 == m_Plane.valid )
-    {   
-    m_Driver->RelabelSegmentationWithCutPlane(m_Plane.vNormal, m_Plane.dIntercept);
-    m_Plane.valid = -1;
-    }
-}
-
-void
-Window3D
-::CheckErrors()
-{
-  GLenum error;
-  while ((error = glGetError()) != GL_NO_ERROR)
-    {
-    std::cerr << "GL-Error: " << (char *) gluErrorString(error) << std::endl;
-    }
-}
-
-void 
-Window3D
-::OnDraw()
-{
-  // Respond to a resize if necessary
-  if (!m_Canvas->valid())
-    {
-    Initialize();
-    glViewport(0,0,m_Canvas->w(),m_Canvas->h());
-    }
-  
-  // Initialize GL if necessary
-  if(m_NeedsInitialization)
-    {
-    ResetView();
-    Initialize();
-    m_NeedsInitialization = false;
-    }      
-
-  // Get the properties for the background color
-  Vector3d clrBack = 
-    m_ParentUI->GetAppearanceSettings()->GetUIElement(
-    SNAPAppearanceSettings::BACKGROUND_3D).NormalColor;
-
-  glClearColor(clrBack[0],clrBack[1],clrBack[2],1);
-  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
-
-  // Compute the center of rotation
-  m_CenterOfRotation = 
-    affine_transform_point(m_WorldMatrix, m_Driver->GetCursorPosition());
-
-  // Set up the projection matrix
-  SetupProjection();
-
-  // Set up the model view matrix
-  glMatrixMode(GL_MODELVIEW);
-  glPushMatrix();  
-  glLoadIdentity();
-
-  // Update the screen geometry
-  glTranslatef( m_Trackball.GetPanX(), m_Trackball.GetPanY(), 0.0 );
-  glMultMatrixf( m_Trackball.GetRot() );
-  glTranslate( - m_CenterOfRotation );
-
-  // Apply the world matrix - all subsequent ops are in voxel space
-  glPushMatrix();
-  glMultMatrixd(m_WorldMatrix.transpose().data_block());
-  // glTranslate(m_Origin);
-  // glScale(m_Spacing);
-
-  // Draw things in pixel coords
-  DrawCrosshairs();
-  DrawSamples();
-  
-  // Undo world matrix - back to drawing in native space
-  glPopMatrix();
-
-  // Draw the cut plane
-  DrawCutPlane();
-
-  // The mesh is already in isotropic coords (needed for marching cubes)
-  m_Mesh.Display();
-
-  // Restore the matrix state
-  glPopMatrix(); 
-
-  // Draw any overlays there may be
-  if(m_ScalpelMode->GetStarted() && m_ScalpelMode->GetInside())
-    {
-    glMatrixMode(GL_PROJECTION);
-    glPushMatrix();
-    glLoadIdentity();
-    gluOrtho2D(0,m_Canvas->w(),m_Canvas->h(),0);
-    
-    glMatrixMode(GL_MODELVIEW);
-    glPushMatrix();
-    glLoadIdentity();
-
-    glPushAttrib(GL_DEPTH_BUFFER_BIT);
-    glDepthFunc(GL_ALWAYS);
-
-    // Get the points
-    Vector2d x1 = to_double(m_ScalpelMode->GetStartPoint());
-    Vector2d x2 = to_double(m_ScalpelMode->GetEndPoint());
-    Vector2d d = x2-x1;
-
-    // Draw a line between the two points
-    glColor3d(1,1,1);
-    glBegin(GL_LINES);
-    glVertex2d(x1[0],x1[1]);    
-    glVertex2d(x2[0],x2[1]);    
-    glEnd();
-
-    // If the points are far enough apart, draw the normal
-    if(d.two_norm() > 10)
-      {
-      // Draw the normal midway through the line
-      Vector2d n = Vector2d(-d[1],d[0]).normalize();
-      Vector2d p1 = 0.5 * (x1 + x2);
-      Vector2d p2 = p1 + 10.0 * n;
-      
-      glBegin(GL_LINES);
-      glVertex2d(p1[0],p1[1]);    
-      glVertex2d(p2[0],p2[1]);    
-      glEnd();
-
-      // Draw a colored triangle
-      d.normalize();
-      Vector2d u1 = p2 + 4.0 * d;
-      Vector2d u2 = p2 - 4.0 * d;
-      Vector2d u3 = p2 + 1.732 * 4.0 * n;
-
-      glBegin(GL_TRIANGLES);
-      glVertex2d(u1[0],u1[1]);    
-      glVertex2d(u2[0],u2[1]);    
-      glVertex2d(u3[0],u3[1]);    
-      glEnd();
-      
-      }
-    
-    glPopMatrix();
-    
-    glMatrixMode(GL_PROJECTION);
-    glPopMatrix();
-    
-    glPopAttrib();
-  }
-
-  glFlush();
-  // CheckErrors();
-}
-
-void 
-Window3D
-::OnRotateStartAction(int x, int y)
-{
-  if ( m_Mode != WIN3D_NONE ) return;
-  m_Mode = WIN3D_ROTATE;
-  m_Trackball.StartRot(x, y, m_Canvas->w(), m_Canvas->h());
-  m_ParentUI->OnTrackballUpdate();
-}
-
-void 
-Window3D
-::OnPanStartAction(int x, int y)
-{
-  if ( m_Mode != WIN3D_NONE ) return;
-  m_Mode = WIN3D_PAN;
-  m_Trackball.StartPan(x, y);
-  m_ParentUI->OnTrackballUpdate();
-}
-
-void 
-Window3D
-::OnZoomStartAction(int irisNotUsed(x), int y)
-{
-  if ( m_Mode != WIN3D_NONE ) return;
-  m_Mode = WIN3D_ZOOM;
-  m_Trackball.StartZoom(y);
-  m_ParentUI->OnTrackballUpdate();
-}
-
-void 
-Window3D
-::OnTrackballDragAction(int x, int y)
-{
-  switch (m_Mode)
-    {
-    case WIN3D_ROTATE: 
-      m_Trackball.TrackRot(x, y, m_Canvas->w(), m_Canvas->h()); 
-      break;
-    case WIN3D_ZOOM:   
-      m_Trackball.TrackZoom(y); 
-      // this->SetupProjection();
-      break;
-    case WIN3D_PAN:    
-      m_Trackball.TrackPan(x, y, m_Canvas->w(), m_Canvas->h(),
-        2 * m_ViewHalf[X], 2 * m_ViewHalf[Y]);
-      break;
-    default: break;
-    }
-
-  m_ParentUI->OnTrackballUpdate();
-  m_Canvas->redraw();
-}
-
-void 
-Window3D
-::OnTrackballStopAction()
-{
-  switch (m_Mode)
-    {
-    case WIN3D_ROTATE:  m_Trackball.StopRot(); break;
-    case WIN3D_PAN:     m_Trackball.StopPan(); break;
-    case WIN3D_ZOOM:    
-      m_Trackball.StopZoom(); 
-      // this->SetupProjection();
-      break;
-    default: break;
-    }
-  m_Mode = WIN3D_NONE;
-  m_ParentUI->OnTrackballUpdate();
-}
-
-void 
-Window3D
-::OnCrosshairClickAction(int x,int y)
-{
-  // Make sure that there is a valid image
-  if (!m_Driver->GetCurrentImageData()->IsMainLoaded()) return;
-
-  // Only respond to the left mouse button (why?)
-  Vector3i hit;
-  if (IntersectSegData(x, y, hit))
-    {
-    m_Driver->SetCursorPosition(to_unsigned_int(hit));
-    }
-
-  m_ParentUI->OnCrosshairPositionUpdate();
-  m_ParentUI->RedrawWindows();
-}
-
-void 
-Window3D
-::OnSpraypaintClickAction(int x,int y)
-{
-  // Make sure that there is a valid image
-  if (!m_Driver->GetCurrentImageData()->IsMainLoaded()) return;
-
-  Vector3i hit;
-  if (this->IntersectSegData(x, y, hit))
-    {
-    AddSample( hit );
-    m_ParentUI->OnIRISMeshEditingAction();
-    m_Canvas->redraw();
-    }
-}
-
-void 
-Window3D
-::OnScalpelPointPairAction(int x1, int y1, int x2, int y2)
-{
-  // Requires a loaded image
-  if (!m_Driver->GetCurrentImageData()->IsMainLoaded()) return;
-
-  // Pass in the first point
-  // OnCutPlanePointRayAction(x1, y1, 1);
-  // OnCutPlanePointRayAction(x2, y2, 2);
-
-  if(ComputeCutPlane(x1,y1,x2,y2)) 
-    {
-    m_Plane.valid = 1;
-    m_ParentUI->OnIRISMeshEditingAction();
-    }
-        
-  m_Canvas->redraw();
-}
-
-/**
-  Does translation and rotation from the m_Trackball (not anisotropic scaling).
-  Make sure to glPopMatrix() after use!
-  */
-void 
-Window3D
-::SetupModelView()
-{
-}
-
-void 
-Window3D
-::SetupProjection()
-{
-  // Get the view extent 'radius'
-  m_ViewHalf = m_DefaultHalf / (double) m_Trackball.GetZoom();
-  
-  double x, y;
-  if(m_ViewHalf[X] * m_Canvas->h() > m_ViewHalf[Y] * m_Canvas->w())
-    {
-    x = m_ViewHalf[X]; 
-    y = m_Canvas->h() * x / m_Canvas->w();
-    }
-  else
-    {
-    y = m_ViewHalf[Y]; 
-    x = m_Canvas->w() * y / m_Canvas->h();
-    }
-
-  // Set up the coordinate projection
-  glMatrixMode( GL_PROJECTION );
-  glLoadIdentity();
-  glOrtho(-x, x, -y, y, -m_DefaultHalf[Z], m_DefaultHalf[Z]);
-}
-
-// Get a copy of the viewport/m_Modelview/projection matrices OpenGL uses
-void Window3D::ComputeMatricies( GLint *vport, double *mview, double *proj )
-{
-  // Compute the center of rotation
-  m_CenterOfRotation = 
-    affine_transform_point(m_WorldMatrix, m_Driver->GetCursorPosition());
-
-  // Set up the model view matrix
-  glMatrixMode(GL_MODELVIEW);
-  glPushMatrix();  
-  glLoadIdentity();
-
-  // Update the screen geometry
-  glTranslatef( m_Trackball.GetPanX(), m_Trackball.GetPanY(), 0.0 );
-  glMultMatrixf( m_Trackball.GetRot() );
-  glTranslate( -m_CenterOfRotation );
-  glMultMatrixd(m_WorldMatrix.transpose().data_block());
-
-  glGetIntegerv( GL_VIEWPORT, vport );
-  glGetDoublev( GL_MODELVIEW_MATRIX, mview );
-  glGetDoublev( GL_PROJECTION_MATRIX, proj );
-
-  glPopMatrix();
-}
-
-void Window3D::ComputeRay( int x, int y, double *mvmatrix, double *projmatrix,
-                           GLint *viewport, Vector3d &v, Vector3d &r )
-{
-  int val;
-  val = gluUnProject( (GLdouble) x, (GLdouble) y, 0.0,
-                      mvmatrix, projmatrix, viewport,
-                      &(v[0]), &(v[1]), &(v[2]) );
-  if ( val == GL_FALSE ) std::cerr << "gluUnProject #1 FAILED!!!!!" << std::endl;
-  
-  val = gluUnProject( (GLdouble) x, (GLdouble) y, 1.0,
-                      mvmatrix, projmatrix, viewport,
-                      &(r[0]), &(r[1]), &(r[2]) );
-  if ( val == GL_FALSE ) std::cerr << "gluUnProject #2 FAILED!!!!!" << std::endl;
-
-  r[0] = r[0] - v[0];
-  r[1] = r[1] - v[1];
-  r[2] = r[2] - v[2];
-}
-
-bool 
-Window3D
-::ComputeCutPlane(int wx1, int wy1, int wx2, int wy2)
-{
-  // Open GL matrices
-  double mvmatrix[16];
-  double projmatrix[16];
-  GLint viewport[4];
-  Vector3d x1,x2,p1,p2;
-
-  // Compute the GL matrices
-  ComputeMatricies( viewport, mvmatrix, projmatrix );
-
-  // Flip the y coordinate
-  wy1 = viewport[3] - wy1 - 1;
-  wy2 = viewport[3] - wy2 - 1;
-
-  // Compute the normal to the viewplane  
-  gluUnProject(0,0,0,mvmatrix,projmatrix,viewport,
-               p1.data_block(),p1.data_block()+1,p1.data_block()+2);
-  gluUnProject(0,0,1,mvmatrix,projmatrix,viewport,
-               p2.data_block(),p2.data_block()+1,p2.data_block()+2);
-  
-  // W is a vector pointing into the screen
-  Vector3d w = p2 - p1;
-
-  // Compute the vector connecting the two points currently lying on the
-  // view plane
-  gluUnProject(wx1,wy1,0,mvmatrix,projmatrix,viewport,
-               x1.data_block(),x1.data_block()+1,x1.data_block()+2);
-  gluUnProject(wx2,wy2,0,mvmatrix,projmatrix,viewport,
-               x2.data_block(),x2.data_block()+1,x2.data_block()+2);
-
-  // Now we have two orthogonal vectors laying on the cut plane.  All we have
-  // to do is take the cross product
-  Vector3d delta = x2-x1;
-  Vector3d n = - itk_cross_3d(delta, w);
-
-  // Compute the length of the normal and exit if it's zero
-  double l = n.two_norm();
-  if(l == 0.0) return false;
-
-  
-  // Compute the distance to the origin
-  m_Plane.vNormal = n.normalize();
-
-  // Check if the normal requires flipping (if the Jacobian of the world matrix
-  // is negative)
-  if(vnl_det(m_WorldMatrix) < 0)
-    m_Plane.vNormal = -m_Plane.vNormal;
-
-  m_Plane.dIntercept = dot_product(x1,m_Plane.vNormal);
-
-  // Now, this is not enough, because we want to be able to draw the plane
-  // in space.  In order to do this we need four corners of a square on the
-  // plane.
-
-  // Compute the points on the plane in world space
-  
-  Vector3d x1World = affine_transform_point(m_WorldMatrix, x1);
-  Vector3d x2World = affine_transform_point(m_WorldMatrix, x2);
-  Vector3d p1World = affine_transform_point(m_WorldMatrix, p1);
-  Vector3d p2World = affine_transform_point(m_WorldMatrix, p2);
-  
-  // Compute the normal in world coordinates
-  Vector3d nWorld = - itk_cross_3d((vnl_vector<double>) (x2World - x1World),
-                                   (vnl_vector<double>) (p2World - p1World));
-  m_Plane.vNormalWorld = nWorld.normalize();
-
-  // Compute the intercept in world coordinates  
-  double interceptWorld = dot_product(x1World,m_Plane.vNormalWorld);
-
-  // Compute the center of the volume
-  Vector3d xVol = to_double(m_VolumeSize) * 0.5;
-
-  // Compute the center of the volume in world coordinates
-  Vector3d xVolCenter = 
-    affine_transform_point(m_WorldMatrix, to_double(m_ImageSize) * 0.5);
-  
-  // Use that to compute the center of the square
-  double edgeLength = (xVol[0] > xVol[1]) ? xVol[0] : xVol[1];
-  edgeLength = (edgeLength > xVol[2]) ? edgeLength : xVol[2];
-
-  // Now compute the center point of the square   
-  Vector3d m_Origin = m_Driver->GetCurrentImageData()->GetImageOrigin();
-  Vector3d xCenter = 
-    xVolCenter - m_Plane.vNormalWorld *
-     (dot_product(xVolCenter,m_Plane.vNormalWorld) - interceptWorld);
-  
-  // Compute the 'up' vector and the 'in' vector
-  Vector3d vUp = (x2World - x1World).normalize();
-  Vector3d vIn = (p2World - p1World).normalize();
-
-  // Compute the corners
-  m_Plane.xDisplayCorner[0] = xCenter + edgeLength * (vUp + vIn);
-  m_Plane.xDisplayCorner[1] = xCenter + edgeLength * (vUp - vIn);
-  m_Plane.xDisplayCorner[2] = xCenter + edgeLength * (- vUp - vIn);
-  m_Plane.xDisplayCorner[3] = xCenter + edgeLength * (- vUp + vIn);
-
-  return true;
-}
-
-
-
-//------------------------------------------------------------------------
-// IntersectSegData(int mouse_x, int mouse_y, Vector3i *hit)
-// computes a m_Ray going straight back from the current viewpoint
-// from the mouse click position on screen.
-// The output Vector3i hit is in image coords.
-//
-//------------------------------------------------------------------------
-int Window3D::IntersectSegData(int mouse_x, int mouse_y, Vector3i &hit)
-{
-  double mvmatrix[16];
-  double projmatrix[16];
-  GLint viewport[4];
-
-  m_Canvas->make_current(); // update GL state
-  ComputeMatricies( viewport, mvmatrix, projmatrix );
-  int x = mouse_x;
-  int y = viewport[3] - mouse_y - 1;
-  ComputeRay( x, y, mvmatrix, projmatrix, viewport, m_Point, m_Ray );
-
-  // The result 
-  int result = 0;
-  
-  // Depending on the situation, we may intersect with a snake image or a
-  // segmentation image
-  // TODO: Need both conditions?
-  if(m_GlobalState->GetSnakeActive() && 
-     m_Driver->GetSNAPImageData()->IsSnakeLoaded())
-    {
-    typedef ImageRayIntersectionFinder<
-      float,SnakeImageHitTester> RayCasterType;
-
-    RayCasterType caster;
-
-    result = 
-      caster.FindIntersection(
-        m_Driver->GetSNAPImageData()->GetLevelSetImage(),
-        m_Point,m_Ray,hit);
-    }
-  else
-    {
-    typedef ImageRayIntersectionFinder<
-      LabelType,LabelImageHitTester> RayCasterType;
-
-    RayCasterType caster;
-    caster.SetHitTester(LabelImageHitTester(m_Driver->GetColorLabelTable()));
-    result = 
-      caster.FindIntersection(
-        m_Driver->GetCurrentImageData()->GetSegmentation()->GetImage(),
-        m_Point,m_Ray,hit);
-    }
-  
-  // m_Ray now has the proj m_Ray, m_Point is the m_Point in image space
-  switch (result)
-    {
-    case 1: return 1;
-    case -1: /*std::cerr << "RAY WAS INVALID!" << std::endl;*/ break;
-    /* default: std::cerr << "No hit found" << std::endl;*/
-    }
-  return 0;
-}
-
-void Window3D::AddSample( Vector3i s )
-{
-  // Add another sample.
-  m_Samples.push_back(s);
-}
-
-void DrawCube( Vector3f &x, Vector3f &y )
-  {
-  glBegin(GL_LINE_LOOP);
-  glVertex3f( x[0], x[1], x[2] );
-  glVertex3f( x[0], y[1], x[2] );
-  glVertex3f( x[0], y[1], y[2] );
-  glVertex3f( x[0], x[1], y[2] );
-  glEnd();
-
-  glBegin(GL_LINE_LOOP);
-  glVertex3f( y[0], x[1], x[2] );
-  glVertex3f( y[0], y[1], x[2] );
-  glVertex3f( y[0], y[1], y[2] );
-  glVertex3f( y[0], x[1], y[2] );
-  glEnd();
-
-  glBegin(GL_LINES);
-  glVertex3f( x[0], x[1], x[2] );
-  glVertex3f( y[0], x[1], x[2] );
-  glVertex3f( x[0], y[1], x[2] );
-  glVertex3f( y[0], y[1], x[2] );
-  glVertex3f( x[0], x[1], y[2] );
-  glVertex3f( y[0], x[1], y[2] );
-  glVertex3f( x[0], y[1], y[2] );
-  glVertex3f( y[0], y[1], y[2] );
-  glEnd();
-  }
-
-void DrawCoordinateCutPlane( unsigned int iPlane, Vector3f &a, Vector3f &b, Vector3f &x )
-  {
-  glBegin(GL_LINE_LOOP);
-
-  switch(iPlane) {
-    case 0 :
-      glVertex3f( x[0], a[1], a[2] );
-      glVertex3f( x[0], a[1], b[2] );
-      glVertex3f( x[0], b[1], b[2] );
-      glVertex3f( x[0], b[1], a[2] );
-      break;
-
-    case 1 :
-      glVertex3f( a[0], x[1], a[2] );
-      glVertex3f( a[0], x[1], b[2] );
-      glVertex3f( b[0], x[1], b[2] );
-      glVertex3f( b[0], x[1], a[2] );
-      break;
-
-    case 2 :
-      glVertex3f( a[0], a[1], x[2] );
-      glVertex3f( a[0], b[1], x[2] );
-      glVertex3f( b[0], b[1], x[2] );
-      glVertex3f( b[0], a[1], x[2] );
-      break;
-    }
-
-  glEnd();
-  }
-
-void Window3D::DrawCrosshairs()
-{
-  if ( !m_CursorVisible ) return;
-
-  // Set up the GL state
-  glPushAttrib(GL_LINE_BIT | GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT);
-  glDisable(GL_LIGHTING);
-
-  // Get the crosshair position
-  Vector3f xCross = 
-    to_float(m_Driver->GetCursorPosition()) + Vector3f(0.5f);
-
-  // Get the UI element properties for the image box
-  SNAPAppearanceSettings::Element &eltBox = 
-    m_ParentUI->GetAppearanceSettings()->GetUIElement(
-    SNAPAppearanceSettings::IMAGE_BOX_3D);
-
-  // Draw the image box
-  if(eltBox.Visible)
-    {
-    // Set the line properties
-    SNAPAppearanceSettings::ApplyUIElementLineSettings(eltBox);
-
-    // The cube around the image
-    glColor3dv(eltBox.NormalColor.data_block());
-    Vector3f zeros(0.0f);
-    Vector3f imageSize = to_float(m_ImageSize);
-    DrawCube( zeros, imageSize );
-
-    // The slice planes
-    glColor3dv(eltBox.ActiveColor.data_block());
-    for(int d = 0; d < 3; d++)
-      DrawCoordinateCutPlane(d, zeros, imageSize, xCross );
-    }
-
-  // Get the UI element properties for the crosshairs
-  SNAPAppearanceSettings::Element &eltCross = 
-    m_ParentUI->GetAppearanceSettings()->GetUIElement(
-    SNAPAppearanceSettings::CROSSHAIRS_3D);
-
-  // Exit if crosshairs are to be ignored
-  if(eltCross.Visible) 
-    {
-    // Set up the line properties
-    glColor3dv(eltCross.NormalColor.data_block());
-    SNAPAppearanceSettings::ApplyUIElementLineSettings(eltCross);
-
-    // Draw the lines
-    glBegin( GL_LINES );
-    for (int i=0; i<3; i++)
-      {
-      float end1[3], end2[3];
-      for (int j=0; j<3; j++)
-        end1[j] = end2[j] = xCross[j];
-      // end1[i] = m_Center[i] - m_ImageSize[i]*0.7+1;
-      // end2[i] = m_Center[i] + m_ImageSize[i]*0.7+1;
-      end1[i] = 0.0f;
-      end2[i] = m_ImageSize[i];
-
-      glVertex3fv(end1);
-      glVertex3fv(end2);
-      }
-    glEnd();
-    }
-
-#if DEBUGGING
-  glColor3f( 1.0, 1.0, 0.0 );
-  glBegin( GL_LINES );
-  glVertex3d( m_Point[0],        m_Point[1],        m_Point[2] );
-  glVertex3d( m_Point[0]+m_Ray[0], m_Point[1]+m_Ray[1], m_Point[2]+m_Ray[2] );
-  glEnd();
-
-  std::cerr << "A = ( " << m_Point[0] << ", " << m_Point[1] << ", " << m_Point[2] << " )" << std::endl;
-  std::cerr << "B = ( " << m_Point[0]+m_Ray[0]
-  << ", " << m_Point[1]+m_Ray[1]
-  << ", " << m_Point[2]+m_Ray[2] << " )" << std::endl;
-#endif
-
-  // Finish
-  glPopAttrib();
-}
-
-void Window3D::DrawSamples()
-{
-  unsigned char index = m_GlobalState->GetDrawingColorLabel();
-  unsigned char rgb[3];
-  m_Driver->GetColorLabelTable()->GetColorLabel(index).GetRGBVector(rgb);
-
-  glColor3ubv(rgb);
-  for (SampleListIterator it=m_Samples.begin();it!=m_Samples.end();it++)
-    {
-    glPushMatrix(); 
-    glTranslate(to_float(*it));
-
-    GLUquadric *quad = gluNewQuadric();
-    gluSphere(quad,1.0,4,4);
-    gluDeleteQuadric(quad);
-    // glutSolidSphere( 1.0, 4, 4 );
-
-    glPopMatrix();
-    }
-}
-
-//-----------------------------------------------------------------------
-// DrawCutPlane
-//   Provides User Feedback Information when in 3D Window Mode
-//   when a Cutplane is defined.
-// Input: the 'plane' member
-// Output: GLplane representing the Cutplane that is defined by the user
-//-----------------------------------------------------------------------
-void Window3D
-::DrawCutPlane() 
-{
-  if (m_Plane.valid != 1) return;
-
-  Vector3d corner[4];  
-  corner[0] = m_Plane.xDisplayCorner[0];
-  corner[1] = m_Plane.xDisplayCorner[1];
-  corner[2] = m_Plane.xDisplayCorner[2];
-  corner[3] = m_Plane.xDisplayCorner[3];
-
-  // Use the current label color
-  unsigned char rgb[3];
-  m_Driver->GetColorLabelTable()->GetColorLabel(
-    m_GlobalState->GetDrawingColorLabel()).GetRGBVector(rgb);
-
-  // Save the settings
-  glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT | GL_LIGHTING_BIT);
-
-  // Create a stipple pattern
-  GLubyte stipple[128];
-  for(unsigned int q = 0; q < 128; q++)
-    stipple[q] = ((q >> 2) % 2 == 0) ? 0xAA : 0x55;
-
-  // Draw a semi-transparent quad
-  glEnable(GL_POLYGON_STIPPLE);
-  glPolygonStipple(stipple);
-  glColor3ubv(rgb);
-  glBegin(GL_QUADS);
-  glVertex(corner[0]);
-  glVertex(corner[1]);
-  glVertex(corner[2]);
-  glVertex(corner[3]);
-  glEnd();
-  glDisable(GL_POLYGON_STIPPLE);
-
-  // Draw the plane using lines
-  glEnable(GL_LINE_SMOOTH);
-  glEnable(GL_LINE_STIPPLE);
-  glEnable(GL_BLEND);
-  glDisable(GL_LIGHTING);
-  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-  glLineWidth(2.0);
-  glLineStipple(2,0xAAAA);
-
-  
-  // Start with a white color
-  glColor3d(1,1,1);
-  Vector3d planeUnitNormal = Vector3d(m_Plane.vNormalWorld).normalize();
-  for(unsigned int i=0;i<4;i++)
-    {
-    glPushMatrix();
-
-    // Create a parallel plane to create a moving effect
-    Vector3d vOffset = planeUnitNormal * (1.0 * i);
-    glTranslate(vOffset);
-
-    // Draw a line loop
-    glBegin(GL_LINE_LOOP);
-    glVertex(corner[0]);
-    glVertex(corner[1]);
-    glVertex(corner[2]);
-    glVertex(corner[3]);
-    glEnd();
-
-    // Switch to new color
-    glColor3ubv(rgb);
-
-    glPopMatrix();
-    }
-
-  glPopAttrib();
-};
-
-int 
-Window3D
-::OnKeyAction(int key)
-{
-  if(Fl::event_state() != FL_CTRL && key == 's')
-    {
-    // Store the state of the trackball
-    m_TrackballBackup = m_Trackball;
-    return 1;
-    }
-  else if(Fl::event_state() != FL_CTRL && key == 'r')
-    {
-    // Restore the trackball state
-    m_Trackball = m_TrackballBackup;
-    m_Canvas->redraw();
-    m_ParentUI->OnTrackballUpdate();
-    return 1;
-    }
-  return 0;
-}
-
-/*
- *$Log: Window3D.cxx,v $
- *Revision 1.13  2009/10/26 16:40:19  pyushkevich
- *FIX(2039124): spray paint was not respecting hidden labels. Also update mesh was not on after label vis change
- *
- *Revision 1.12  2009/10/26 07:34:11  pyushkevich
- *ENH: substantially reduced memory footprint when loading float NIFTI images
- *
- *Revision 1.11  2009/10/25 13:17:05  pyushkevich
- *FIX: bugs in SF.net, crash on mesh update in large images, bad vols/stats output
- *
- *Revision 1.10  2009/07/16 22:02:29  pyushkevich
- *Made OpenGLTexture non-templated
- *
- *Revision 1.9  2009/06/02 04:32:46  garyhuizhang
- *ENH: layer support
- *
- *Revision 1.8  2009/01/30 23:08:21  garyhuizhang
- *ENH: better implementation of the keyboard shortcuts that do not require the SHIFT key
- *
- *Revision 1.7  2009/01/30 20:57:34  garyhuizhang
- *Bug Fix: check if any of the CTRL keys is pressed in Windows3D::OnKeyAction()
- *
- *Revision 1.6  2009/01/23 20:54:11  pyushkevich
- *FIX: fixed cut plane behavior, which was broken by earlier 3D changes
- *
- *Revision 1.5  2009/01/23 20:09:38  pyushkevich
- *FIX: 3D rendering now takes place in Nifti(RAS) world coordinates, rather than the VTK (x spacing + origin) coordinates. As part of this, itk::OrientedImage is now used for 3D images in SNAP. Still have to fix cut plane code in Window3D
- *
- *Revision 1.4  2009/01/17 10:40:28  pyushkevich
- *Added synchronization to 3D window viewpoint
- *
- *Revision 1.3  2008/02/10 23:55:22  pyushkevich
- *Added "Auto" button to the intensity curve window; Added prompt before quitting on unsaved data; Fixed issues with undo on segmentation image load; Added synchronization between SNAP sessions.
- *
- *Revision 1.2  2007/12/30 04:05:29  pyushkevich
- *GPL License
- *
- *Revision 1.1  2006/12/02 04:22:27  pyushkevich
- *Initial sf checkin
- *
- *Revision 1.1.1.1  2006/09/26 23:56:17  pauly2
- *Import
- *
- *Revision 1.33  2006/02/01 20:21:27  pauly
- *ENH: An improvement to the main SNAP UI structure: one set of GL windows is used to support SNAP and IRIS modes
- *
- *Revision 1.32  2006/01/05 18:03:09  pauly
- *STYLE: Removed unnecessary console messages from SNAP
- *
- *Revision 1.31  2005/12/12 00:27:45  pauly
- *ENH: Preparing SNAP for 1.4 release. Snapshot functionality
- *
- *Revision 1.30  2005/11/23 14:32:15  ibanez
- *BUG: 2404. Patch provided by Paul Yushkevish.
- *
- *Revision 1.29  2005/10/29 14:00:15  pauly
- *ENH: SNAP enhacements like color maps and progress bar for 3D rendering
- *
- *Revision 1.28  2005/08/10 03:24:21  pauly
- *BUG: Corrected problems with 3D window, label IO from association files
- *
- *Revision 1.27  2005/04/21 14:46:30  pauly
- *ENH: Improved management and editing of color labels in SNAP
- *
- *Revision 1.26  2005/03/08 03:12:51  pauly
- *BUG: Minor bugfixes in SNAP, mostly to the user interface
- *
- *Revision 1.25  2004/12/31 17:34:04  lorensen
- *COMP: gcc3.4 issues.
- *
- *Revision 1.24  2004/10/04 17:41:46  pauly
- *FIX: Filename extensions for FLTK includes
- *
- *Revision 1.23  2004/09/21 16:13:35  jjomier
- *FIX: Linux, gcc3.3 fixes
- *
- *Revision 1.22  2004/09/21 15:50:51  jjomier
- *FIX: vector_multiply_mixed requires template parameters otherwise MSVC cannot deduce them
- *
- *Revision 1.21  2004/09/14 14:11:11  pauly
- *ENH: Added an activation manager to main UI class, improved snake code, various UI fixes and additions
- *
- *Revision 1.20  2004/08/26 18:29:20  pauly
- *ENH: New user interface for configuring the UI options
- *
- *Revision 1.19  2004/07/29 14:02:05  pauly
- *ENH: An interface for changing SNAP appearance settings
- *
- *Revision 1.18  2004/07/22 19:22:51  pauly
- *ENH: Large image support for SNAP. This includes being able to use more screen real estate to display a slice, a fix to the bug with manual segmentation of images larger than the window size, and a thumbnail used when zooming into the image.
- *
- *Revision 1.17  2004/06/01 13:33:55  king
- *ERR: Fix for cross_3d to work with both the ITK version and current cvs version of vxl.
- *
- *Revision 1.16  2004/05/12 18:09:12  pauly
- *FIX:Error with cross_3d symbol
- *
- *Revision 1.15  2004/01/27 18:18:44  pauly
- *FIX: Last MAC OSX fix
- *
- *Revision 1.14  2004/01/27 18:05:38  pauly
- *FIX: More MAC OSX fixes. Also removed old snake code no longer in use
- *
- *Revision 1.13  2004/01/27 17:34:00  pauly
- *FIX: Compiling on Mac OSX, issue with GLU include file
- *
- *Revision 1.12  2003/11/25 23:32:48  pauly
- *FIX: Snake evolution did not work in multiprocessor mode
- *
- *Revision 1.11  2003/11/10 00:24:50  pauly
- **** empty log message ***
- *
- *Revision 1.10  2003/10/14 13:44:27  pauly
- *FIX: Fixed warnings on gcc-3.3
- *
- *Revision 1.9  2003/10/10 15:04:21  pauly
- *ENH: Cut plane improvements (paint-over-visible and paint-over-one)
- *
- *Revision 1.8  2003/10/10 14:25:55  pauly
- *FIX: Ensured that code compiles on gcc 3-3
- *
- *Revision 1.7  2003/10/09 22:45:15  pauly
- *EMH: Improvements in 3D functionality and snake parameter preview
- *
- *Revision 1.6  2003/10/02 20:57:46  pauly
- *FIX: Made sure that the previous check-in compiles on Linux
- *
- *Revision 1.5  2003/10/02 14:55:53  pauly
- *ENH: Development during the September code freeze
- *
- *Revision 1.2  2003/09/11 19:23:29  pauly
- *FIX: Code compiles and runs on UNIX platform
- *
- *Revision 1.1  2003/09/11 13:51:15  pauly
- *FIX: Enabled loading of images with different orientations
- *ENH: Implemented image save and load operations
- *
- *Revision 1.4  2003/08/28 22:58:30  pauly
- *FIX: Erratic scrollbar behavior
- *
- *Revision 1.3  2003/08/27 14:03:24  pauly
- *FIX: Made sure that -Wall option in gcc generates 0 warnings.
- *FIX: Removed 'comment within comment' problem in the cvs log.
- *
- *Revision 1.2  2003/08/27 04:57:47  pauly
- *FIX: A large number of bugs has been fixed for 1.4 release
- *
- *Revision 1.1  2003/07/12 04:46:51  pauly
- *Initial checkin of the SNAP application into the InsightApplications tree.
- *
- *Revision 1.2  2003/07/12 01:34:18  pauly
- *More final changes before ITK checkin
- *
- *Revision 1.1  2003/07/11 23:25:33  pauly
- **** empty log message ***
- *
- *Revision 1.9  2003/06/08 23:27:56  pauly
- *Changed variable names using combination of ctags, egrep, and perl.
- *
- *Revision 1.8  2003/06/04 04:52:17  pauly
- *More UI fixes for the demo
- *
- *Revision 1.7  2003/05/08 21:59:05  pauly
- *SNAP is almost working
- *
- *Revision 1.6  2003/05/07 19:14:46  pauly
- *More progress on getting old segmentation working in the new SNAP.  Almost there, region of interest and bubbles are working.
- *
- *Revision 1.5  2003/04/29 14:01:42  pauly
- *Charlotte Trip
- *
- *Revision 1.4  2003/04/23 06:05:18  pauly
- **** empty log message ***
- *
- *Revision 1.3  2003/04/18 17:32:18  pauly
- **** empty log message ***
- *
- *Revision 1.2  2003/04/16 05:04:17  pauly
- *Incorporated intensity modification into the snap pipeline
- *New IRISApplication
- *Random goodies
- *
- *Revision 1.1  2003/03/07 19:29:48  pauly
- *Initial checkin
- *
- *Revision 1.2  2002/12/16 16:40:19  pauly
- **** empty log message ***
- *
- *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
- *Started the project repository
- *
- *
- *Revision 1.10  2002/06/04 20:26:23  seanho
- *new rotation code from iris
- *
- *Revision 1.9  2002/04/27 18:31:05  moon
- *Finished commenting
- *
- *Revision 1.8  2002/04/24 17:15:13  bobkov
- *made no changes
- *
- *Revision 1.7  2002/04/23 22:00:39  moon
- *Just put in a couple glMatrixMode(GL_MODELVIEW) in a few places I thought it should
- *be just to be cautious.  I don't think it changed anything.
- *
- *Revision 1.6  2002/04/22 21:56:21  moon
- *Put in code to get crosshairs m_Mode working in 3D window.  Just checks global
- *flag in the mouseclick method to see if we're in snake m_Mode, so that the
- *right windows get redrawn.
- *
- *Revision 1.5  2002/04/13 16:22:40  moon
- *Fixed the problem with the 3D window drawing in black.
- *The draw method needed to call Init() in the if (!valid()) block.  It had two
- *checks, for !valid, and m_NeedsInitialization.  They just needed to be combined so that
- *lighting, etc. was set up either way.  The bug seems to be fixed.
- *
- *Revision 1.4  2002/04/10 21:22:12  moon
- *added some make_current calls to some methods, which seems to help the window to
- *update better, but the color/lighting problem is still there.
- *
- *Revision 1.3  2002/04/10 20:26:24  moon
- *just put in some debug statements.  Trying to debug the 3dwindow not drawing right.
- *
- *Revision 1.2  2002/03/08 14:06:32  moon
- *Added Header and Log tags to all files
- **/
diff --git a/UserInterface/Window3D/Window3D.h b/UserInterface/Window3D/Window3D.h
deleted file mode 100644
index a69b955..0000000
--- a/UserInterface/Window3D/Window3D.h
+++ /dev/null
@@ -1,365 +0,0 @@
-/*=========================================================================
-
-  Program:   ITK-SNAP
-  Module:    $RCSfile: Window3D.h,v $
-  Language:  C++
-  Date:      $Date: 2009/01/23 20:09:38 $
-  Version:   $Revision: 1.4 $
-  Copyright (c) 2007 Paul A. Yushkevich
-  
-  This file is part of ITK-SNAP 
-
-  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
-
-  -----
-
-  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
-  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the above copyright notices for more information. 
-
-=========================================================================*/
-#ifndef __Window3D_h_
-#define __Window3D_h_
-
-#include <stdlib.h>
-#include <FL/Fl.H>
-#include <FL/Fl_Gl_Window.H>
-
-#include "SNAPOpenGL.h"
-#include "RecursiveInteractionMode.h"
-#include "SNAPCommonUI.h"
-#include "Trackball.h"
-#include "MeshObject.h"
-
-// Forward references to parent classes
-class UserInterfaceBase;
-class IRISApplication;
-class GlobalState;
-
-// Forward references to interactors defined in Window3D.cxx
-class Crosshairs3DInteractionMode;
-class Trackball3DInteractionMode;
-class Spraypaint3DInteractionMode;
-class Scalpel3DInteractionMode;
-
-namespace itk {
-  class Command;
-}
-
-//--------------------------------------------------------------
-// plane struct
-//-------------------------------------------------------------
-struct CutPlaneStruct
-{
-  // The normal vector in image coordinates
-  Vector3d vNormal;
-
-  // The intercept (distance to zero) in image coordinates
-  double dIntercept;
-
-  // The normal vector in world coordinates
-  Vector3d vNormalWorld;
-
-  // The four corners used to display the plane  
-  Vector3d xDisplayCorner[4];
-
-  // The valid/invalid state of the plane
-  int valid; 
-};
-
-/**
- * \class Window3D
- * \brief Window used to display the 3D segmentation
- */
-class Window3D : public RecursiveInteractionMode
-{
-public:
-
-  enum {X,Y,Z};
-
-  /**
-   * Constructor: registers this interactor with the parent UI and the 
-   * client window
-   */
-  Window3D(UserInterfaceBase *parentUI, FLTKCanvas *canvas);
-
-  virtual ~Window3D(void); /* Needed to be virtual to avoid compiler warning */
-  Window3D& operator= ( const Window3D& W ) { return *this; };
-
-  /** Initialize the window */
-  void Initialize();
-
-  /** Clear the 3D display */
-  void ClearScreen();
-
-  /** Reset the trackball to default position */
-  void ResetView();
-
-  /** Perform the GL drawing operations */
-  void OnDraw();
-
-  /** Recompute the mesh (slow operation) */
-  void UpdateMesh(itk::Command *xProgressCommand);
-
-  /** Respond to user pressing the accept button */
-  void Accept();
-
-  /** Enter the cross-hairs mode of operation */
-  virtual void EnterCrosshairsMode();
-  
-  /** Enter the trackball mode of operation */
-  virtual void EnterTrackballMode();
-
-  /** Enter the scalpel mode of operation */
-  virtual void EnterScalpelMode();
-  
-  /** Enter the spraypaint mode of operation */
-  virtual void EnterSpraypaintMode();
-
-  irisGetMacro(Trackball, Trackball);
-  irisSetMacro(Trackball, Trackball);
-
-  /** A parent class from which all the Fl event handlers associated
-   * with this class should be derived */
-  class EventHandler : public InteractionMode {
-  public:
-    EventHandler(Window3D *parent) 
-      : InteractionMode(parent->GetCanvas()) 
-    {
-      m_Parent = parent;
-    }    
-    void Register() 
-    {
-      m_Driver = m_Parent->m_Driver;
-      m_ParentUI = m_Parent->m_ParentUI;
-      m_GlobalState = m_Parent->m_GlobalState;
-    }
-    virtual int OnKeyDown(const FLTKEvent &e)
-      { return m_Parent->OnKeyAction(e.Key); }
-  protected:
-    Window3D *m_Parent;
-    GlobalState *m_GlobalState;
-    UserInterfaceBase *m_ParentUI;
-    IRISApplication *m_Driver;
-  };
-
-  // Allow friendly access by interactors
-  friend class EventHandler;
-  friend class Trackball3DInteractionMode;
-  friend class Crosshairs3DInteractionMode;
-  friend class Scalpel3DInteractionMode;
-  friend class Spraypaint3DInteractionMode;
-
-  // Methods called by these interactors (unlike GenericSliceWindow, this window
-  // does not delegate much of its control to the interactors and only provides
-  // these interfaces for them
-  void OnRotateStartAction(int x, int y);
-  void OnPanStartAction(int x, int y);
-  void OnZoomStartAction(int x, int y);
-  void OnTrackballDragAction(int x, int y);
-  void OnTrackballStopAction();
-  void OnCrosshairClickAction(int x,int y);
-  void OnSpraypaintClickAction(int x,int y);
-  void OnScalpelPointPairAction(int x1, int y1, int x2, int y2);
-  int OnKeyAction(int key);
-
-private:
-
-  // Pointer to the application driver for this UI object
-  IRISApplication *m_Driver;
-
-  // Pointer to the global state object (shorthand)
-  GlobalState *m_GlobalState;
-
-  // Pointer to GUI that contains this Window3D object
-  UserInterfaceBase *m_ParentUI;   
-
-  // Interaction modes
-  Crosshairs3DInteractionMode *m_CrosshairsMode;
-  Trackball3DInteractionMode *m_TrackballMode;
-  Spraypaint3DInteractionMode *m_SpraypaintMode;
-  Scalpel3DInteractionMode *m_ScalpelMode;
-
-  // Cut planes 3d mode added by Robin
-  enum Win3DMode
-    { WIN3D_NONE, WIN3D_PAN, WIN3D_ZOOM, WIN3D_ROTATE, WIN3D_CUT };
-
-  Win3DMode m_Mode;
-  Trackball  m_Trackball, m_TrackballBackup;
-  MeshObject m_Mesh;
-  CutPlaneStruct m_Plane;
-
-  // id of window
-  int m_NeedsInitialization;
-  int m_CursorVisible;
-
-  // Coordinate systems: image coords have unit distance equal to one voxel,
-  // origin is at the origin of the image (left bottom back).
-  // World coords have same origin, but distance is in mm.
-  // The mesh object is in world coords, but the crosshairs position and the
-  // rays to fire into the seg data are in image coords.
-
-  // Extent of the image, in image coords
-  Vector3ui m_ImageSize;   
-
-  // Matrix from voxel space to world coordinates (NIFTI/RAS coords)
-  typedef vnl_matrix_fixed<double, 4, 4> Mat4d;
-  Mat4d m_WorldMatrix;
-
-  // Dimensions of a voxel, in mm
-  // Vector3f m_Spacing, m_Origin;   
-
-  // Dimensions of the image (dimensions * spacing)
-  Vector3d m_VolumeSize;
-
-  // Center of image, in world coords
-  Vector3d m_Center;    
-
-  // Center of rotation, in world coords
-  Vector3d m_CenterOfRotation;    
-
-  // width of view, in world coords
-  Vector3d m_DefaultHalf, m_ViewHalf; 
-
-  // A ray and a point used for projecting mouse-clicks onto the 3D surface
-  Vector3d m_Ray;
-  Vector3d m_Point;
-
-  // An array of samples
-  typedef std::list<Vector3i> SampleListType;
-  typedef SampleListType::iterator SampleListIterator;
-  SampleListType m_Samples;
-  
-  void MousePressFunc(int button);
-  void MouseReleaseFunc();
-  void MouseMotionFunc();
-  void MouseCrossPressFunc(int button);
-  void MousePointPressFunc(int button);
-  void MouseCutPressFunc(int button);
-  void SetupModelView();
-  void SetupProjection();
-  void ComputeMatricies( GLint *vport, double *mview, double *proj );
-  void ComputeRay( int x, int y, double *mvmatrix, double *projmat,
-                   GLint *viewport, Vector3d &v, Vector3d &r );
-
-  /** Try to compute cut plane.  Return false if the points coincide */
-  bool ComputeCutPlane(int wx1, int wy1, int wx2, int wy2);
-
-  int IntersectSegData(int mouse_x, int mouse_y, Vector3i &hit);
-
-  // void OnCutPlanePointRayAction(int mouse_x, int mouse_y, int i);
-  // void ComputePlane();
-  void DrawCutPlane(); // Added by Robin & Ming
-
-  void AddSample( Vector3i s );
-  void DrawCrosshairs();
-  void DrawSamples();
-
-  void CheckErrors();
-
-};
-
-#endif // __Window3D_h_
-
-/*
- *$Log: Window3D.h,v $
- *Revision 1.4  2009/01/23 20:09:38  pyushkevich
- *FIX: 3D rendering now takes place in Nifti(RAS) world coordinates, rather than the VTK (x spacing + origin) coordinates. As part of this, itk::OrientedImage is now used for 3D images in SNAP. Still have to fix cut plane code in Window3D
- *
- *Revision 1.3  2009/01/17 10:40:28  pyushkevich
- *Added synchronization to 3D window viewpoint
- *
- *Revision 1.2  2007/12/30 04:05:29  pyushkevich
- *GPL License
- *
- *Revision 1.1  2006/12/02 04:22:27  pyushkevich
- *Initial sf checkin
- *
- *Revision 1.1.1.1  2006/09/26 23:56:17  pauly2
- *Import
- *
- *Revision 1.13  2006/02/01 20:21:27  pauly
- *ENH: An improvement to the main SNAP UI structure: one set of GL windows is used to support SNAP and IRIS modes
- *
- *Revision 1.12  2005/12/12 00:27:45  pauly
- *ENH: Preparing SNAP for 1.4 release. Snapshot functionality
- *
- *Revision 1.11  2005/12/08 18:20:46  hjohnson
- *COMP:  Removed compiler warnings from SGI/linux/MacOSX compilers.
- *
- *Revision 1.10  2005/10/29 14:00:16  pauly
- *ENH: SNAP enhacements like color maps and progress bar for 3D rendering
- *
- *Revision 1.9  2004/09/14 14:11:11  pauly
- *ENH: Added an activation manager to main UI class, improved snake code, various UI fixes and additions
- *
- *Revision 1.8  2004/08/26 18:29:21  pauly
- *ENH: New user interface for configuring the UI options
- *
- *Revision 1.7  2004/01/27 18:05:38  pauly
- *FIX: More MAC OSX fixes. Also removed old snake code no longer in use
- *
- *Revision 1.6  2004/01/27 17:34:00  pauly
- *FIX: Compiling on Mac OSX, issue with GLU include file
- *
- *Revision 1.5  2003/10/09 22:45:15  pauly
- *EMH: Improvements in 3D functionality and snake parameter preview
- *
- *Revision 1.4  2003/10/02 14:55:53  pauly
- *ENH: Development during the September code freeze
- *
- *Revision 1.1  2003/09/11 13:51:15  pauly
- *FIX: Enabled loading of images with different orientations
- *ENH: Implemented image save and load operations
- *
- *Revision 1.3  2003/08/27 14:03:24  pauly
- *FIX: Made sure that -Wall option in gcc generates 0 warnings.
- *FIX: Removed 'comment within comment' problem in the cvs log.
- *
- *Revision 1.2  2003/08/27 04:57:47  pauly
- *FIX: A large number of bugs has been fixed for 1.4 release
- *
- *Revision 1.1  2003/07/12 04:46:51  pauly
- *Initial checkin of the SNAP application into the InsightApplications tree.
- *
- *Revision 1.6  2003/07/12 01:34:18  pauly
- *More final changes before ITK checkin
- *
- *Revision 1.5  2003/07/11 23:25:33  pauly
- **** empty log message ***
- *
- *Revision 1.4  2003/06/08 23:27:56  pauly
- *Changed variable names using combination of ctags, egrep, and perl.
- *
- *Revision 1.3  2003/04/23 06:05:18  pauly
- **** empty log message ***
- *
- *Revision 1.2  2003/04/16 05:04:17  pauly
- *Incorporated intensity modification into the snap pipeline
- *New IRISApplication
- *Random goodies
- *
- *Revision 1.1  2003/03/07 19:29:48  pauly
- *Initial checkin
- *
- *Revision 1.1.1.1  2002/12/10 01:35:36  pauly
- *Started the project repository
- *
- *
- *Revision 1.2  2002/03/08 14:06:32  moon
- *Added Header and Log tags to all files
- **/
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/.TAR_RELEASE.sh b/Utilities/FLTK/Fl_Native_File_Chooser/.TAR_RELEASE.sh
deleted file mode 100644
index 4706348..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/.TAR_RELEASE.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh
-
-#
-# CREATE RELEASE TAR FILE
-#     For maintainer only!
-#
-
-VERSION=`awk '/^[0-9]*\.[^ \t]/ {print $1; exit(0);}'<CHANGES`
-TARFILE=/var/tmp/Fl_Native_File_Chooser-$VERSION.tar.gz
-RELEASEDIR=./.release/Fl_Native_File_Chooser-$VERSION
-
-# MODES
-chmod 644 FL/* fltk/* *.cxx [A-Z]* make.bat \
-	  documentation/*.html documentation/images/* \
-	  reference/* \
-	  Makefile* CHANGES CREDITS TODO README*
-
-chmod 755 reference documentation documentation/images \
-	  FL fltk
-
-# RELEASE DIR
-rm -rf ./.release/ 2> /dev/null
-mkdir -p $RELEASEDIR
-
-cp -rp .TAR_RELEASE.sh * ./.release/Fl_Native_File_Chooser-$VERSION
-
-sleep 1		# prevents 'file changed' during tar
-
-# Remove local settings
-awk '/REMOVE:START/ { remove = 1; }
-     /REMOVE:END/   { remove = 0; }
-     { if ( remove == 0 ) print $0 }' \
-	   < $RELEASEDIR/Makefile \
-	   > $RELEASEDIR/Makefile.new
-mv $RELEASEDIR/Makefile.new $RELEASEDIR/Makefile
-
-# CREATE TAR FILE
-( cd ./.release; \
-  tar cvfz $TARFILE --numeric-owner \
-                    --owner=0 \
-		    --group=0 \
-		    --exclude=scp-to-seriss \
-		    Fl_Native_File_Chooser-$VERSION 
-)
-
-# CLEANUP
-rm -rf ./.release 2> /dev/null
-echo "*** Created: $TARFILE"
-
-# UPLOAD
-if [ -x ./scp-to-seriss ]; then ./scp-to-seriss $TARFILE; fi
-
-exit 0
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/CHANGES b/Utilities/FLTK/Fl_Native_File_Chooser/CHANGES
deleted file mode 100644
index 4d99e72..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/CHANGES
+++ /dev/null
@@ -1,166 +0,0 @@
-# WARNING: Makefile automatically derives version number from the first line
-# of this file that starts with x.x
-#  |
-# \|/
-#  v
-
-0.86 - 09/05/2009      -- applied patches received from users
------------------------------------------------------
-
-	o NO API CHANGES IN THIS RELEASE -- FIXES ONLY
-
-        o Applied Gary Hui Zhang's patch from fltk.developer 09/04/2009
-	  to use FsRef instead of FsSpec (to support OSX 10.6 Snow Leopard)
-	
-	o Applied Walter Garm's recommendations to remove BIF_SHAREABLE
-	  from the WIN32 flags.
-	  
-	  When BIF_SHAREABLE is specified, apparently it HIDES shareable
-	  drives in BROWSE_DIRECTORY mode. In his case (and mine) 
-	  mapped network drives (eg. Z: -> \\meade\net) would NOT
-	  show up in BROWSE_DIRECTORY mode if the BIF_SHAREABLE enabled.
-	  (Drive would only show up if specified as the preset filename)
-
-	o Applied Manolo's 3 suggestions from Oct 08 2008:
-
-	    > Remove the 'Default' format from BROWSE_SAVE_FILE dialog
-	      by adding kNavGenericSignature as 3rg argument of
-	      NavCreatePutFileDialog()
-
-	    > Fixed BROWSE_SAVE_FILE to not fail if file does not exist yet
-
-	    > Converted all kCFStringEncodingASCII -> kCFStringEncodingUTF8
-
-	o 4 space indent conformation
-
-0.85
------------------------------------------------------
-	o Enable options(fltk::NativeFileChooser::NEW_FOLDER) to work for Mac.
-	  fltk1 & fltk2 docs for options() updated; NEW_FOLDER flag turned green for Mac.
-	  Feature added for Mark Brevoort. Posted patch to fltk.general on 11/21/07.
-
-        o Updated the COPYING file to be LGPL (somehow a GPL license got in there)
-
-0.84 -- 10/01/2007 release
------------------------------------------------------
-	o FLTK2 SUPPORT!
-	  Merged in Frederic Hoerni's mods for fltk2 support, 
-	  converted to fltk2 style namespace.
-
-	o Makefile fix for IMGLIB from Gonzalo Garramuno (fltk.general 09/30/07)
-
-	o Incorporated Ian MacArthur's Makefile for fltk-config
-
-	o 80 column compliance
-
-	o Build: 
-	    > Tar file now extracts with version number in the directory name,
-	    > 'make tar' logic now moved into separate shell script
-
-	o Windows:
-            > Fixed memory leak with lpstrFile (alloc'ed twice)
-	    > Removed unused strfree() code in ClearOFN()
-	    > Small code formatting fixes
-
-
-0.83d -- 11/23/2006 fix release
------------------------------------------------------
-	o Linux:
-	    > Added Shane Hill's #include <sys/stat.h> to Fl_Native_File_Chooser_FLTK.cxx
-
-	o Windows:
-	    > Added OFN_NOCHANGEDIR flag to prevent GetOpenFileName() from changing the CWD
-	    > Added Andreas Sch?mann's fix for _nfilters++ to the add_filter() method
-	    > Fixed showfile() GetCurrentDirectory() call
-
-	o Copyright fixes and README.txt brought up to date
-
-
-0.83c -- 02/03/2006 fix release
------------------------------------------------------
-        o Windows: 
-	    > Fixed behavior of BROWSE_SAVE_FILE
-	    > Fixed SAVEAS_CONFIRM 
-	    > Mods to getcwd() macros in test-browser.cxx for MINGW
-	    > Fixes to test-browser.cxx for MinGW compiles (removed #ifdef VISUAL_STUDIO)
-
-	o Linux:
-	    > "Save File" now has working "Show SaveAs Confirm" dialog
-	    > "Save File" under linux wasn't letting user type in a filename
-            > 'int type()' method wasn't implemented, added _btype
-	    > Removed ifeq() cruft from Makefile.LINUX
-
-	o Applied Ian's fixes to Makefile.fltkconfig
-	o Makefile was sourcing user's ~/.cshrc, added '-f' to SHELL=/bin/csh -f
-
-0.83b -- 01/07/2006 erco: small patches from Ian
-------------------------------------------------
-	o Makefile.fltkconfig WINDOWS -> WIN32
-	o Tar forces owner/group to 0/0, fixed perms on images dir
-
-0.83a -- 01/06/2006 erco: small patches from Ian
-------------------------------------------------
-	o Makefile.fltkconfig patch
-	o Enforce correct perms on files in tar file
-
-0.83 -- 12/06/2005 erco: misc 
------------------------------------------------
-        o Windows: Added preset_file() support
-	o Linux: missing filters() method
-	o All: Added options() to API, removed macosx_*()
-	o Added options() to the API with flags:
-		o NEW_FOLDER
-		o PREVIEW
-		o SAVEAS_CONFIRM
-	o Removed macosx_*() stuff -- bad idea
-
-0.82 -- 12/05/2005 erco: misc fixes after merge
------------------------------------------------
-	o win32 filter fixes for Alessandro's 11/29 report
-	o Rellocated Macos reference links from code to REFERENCE-MAC.txt
-	o Made sure all #ifdefs use _WIN32 instead of other variants.
-	o Fixed problem with FLTK chooser not showing its icons (natevw)
-	o Added macosx_*() platform specific accessors
-
-    TODO: See ./TODO for outstanding items
-
-0.81 -- 11/28/2005 erco: linux version cleanup
-----------------------------------------------
-        o Support documented filters
-	o free/strdup -> new/delete
-	o added #ifndef at top of FL/Fl_Native_File_Chooser.H to prevent recursion
-
-0.80 -- 11/27/2005 erco+nate: code merge, cleanup
--------------------------------------------------
-	o Merge in Nathan's changes
-	o Updated docs for all changes noted here
-	o Rewrote mac's filter code to support old "*.a" and new "Desc1\t*.a\nDesc2\t*.b" syntax
-	o Changed Nathan's set_filter() -> filter_value() (consistent with FLTK's own chooser)
-	o Renamed test program to test-browser.cxx
-	o Code cleanup: variable + method naming, 80 column conformance, indents, strdup/malloc -> new
-	TODO: Linux version needs code cleanup (strdup -> new, etc)
-
-0.70 -- 08/04/05 erco: general cleanup
---------------------------------------
-
-	o Implemented Linux.
-	  This was easy -- just use Fl_File_Chooser.
-
-	o Removed references to non-existant size() method from docs;
-	  the correct method name is total_filenames()
-
-0.62 -- 02/02/2005
-------------------
-
-	o Added Ian's mods to main.cxx to use getcwd() instead of fixed path
-
-	o Added #include/#define's to support getcwd() under Windows VS
-
-0.61 -- 01/26/2005
-------------------
-	o Applied Ian MacArthur's 01/26/2005 fixes,
-	  and Makefile.fltkconfig, including tab fixes and line 90 .obj -> .o fix.
-
-	o Enabled /Wall on Windows VS7.x, and fixed all problems related to Fl_Native*
-	  (mainly, ctor type value was being ignored)
-
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/CMakeLists.txt b/Utilities/FLTK/Fl_Native_File_Chooser/CMakeLists.txt
deleted file mode 100644
index e04ae0e..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/CMakeLists.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-INCLUDE_DIRECTORIES(${SNAP_SOURCE_DIR}/Utilities/FLTK/Fl_Native_File_Chooser)
-ADD_DEFINITIONS(-DFLTK1)	
-ADD_LIBRARY(fltk_native_file_chooser Fl_Native_File_Chooser.cxx)
\ No newline at end of file
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/COPYING b/Utilities/FLTK/Fl_Native_File_Chooser/COPYING
deleted file mode 100644
index 6a587e1..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/COPYING
+++ /dev/null
@@ -1,529 +0,0 @@
-		   Fl_Native_File_Chooser License
-		   December 16, 2002
-
-The Fl_Native_File_Chooser (FNFC) library and included programs are 
-provided under the terms of the GNU Library General Public License 
-(LGPL) with the following exceptions:
-
-    1. Modifications to the FNFC configure script, config
-       header file, and makefiles by themselves to support
-       a specific platform do not constitute a modified or
-       derivative work.
-
-       The authors do request that such modifications be
-       contributed to the FNFC project - send all
-       contributions to "erco at seriss dot com".
-
-    2. Widgets that are subclassed from FNFC widgets do not
-       constitute a derivative work.
-
-    3. Static linking of applications and widgets to the
-       FNFC library does not constitute a derivative work
-       and does not require the author to provide source
-       code for the application or widget, use the shared
-       FNFC libraries, or link their applications or
-       widgets against a user-supplied version of FNFC.
-
-       If you link the application or widget to a modified
-       version of FNFC, then the changes to FNFC must be
-       provided under the terms of the LGPL in sections
-       1, 2, and 4.
-
-    4. You do not have to provide a copy of the FNFC license
-       with programs that are linked to the FNFC library, nor
-       do you have to identify the FNFC license in your
-       program or documentation as required by section 6
-       of the LGPL.
-
-       However, programs must still identify their use of FNFC.
-       The following example statement can be included in user
-       documentation to satisfy this requirement:
-
-           [program/widget] is based in part on the work of
-	   of the Fl_Native_File_Chooser project
-	   http://seriss.com/people/erco/fltk/Fl_Native_File_Chooser/
-
------------------------------------------------------------------------
-
-		  GNU LIBRARY GENERAL PUBLIC LICENSE
-			 Version 2, June 1991
-
-	  Copyright (C) 1991 Free Software Foundation, Inc.
-       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-     Everyone is permitted to copy and distribute verbatim copies
-      of this license document, but changing it is not allowed.
-
-    [This is the first released version of the library GPL.  It is
-   numbered 2 because it goes with version 2 of the ordinary GPL.]
-
-			       Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
-  This license, the Library General Public License, applies to some
-specially designated Free Software Foundation software, and to any
-other libraries whose authors decide to use it.  You can use it for
-your libraries, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if
-you distribute copies of the library, or if you modify it.
-
-  For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you.  You must make sure that they, too, receive or can get the source
-code.  If you link a program with the library, you must provide
-complete object files to the recipients so that they can relink them
-with the library, after making changes to the library and recompiling
-it.  And you must show them these terms so they know their rights.
-
-  Our method of protecting your rights has two steps: (1) copyright
-the library, and (2) offer you this license which gives you legal
-permission to copy, distribute and/or modify the library.
-
-  Also, for each distributor's protection, we want to make certain
-that everyone understands that there is no warranty for this free
-library.  If the library is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original
-version, so that any problems introduced by others will not reflect on
-the original authors' reputations.
-

-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that companies distributing free
-software will individually obtain patent licenses, thus in effect
-transforming the program into proprietary software.  To prevent this,
-we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
-  Most GNU software, including some libraries, is covered by the ordinary
-GNU General Public License, which was designed for utility programs.  This
-license, the GNU Library General Public License, applies to certain
-designated libraries.  This license is quite different from the ordinary
-one; be sure to read it in full, and don't assume that anything in it is
-the same as in the ordinary license.
-
-  The reason we have a separate public license for some libraries is that
-they blur the distinction we usually make between modifying or adding to a
-program and simply using it.  Linking a program with a library, without
-changing the library, is in some sense simply using the library, and is
-analogous to running a utility program or application program.  However, in
-a textual and legal sense, the linked executable is a combined work, a
-derivative of the original library, and the ordinary General Public License
-treats it as such.
-
-  Because of this blurred distinction, using the ordinary General
-Public License for libraries did not effectively promote software
-sharing, because most developers did not use the libraries.  We
-concluded that weaker conditions might promote sharing better.
-
-  However, unrestricted linking of non-free programs would deprive the
-users of those programs of all benefit from the free status of the
-libraries themselves.  This Library General Public License is intended to
-permit developers of non-free programs to use free libraries, while
-preserving your freedom as a user of such programs to change the free
-libraries that are incorporated in them.  (We have not seen how to achieve
-this as regards changes in header files, but we have achieved it as regards
-changes in the actual functions of the Library.)  The hope is that this
-will lead to faster development of free libraries.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.  Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library".  The
-former contains code derived from the library, while the latter only
-works together with the library.
-
-  Note that it is possible for a library to be covered by the ordinary
-General Public License rather than by this special one.
-

-		  GNU LIBRARY GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License Agreement applies to any software library which
-contains a notice placed by the copyright holder or other authorized
-party saying it may be distributed under the terms of this Library
-General Public License (also called "this License").  Each licensee is
-addressed as "you".
-
-  A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
-  The "Library", below, refers to any such software library or work
-which has been distributed under these terms.  A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language.  (Hereinafter, translation is
-included without limitation in the term "modification".)
-
-  "Source code" for a work means the preferred form of the work for
-making modifications to it.  For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
-  Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it).  Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
-  1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
-  You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-

-  2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) The modified work must itself be a software library.
-
-    b) You must cause the files modified to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    c) You must cause the whole of the work to be licensed at no
-    charge to all third parties under the terms of this License.
-
-    d) If a facility in the modified Library refers to a function or a
-    table of data to be supplied by an application program that uses
-    the facility, other than as an argument passed when the facility
-    is invoked, then you must make a good faith effort to ensure that,
-    in the event an application does not supply such function or
-    table, the facility still operates, and performs whatever part of
-    its purpose remains meaningful.
-
-    (For example, a function in a library to compute square roots has
-    a purpose that is entirely well-defined independent of the
-    application.  Therefore, Subsection 2d requires that any
-    application-supplied function or table used by this function must
-    be optional: if the application does not supply it, the square
-    root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library.  To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License.  (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.)  Do not make any other change in
-these notices.
-

-  Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
-  This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
-  4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
-  If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library".  Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
-  However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library".  The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
-  When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library.  The
-threshold for this to be true is not precisely defined by law.
-
-  If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work.  (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
-  Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-

-  6. As an exception to the Sections above, you may also compile or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
-  You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License.  You must supply a copy of this License.  If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License.  Also, you must do one
-of these things:
-
-    a) Accompany the work with the complete corresponding
-    machine-readable source code for the Library including whatever
-    changes were used in the work (which must be distributed under
-    Sections 1 and 2 above); and, if the work is an executable linked
-    with the Library, with the complete machine-readable "work that
-    uses the Library", as object code and/or source code, so that the
-    user can modify the Library and then relink to produce a modified
-    executable containing the modified Library.  (It is understood
-    that the user who changes the contents of definitions files in the
-    Library will not necessarily be able to recompile the application
-    to use the modified definitions.)
-
-    b) Accompany the work with a written offer, valid for at
-    least three years, to give the same user the materials
-    specified in Subsection 6a, above, for a charge no more
-    than the cost of performing this distribution.
-
-    c) If distribution of the work is made by offering access to copy
-    from a designated place, offer equivalent access to copy the above
-    specified materials from the same place.
-
-    d) Verify that the user has already received a copy of these
-    materials or that you have already sent this user a copy.
-
-  For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it.  However, as a special exception,
-the source code distributed need not include anything that is normally
-distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
-  It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system.  Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-

-  7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
-    a) Accompany the combined library with a copy of the same work
-    based on the Library, uncombined with any other library
-    facilities.  This must be distributed under the terms of the
-    Sections above.
-
-    b) Give prominent notice with the combined library of the fact
-    that part of it is a work based on the Library, and explaining
-    where to find the accompanying uncombined form of the same work.
-
-  8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License.  Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License.  However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-  9. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Library or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
-  10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-

-  11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded.  In such case, this License incorporates the limitation as if
-written in the body of this License.
-
-  13. The Free Software Foundation may publish revised and/or new
-versions of the Library General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation.  If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-

-  14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission.  For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this.  Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
-			    NO WARRANTY
-
-  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-

-     Appendix: How to Apply These Terms to Your New Libraries
-
-  If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change.  You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
-  To apply these terms, attach the following notices to the library.  It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the library's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
-
-    This library 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
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the
-  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
-  <signature of Ty Coon>, 1 April 1990
-  Ty Coon, President of Vice
-
-That's all there is to it!
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/CREDITS b/Utilities/FLTK/Fl_Native_File_Chooser/CREDITS
deleted file mode 100644
index bbaed87..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/CREDITS
+++ /dev/null
@@ -1,13 +0,0 @@
-Author
-------------
-Greg Ercolano      -- initial version for mac + win32, code maintainer
-
-Contrubutors
-------------
-Ian MacArthur      -- various fixes, additions, Makefile.fltkconfig
-Nathan Vander Wilt -- filter code for WIN32 and Mac, FLTK chooser
-Boris Mayer        -- various debugging
-Frederic Hoerni    -- fltk2 port
-Walter Garms       -- Recommended WIN32 fixes for network shares
-Manolo Gouy        -- various MAC fixes; utf8, kNavGenericSignature
-Gary Hui Zhang     -- snow leopard mods: FsSpec -> FsRef
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser.H b/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser.H
deleted file mode 100644
index 88c0acb..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser.H
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// Fl_Native_File_Chooser.H -- FLTK native OS file chooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-
-#ifndef FL_NATIVE_FILE_CHOOSER_H
-#define FL_NATIVE_FILE_CHOOSER_H
-
-// Use Windows' chooser
-#ifdef _WIN32
-#include <FL/Fl_Native_File_Chooser_WIN32.H>
-#endif
-
-// Use Apple's chooser
-#ifdef __APPLE__
-#include <FL/Fl_Native_File_Chooser_MAC.H>
-#endif
-
-// All else falls back to FLTK's own chooser
-#if ! defined(__APPLE__) && !defined(_WIN32)
-#include <FL/Fl_Native_File_Chooser_FLTK.H>
-#endif
-
-#endif /*FL_NATIVE_FILE_CHOOSER_H*/
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser_FLTK.H b/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser_FLTK.H
deleted file mode 100644
index 46fa2ed..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser_FLTK.H
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-// Fl_Native_File_Chooser_DEFAULT.H -- FLTK native OS file chooser widget
-//
-// Copyright 2005 by Nathan Vander Wilt.
-// March 2005 - wrapper around Fl_File_Chooser
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-
-#include <FL/Fl_File_Chooser.H>
-#include <FL/Fl_File_Icon.H>
-#include <string.h>
-
-class Fl_Native_File_Chooser {
-public:
-    enum Type {
-	BROWSE_FILE = 0,
-	BROWSE_DIRECTORY,
-	BROWSE_MULTI_FILE,
-	BROWSE_MULTI_DIRECTORY,
-	BROWSE_SAVE_FILE,
-	BROWSE_SAVE_DIRECTORY
-    };
-    enum Option {
-        NO_OPTIONS     = 0x0000,	// no options enabled
-	SAVEAS_CONFIRM = 0x0001,	// Show native 'Save As' overwrite
-					// confirm dialog (if supported)
-	NEW_FOLDER     = 0x0002,	// Show 'New Folder' icon
-					// (if supported)
-	PREVIEW        = 0x0004		// enable preview mode
-    };
-private:
-    int   _btype;			// kind-of browser to show()
-    int   _options;			// general options
-    char *_filter;			// user supplied filter
-    char *_parsedfilt;			// parsed filter
-    int   _filtvalue;			// selected filter
-    char *_preset_file;
-    char *_prevvalue;			// Returned filename
-    char *_directory;
-    char *_errmsg;			// error message
-    Fl_File_Chooser *file_chooser;
-
-    int exist_dialog() {
-	return(fl_choice("File exists. Are you sure you want to overwrite?", 
-			 "Cancel", "   OK   ", NULL));
-    }
-    void load_system_icons() {
-	Fl_File_Icon::load_system_icons();
-    }
-
-    int _nfilters;
-
-    // Private methods
-    void errmsg(const char *msg);
-    int type_fl_file(int);
-    void parse_filter();
-    void keeplocation();
-
-public:
-    Fl_Native_File_Chooser(int val=BROWSE_FILE);
-    ~Fl_Native_File_Chooser();
-
-    // Public methods
-    void type(int);
-    int type() const;
-    void options(int);
-    int options() const;
-    int count() const;
-    const char *filename() const;
-    const char *filename(int i) const;
-    void directory(const char *val);
-    const char *directory() const;
-    void title(const char *);
-    const char* title() const;
-    const char *filter() const;
-    void filter(const char *);
-    int filters() const { return(_nfilters); }
-    void filter_value(int i);
-    int filter_value() const;
-    void preset_file(const char*);
-    const char* preset_file() const;
-    const char *errmsg() const;
-    int show();
-};
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser_MAC.H b/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser_MAC.H
deleted file mode 100644
index e07e08c..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser_MAC.H
+++ /dev/null
@@ -1,138 +0,0 @@
-//
-// Fl_Native_File_Chooser_MAC.H -- FLTK native OS file chooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-//      10        20        30        40        50        60        70
-//       |         |         |         |         |         |         |
-// 4567890123456789012345678901234567890123456789012345678901234567890123456789
-
-// OSX-SPECIFIC NATIVE BROWSER
-#ifdef __APPLE_CC__
-#include <Carbon/Carbon.h>
-#else
-#include <Carbon.h>
-#endif
-
-#include <FL/filename.H>
-#define MAXFILTERS	80
-
-class Fl_Native_File_Chooser {
-public:
-    enum Type {
-	BROWSE_FILE = 0,
-	BROWSE_DIRECTORY,
-	BROWSE_MULTI_FILE,
-	BROWSE_MULTI_DIRECTORY,
-	BROWSE_SAVE_FILE,
-	BROWSE_SAVE_DIRECTORY
-    };
-    enum Option {
-        NO_OPTIONS     = 0x0000,	// no options enabled
-	SAVEAS_CONFIRM = 0x0001,	// Show native 'Save As' overwrite
-					// confirm dialog (if supported)
-	NEW_FOLDER     = 0x0002,	// Show 'New Folder' icon
-					// (if supported)
-	PREVIEW        = 0x0004,	// enable preview mode
-    };
-protected:
-    NavDialogCreationOptions _opts;	// file navigation options
-private:
-    int             _btype;		// kind-of browser to show()
-    int             _options;		// general options
-    NavDialogRef    _ref;		// file navigation reference
-    NavActionState  _keepstate;		// various chooser options
-    NavMenuItemSpec _tempitem;   	// Popup menu selection
-    char          **_pathnames;		// array of pathnames
-    int             _tpathnames;	// total pathnames
-    char           *_directory;		// default pathname to use
-    char           *_title;		// title for window
-    char           *_preset_file;	// the 'save as' filename
-
-    char           *_filter;		// user-side search filter, eg:
-					// C Files\t*.[ch]\nText Files\t*.txt"
-
-    char           *_filt_names;	// filter names (tab delimited)
-    					// eg. "C Files\tText Files"
-
-    char           *_filt_patt[MAXFILTERS];
-                                        // array of filter patterns, eg:
-					//     _filt_patt[0]="*.{cxx,h}"
-					//     _filt_patt[1]="*.txt"
-
-    int             _filt_total;	// parse_filter() # of filters loaded
-    int             _filt_value;	// index of the selected filter
-    char           *_errmsg;		// error message
-
-    // PRIVATE CLASS TO HANDLE NAVIGATION DIALOG REPLY STRUCT
-    //     Class-ified, mainly to ensure proper cleanup.
-    //
-    class NavReply {
-        int _valid_reply;
-	NavReplyRecord _reply;
-    public:
-        NavReply();
-	~NavReply();
-	int get_reply(NavDialogRef& ref);
-	int get_saveas_basename(char *s, int slen);
-	int get_dirname(char *s, int slen);
-	int get_pathnames(char **&pathnames, int& tpathnames);
-    };
-
-    // Private methods
-    void errmsg(const char *msg);
-    void clear_pathnames();
-    void set_single_pathname(const char *s);
-    int get_saveas_basename(NavDialogRef& ref);
-    int get_pathnames(NavDialogRef& ref);
-    static void event_handler(NavEventCallbackMessage callBackSelector, 
-    					     NavCBRecPtr cbparm, void *data);
-
-    void clear_filters();
-    void add_filter(const char *, const char *);
-    void parse_filter(const char *from);
-    static Boolean filter_proc_cb(AEDesc *, void *, void *, NavFilterModes);
-    Boolean filter_proc_cb2(AEDesc*, void*, void*, NavFilterModes);
-    int post();
-    
-public:
-    Fl_Native_File_Chooser(int val = BROWSE_FILE);
-    ~Fl_Native_File_Chooser();
-
-    // Public methods
-    void type(int);
-    int type() const;
-    void options(int);
-    int options() const;
-    int count() const;
-    const char *filename() const;
-    const char *filename(int i) const;
-    void directory(const char *);
-    const char *directory() const;
-    void title(const char *);
-    const char *title() const;
-    const char *filter() const;
-    void filter(const char *);
-    void filter_value(int i) { _filt_value = i; }
-    int filter_value() { return(_filt_value); }
-    int filters() { return(_filt_total); }
-    void preset_file(const char *);
-    const char *preset_file();
-    const char *errmsg() const;
-    int show();
-};
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser_WIN32.H b/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser_WIN32.H
deleted file mode 100644
index 889b484..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/FL/Fl_Native_File_Chooser_WIN32.H
+++ /dev/null
@@ -1,108 +0,0 @@
-//
-// Fl_Native_File_Chooser_WINDOWS.H -- FLTK native OS file chooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-// April 2005 - API changes, improved filter processing by Nathan Vander Wilt
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-
-// #define _WIN32_WINNT	0x0501	// needed for OPENFILENAME's 'FlagsEx'
-#include <stdio.h>
-#include <stdlib.h>		// malloc
-#include <windows.h>
-#include <commdlg.h>		// OPENFILENAME, GetOpenFileName()
-#include <shlobj.h>		// BROWSEINFO, SHBrowseForFolder()
-
-class Fl_Native_File_Chooser {
-public:
-    enum Type {
-	BROWSE_FILE = 0,
-        BROWSE_DIRECTORY,
-	BROWSE_MULTI_FILE,
-	BROWSE_MULTI_DIRECTORY,
-	BROWSE_SAVE_FILE,
-	BROWSE_SAVE_DIRECTORY
-    };
-    enum Option {
-        NO_OPTIONS     = 0x0000,	// no options enabled
-	SAVEAS_CONFIRM = 0x0001,	// Show native 'Save As' overwrite
-					// confirm dialog (if supported)
-	NEW_FOLDER     = 0x0002,	// Show 'New Folder' icon
-					// (if supported)
-	PREVIEW        = 0x0004,	// enable preview mode
-    };
-private:
-    int  _btype;		// kind-of browser to show()
-    int  _options;		// general options
-    OPENFILENAME _ofn;		// GetOpenFileName() & GetSaveFileName() struct
-    BROWSEINFO   _binf;		// SHBrowseForFolder() struct
-    char  **_pathnames;		// array of pathnames
-    int     _tpathnames;	// total pathnames
-    char   *_directory;		// default pathname to use
-    char   *_title;		// title for window
-    char   *_filter;		// user-side search filter
-    char   *_parsedfilt;	// filter parsed for Windows dialog
-    int     _nfilters;		// number of filters parse_filter counted
-    char   *_preset_file;	// the file to preselect
-    char   *_errmsg;		// error message
-
-    // Private methods
-    void errmsg(const char *msg);
-
-    void clear_pathnames();
-    void set_single_pathname(const char *s);
-    void add_pathname(const char *s);
-
-    void FreePIDL(ITEMIDLIST *pidl);
-    void ClearOFN();
-    void ClearBINF();
-    void Win2Unix(char *s);
-    void Unix2Win(char *s);
-    int showfile();
-    static int CALLBACK Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data);
-    int showdir();
-
-    void parse_filter(const char *);
-    void clear_filters();
-    void add_filter(const char *, const char *);
-
-public:
-    Fl_Native_File_Chooser(int val = BROWSE_FILE);
-    ~Fl_Native_File_Chooser();
-
-    // Public methods
-    void type(int val);
-    int type() const;
-    void options(int);
-    int options() const;
-    int count() const;
-    const char *filename() const;
-    const char *filename(int i) const;
-    void directory(const char *val);
-    const char *directory() const;
-    void title(const char *val);
-    const char *title() const;
-    const char *filter() const;
-    void filter(const char *val);
-    int filters() const { return _nfilters; }
-    void filter_value(int i);
-    int filter_value() const;
-    void preset_file(const char *);
-    const char *preset_file() const;
-    const char *errmsg() const;
-    int show();
-};
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser.cxx b/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser.cxx
deleted file mode 100644
index 5c851cb..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser.cxx
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// Fl_Native_File_Chooser.cxx -- FLTK native OS file chooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-
-// Use Windows' chooser
-#ifdef _WIN32
-#include "Fl_Native_File_Chooser_WIN32.cxx"
-#endif
-
-// Use Apple's chooser
-#ifdef __APPLE__
-#include "Fl_Native_File_Chooser_MAC.cxx"
-#endif
-
-// All else falls back to FLTK's own chooser
-#if ! defined(__APPLE__) && !defined(_WIN32)
-#include "Fl_Native_File_Chooser_FLTK.cxx"
-#endif
-
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser_FLTK.cxx b/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser_FLTK.cxx
deleted file mode 100644
index 0244c53..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser_FLTK.cxx
+++ /dev/null
@@ -1,374 +0,0 @@
-//
-// Fl_Native_File_Chooser_FLTK.cxx -- FLTK native OS file chooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-// API changes + filter improvements by Nathan Vander Wilt 2005
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-// Please keep code 80 column compliant.
-//
-//      10        20        30        40        50        60        70
-//       |         |         |         |         |         |         |
-// 4567890123456789012345678901234567890123456789012345678901234567890123456789
-//
-
-#ifdef FLTK1
-//
-// FLTK1
-//
-#include <FL/Fl_Native_File_Chooser.H>
-#define FNFC_CLASS Fl_Native_File_Chooser
-#define FNFC_CTOR  Fl_Native_File_Chooser
-#define FLTK_CHOOSER_SINGLE    Fl_File_Chooser::SINGLE
-#define FLTK_CHOOSER_DIRECTORY Fl_File_Chooser::DIRECTORY
-#define FLTK_CHOOSER_MULTI     Fl_File_Chooser::MULTI
-#define FLTK_CHOOSER_CREATE    Fl_File_Chooser::CREATE
-#else
-//
-// FLTK2
-//
-#include <fltk/NativeFileChooser.h>
-#include <fltk/run.h>
-#define FNFC_CTOR  NativeFileChooser
-#define FNFC_CLASS fltk::FNFC_CTOR
-#define FLTK_CHOOSER_SINGLE    fltk::FileChooser::SINGLE
-#define FLTK_CHOOSER_DIRECTORY fltk::FileChooser::DIRECTORY
-#define FLTK_CHOOSER_MULTI     fltk::FileChooser::MULTI
-#define FLTK_CHOOSER_CREATE    fltk::FileChooser::CREATE
-#endif
-
-#include "common.cxx"
-#include <sys/stat.h>
-
-// CTOR
-FNFC_CLASS::FNFC_CTOR(int val) {
-    static int init = 0;		// 'first time' initialize flag
-    if ( init == 0 ) {
-        // Initialize when instanced for first time
-	load_system_icons();
-	init = 1;
-    }
-    _btype       = val;
-    _options     = NO_OPTIONS;
-    _filter      = NULL;
-    _filtvalue   = 0;
-    _parsedfilt  = NULL;
-    _preset_file = NULL;
-    _prevvalue   = NULL;
-    _directory   = NULL;
-    _errmsg      = NULL;
-#ifdef FLTK1
-    file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL);
-#else
-    file_chooser = new fltk::FileChooser(NULL, NULL, 0, NULL);
-#endif
-    type(val);		// do this after file_chooser created
-    _nfilters    = 0;
-}
-
-// DTOR
-FNFC_CLASS::~FNFC_CTOR() {
-    delete file_chooser;
-    _filter      = strfree(_filter);
-    _parsedfilt  = strfree(_parsedfilt);
-    _preset_file = strfree(_preset_file);
-    _prevvalue   = strfree(_prevvalue);
-    _directory   = strfree(_directory);
-    _errmsg      = strfree(_errmsg);
-}
-
-// PRIVATE: SET ERROR MESSAGE
-void FNFC_CLASS::errmsg(const char *msg) {
-    _errmsg = strfree(_errmsg);
-    _errmsg = strnew(msg);
-}
-
-// PRIVATE: translate Native types to Fl_File_Chooser types
-int FNFC_CLASS::type_fl_file(int val) {
-    switch (val) {
-        case BROWSE_FILE:
-	    return(FLTK_CHOOSER_SINGLE);
-        case BROWSE_DIRECTORY:
-	    return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_DIRECTORY);
-        case BROWSE_MULTI_FILE:
-	    return(FLTK_CHOOSER_MULTI);
-        case BROWSE_MULTI_DIRECTORY:
-	    return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI);
-        case BROWSE_SAVE_FILE:
-	    return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_CREATE);
-        case BROWSE_SAVE_DIRECTORY:
-	    return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI | FLTK_CHOOSER_CREATE);
-        default:
-	    return(FLTK_CHOOSER_SINGLE);
-    }
-}
-
-void FNFC_CLASS::type(int val) {
-    _btype = val;
-    file_chooser->type(type_fl_file(val));
-}
-
-int FNFC_CLASS::type() const {
-    return(_btype);
-}
-
-// SET OPTIONS
-void FNFC_CLASS::options(int val) {
-    _options = val;
-}
-
-// GET OPTIONS
-int FNFC_CLASS::options() const {
-    return(_options);
-}
-
-// Show chooser, blocks until done.
-// RETURNS:
-//    0 - user picked a file
-//    1 - user cancelled
-//   -1 - failed; errmsg() has reason
-//
-int FNFC_CLASS::show() {
-    // FILTER
-    if ( _parsedfilt ) {
-        file_chooser->filter(_parsedfilt);
-    }
-
-    // FILTER VALUE
-    //     Set this /after/ setting the filter
-    //
-    file_chooser->filter_value(_filtvalue);
-
-    // DIRECTORY
-    if ( _directory && _directory[0] ) {
-        file_chooser->directory(_directory);
-    } else {
-        file_chooser->directory(_prevvalue);
-    }
-
-    // PRESET FILE
-    if ( _preset_file ) {
-        file_chooser->value(_preset_file);
-    }
-
-    // OPTIONS: PREVIEW
-    file_chooser->preview( (options() & PREVIEW) ? 1 : 0);
-
-    // OPTIONS: NEW FOLDER
-    if ( options() & NEW_FOLDER )
-        file_chooser->type(file_chooser->type() |
-	                   FLTK_CHOOSER_CREATE);		// on
-
-    // SHOW
-    file_chooser->show();
-
-#ifdef FLTK1
-    // FLTK1: BLOCK WHILE BROWSER SHOWN
-    while ( file_chooser->shown() ) {
-        Fl::wait();
-    }
-#else
-    // FLTK2: BLOCK WHILE BROWSER SHOWN
-    while ( file_chooser->visible() ) {
-        fltk::wait();
-    }
-#endif
-
-    if ( file_chooser->value() && file_chooser->value()[0] ) {
-        _prevvalue = strfree(_prevvalue);
-	_prevvalue = strnew(file_chooser->value());
-	_filtvalue = file_chooser->filter_value();	// update filter value
-
-	// HANDLE SHOWING 'SaveAs' CONFIRM
-	if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) {
-	    struct stat buf;
-	    if ( stat(file_chooser->value(), &buf) != -1 ) {
-		if ( buf.st_mode & S_IFREG ) {		// Regular file + exists?
-		     if ( exist_dialog() == 0 ) {
-		         return(1);
-		     }
-		}
-	    }
-	}
-    }
-
-    if ( file_chooser->count() ) return(0);
-    else return(1);
-}
-
-// RETURN ERROR MESSAGE
-const char *FNFC_CLASS::errmsg() const {
-    return(_errmsg ? _errmsg : "No error");
-}
-
-// GET FILENAME
-const char* FNFC_CLASS::filename() const {
-    if ( file_chooser->count() > 0 ) return(file_chooser->value());
-    return("");
-}
-
-// GET FILENAME FROM LIST OF FILENAMES
-const char* FNFC_CLASS::filename(int i) const {
-    if ( i < file_chooser->count() )
-        return(file_chooser->value(i+1));	// convert fltk 1 based to our 0 based
-    return("");
-}
-
-// SET TITLE
-//     Can be NULL if no title desired.
-//
-void FNFC_CLASS::title(const char *val) {
-    file_chooser->label(val);
-}
-
-// GET TITLE
-//    Can return NULL if none set.
-//
-const char *FNFC_CLASS::title() const {
-    return(file_chooser->label());
-}
-
-// SET FILTER
-//     Can be NULL if no filter needed
-//
-void FNFC_CLASS::filter(const char *val) {
-    _filter = strfree(_filter);
-    _filter = strnew(val);
-    parse_filter();
-}
-
-// GET FILTER
-const char *FNFC_CLASS::filter() const {
-    return(_filter);
-}
-
-// SET SELECTED FILTER
-void FNFC_CLASS::filter_value(int val) {
-    _filtvalue = val;
-}
-
-// RETURN SELECTED FILTER
-int FNFC_CLASS::filter_value() const {
-    return(_filtvalue);
-}
-
-// GET TOTAL FILENAMES CHOSEN
-int FNFC_CLASS::count() const {
-    return(file_chooser->count());
-}
-
-// PRESET PATHNAME
-//     Can be NULL if no preset is desired.
-//
-void FNFC_CLASS::directory(const char *val) {
-    _directory = strfree(_directory);
-    _directory = strnew(val);
-}
-
-// GET PRESET PATHNAME
-//    Can return NULL if none set.
-//
-const char *FNFC_CLASS::directory() const {
-    return(_directory);
-}
-
-// Convert our filter format to fltk's chooser format
-//     FROM                                     TO (FLTK)
-//     -------------------------                --------------------------
-//     "*.cxx"                                  "*.cxx Files(*.cxx)"
-//     "C Files\t*.{cxx,h}"                     "C Files(*.{cxx,h})"
-//     "C Files\t*.{cxx,h}\nText Files\t*.txt"  "C Files(*.{cxx,h})\tText Files(*.txt)"
-//
-//     Returns a modified version of the filter that the caller is responsible
-//     for freeing with strfree().
-//
-void FNFC_CLASS::parse_filter() {
-    _parsedfilt = strfree(_parsedfilt);	// clear previous parsed filter (if any)
-    _nfilters = 0;
-    char *in = _filter;
-    if ( !in ) return;
-
-    int has_name = strchr(in, '\t') ? 1 : 0;
-
-    char mode = has_name ? 'n' : 'w';	// parse mode: n=title, w=wildcard
-    char wildcard[1024] = "";		// parsed wildcard
-    char name[1024] = "";
-
-    // Parse filter user specified
-    for ( ; 1; in++ ) {
-
-        /*** DEBUG
-        printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n",
-	                    *in, mode,     name,     wildcard);
-	***/
-
-        switch (*in) {
-	    // FINISHED PARSING NAME?
-	    case '\t':
-	        if ( mode != 'n' ) goto regchar;
-		mode = 'w';
-		break;
-
-	    // ESCAPE NEXT CHAR
-	    case '\\':
-	        ++in;
-		goto regchar;
-
-	    // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
-	    case '\r':
-	    case '\n':
-	    case '\0':
-		// APPEND NEW FILTER TO LIST
-		if ( wildcard[0] ) {
-		    // OUT: "name(wild)\tname(wild)"
-		    char comp[2048];
-		    sprintf(comp, "%s%.511s(%.511s)", ((_parsedfilt)?"\t":""),
-		    				      name, wildcard);
-		    _parsedfilt = strapp(_parsedfilt, comp);
-		    _nfilters++;
-		    //DEBUG printf("DEBUG: PARSED FILT NOW <%s>\n", _parsedfilt);
-		}
-		// RESET
-		wildcard[0] = name[0] = '\0';
-		mode = strchr(in, '\t') ? 'n' : 'w';
-		// DONE?
-		if ( *in == '\0' ) return;	// done
-		else continue;			// not done yet, more filters
-
-	    // Parse all other chars
-	    default:				// handle all non-special chars
-	    regchar:				// handle regular char
-                switch ( mode ) {
-	            case 'n': chrcat(name, *in);     continue;
-	            case 'w': chrcat(wildcard, *in); continue;
-	        }
-		break;
-	}
-    }
-    //NOTREACHED
-}
-
-// SET PRESET FILENAME
-void FNFC_CLASS::preset_file(const char* val) {
-    _preset_file = strfree(_preset_file);
-    _preset_file = strnew(val);
-}
-
-// GET PRESET FILENAME
-const char* FNFC_CLASS::preset_file() const {
-    return(_preset_file);
-}
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser_MAC.cxx b/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser_MAC.cxx
deleted file mode 100644
index 007a4a6..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser_MAC.cxx
+++ /dev/null
@@ -1,867 +0,0 @@
-//
-// Fl_Native_File_Chooser_MAC.cxx -- FLTK native OS file chooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-// FLTK2/MAC port by Greg Ercolano 2007.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-// Please keep code 80 column compliant.
-//
-//      10        20        30        40        50        60        70
-//       |         |         |         |         |         |         |
-// 4567890123456789012345678901234567890123456789012345678901234567890123456789
-//
-// TODO:
-//	o When doing 'open file', only dir is preset, not filename.
-//        Possibly 'preset_file' could be used to select the filename.
-//
-#include "common.cxx"		// strnew/strfree/strapp/chrcat
-#include <libgen.h>		// dirname(3)
-#include <sys/types.h>		// stat(2)
-#include <sys/stat.h>		// stat(2)
-
-
-#ifdef FLTK1
-//
-// FLTK1
-//
-#include <FL/Fl.H>
-#include <FL/Fl_Native_File_Chooser.H>
-#include <FL/filename.H>
-#define FNFC_CLASS Fl_Native_File_Chooser
-#define FNFC_CTOR  Fl_Native_File_Chooser
-#else
-//
-// FLTK2
-//
-#include <fltk/NativeFileChooser.h>
-#include <fltk/run.h>
-#include <fltk/filename.h>
-#define FNFC_CTOR  NativeFileChooser
-#define FNFC_CLASS fltk::FNFC_CTOR
-#define fl_filename_match filename_match	// fltk1 name -> fltk2 name
-#define fl_filename_isdir filename_isdir	// fltk1 name -> fltk2 name
-#endif
-
-// TRY TO CONVERT AN AEDesc TO AN FSRef
-//     As per Apple Technical Q&A QA1274
-//     eg: http://developer.apple.com/qa/qa2001/qa1274.html
-//     Returns 'noErr' if OK, or an 'OSX result code' on error.
-//
-static int AEDescToFSRef(const AEDesc* desc, FSRef* fsref) {
-    OSStatus err = noErr;
-    AEDesc coerceDesc;
-    // If AEDesc isn't already an FSRef, convert it to one
-    if ( desc->descriptorType != typeFSRef ) {
-	if ( ( err = AECoerceDesc(desc, typeFSRef, &coerceDesc) ) == noErr ) {
-	    // Get FSRef out of AEDesc
-	    err = AEGetDescData(&coerceDesc, fsref, sizeof(FSRef));
-	    AEDisposeDesc(&coerceDesc);
-	}
-    } else {
-	err = AEGetDescData(desc, fsref, sizeof(FSRef));
-    }
-    return( err );
-}
-
-// NAVREPLY: CTOR
-FNFC_CLASS::NavReply::NavReply() {
-    _valid_reply = 0;
-}
-
-// NAVREPLY: DTOR
-FNFC_CLASS::NavReply::~NavReply() {
-    if ( _valid_reply ) {
-	NavDisposeReply(&_reply);
-    }
-}
-
-// GET REPLY FROM THE NAV* DIALOG
-int FNFC_CLASS::NavReply::get_reply(NavDialogRef& ref) {
-    if ( _valid_reply ) {
-	NavDisposeReply(&_reply);	// dispose of previous
-	_valid_reply = 0;
-    }
-    if ( ref == NULL || NavDialogGetReply(ref, &_reply) != noErr ) {
-	return(-1);
-    }
-    _valid_reply = 1;
-    return(0);
-}
-
-// RETURN THE BASENAME USER WANTS TO 'Save As'
-int FNFC_CLASS::NavReply::get_saveas_basename(char *s, int slen) {
-    if (CFStringGetCString(_reply.saveFileName, s, slen-1, 
-                           kCFStringEncodingUTF8) == false) {
-	s[0] = '\0';
-	return(-1);
-    }
-    return(0);
-}
-
-// RETURN THE DIRECTORY NAME
-//    Returns 0 on success, -1 on error.
-//
-int FNFC_CLASS::NavReply::get_dirname(char *s, int slen) {
-    FSRef fsref;
-    if ( AEDescToFSRef(&_reply.selection, &fsref) != noErr ) {
-	// Conversion failed? Return empty name
-	s[0] = 0;
-	return(-1);
-    }
-    FSRefMakePath(&fsref, (UInt8 *)s, slen);
-    return(0);
-}
-
-// RETURN MULTIPLE DIRECTORIES
-//     Returns: 0 on success with pathnames[] containing pathnames selected,
-//             -1 on error
-//
-int FNFC_CLASS::NavReply::get_pathnames(char **&pathnames, int& tpathnames) {
-    // How many items selected?
-    long count = 0;
-    if ( AECountItems(&_reply.selection, &count) != noErr ) {
-        return(-1);
-    }
-
-    // Allocate space for that many pathnames
-    pathnames = new char*[count];
-    memset((void*)pathnames, 0, count*sizeof(char*));
-    tpathnames = count;
-
-    // Walk list of pathnames selected
-    for (short index=1; index<=count; index++) {
-	AEKeyword keyWord;
-	AEDesc    desc;
-	if (AEGetNthDesc(&_reply.selection, index, typeFSRef, &keyWord, 
-	                 &desc) != noErr) {
-	    pathnames[index-1] = strnew("");
-	    continue;
-	}
-	FSRef fsref;
-	if (AEGetDescData(&desc, &fsref, sizeof(FSRef)) != noErr ) {
-	    pathnames[index-1] = strnew("");
-	    continue;
-	}
-	char s[4096];
-	FSRefMakePath(&fsref, (UInt8 *)s, sizeof(s)-1);
-	pathnames[index-1] = strnew(s);
-	AEDisposeDesc(&desc);
-    }
-    return(0);
-}
-
-// FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS
-void FNFC_CLASS::clear_pathnames() {
-    if ( _pathnames ) {
-	while ( --_tpathnames >= 0 ) {
-	    _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]);
-	}
-	delete [] _pathnames;
-	_pathnames = NULL;
-    }
-    _tpathnames = 0;
-}
-
-// SET A SINGLE PATHNAME
-void FNFC_CLASS::set_single_pathname(const char *s) {
-    clear_pathnames();
-    _pathnames = new char*[1];
-    _pathnames[0] = strnew(s);
-    _tpathnames = 1;
-}
-
-// GET THE 'Save As' FILENAME
-//    Returns -1 on error, errmsg() has reason, filename == "".
-//             0 if OK, filename() has filename chosen.
-//
-int FNFC_CLASS::get_saveas_basename(NavDialogRef& ref) {
-    if ( ref == NULL ) {
-	errmsg("get_saveas_basename: ref is NULL");
-	return(-1);
-    }
-    NavReply reply;
-    OSStatus err;
-    if ((err = reply.get_reply(ref)) != noErr ) {
-	errmsg("NavReply::get_reply() failed");
-	clear_pathnames();
-	return(-1);
-    }
-
-    char pathname[4096] = "";
-    // Directory name..
-    //    -2 leaves room to append '/'
-    //
-    if ( reply.get_dirname(pathname, sizeof(pathname)-2) < 0 ) {
-	clear_pathnames();
-	errmsg("NavReply::get_dirname() failed");
-	return(-1);
-    }
-    // Append '/'
-    int len = strlen(pathname);
-    pathname[len++] = '/';
-    pathname[len] = '\0';
-    // Basename..
-    if ( reply.get_saveas_basename(pathname+len, sizeof(pathname)-len) < 0 ) {
-	clear_pathnames();
-	errmsg("NavReply::get_saveas_basename() failed");
-	return(-1);
-    }
-    set_single_pathname(pathname);
-    return(0);
-}
-
-// GET (POTENTIALLY) MULTIPLE FILENAMES
-//     Returns:
-//         -1 -- error, errmsg() has reason, filename == ""
-//          0 -- OK, pathnames()/filename() has pathname(s) chosen
-//
-int FNFC_CLASS::get_pathnames(NavDialogRef& ref) {
-    if ( ref == NULL ) {
-	errmsg("get_saveas_basename: ref is NULL");
-	return(-1);
-    }
-    NavReply reply;
-    OSStatus err;
-    if ((err = reply.get_reply(ref)) != noErr ) { 
-	errmsg("NavReply::get_reply() failed");
-	clear_pathnames();
-	return(-1);
-    }
-    // First, clear pathnames array of any previous contents
-    clear_pathnames();
-    if ( reply.get_pathnames(_pathnames, _tpathnames) < 0 ) {
-	clear_pathnames();
-	errmsg("NavReply::get_dirname() failed");
-	return(-1);
-    }
-    return(0);
-}
-
-// IS PATHNAME A DIRECTORY?
-//    1 - path is a dir
-//    0 - path not a dir or error
-//
-static int IsDir(const char *pathname) {
-    struct stat buf;
-    if ( stat(pathname, &buf) != -1 ) {
-	if ( buf.st_mode & S_IFDIR ) return(1);
-    }
-    return(0);
-}
-
-// PRESELECT PATHNAME IN BROWSER
-static void PreselectPathname(NavCBRecPtr cbparm, const char *path) {
-    // XXX: path must be a dir, or kNavCtlSetLocation fails with -50.
-    //      Why, I don't know. Let me know with a bug report. -erco
-    //
-    if ( ! IsDir(path) ) {
-	path = dirname(const_cast<char *>(path));
-    }
-    OSStatus err;
-    FSRef fsref;
-    err = FSPathMakeRef((const UInt8*)path, &fsref, NULL);
-    if ( err != noErr) {
-	fprintf(stderr, "FSPathMakeRef(%s) failed: err=%d\n", path, (int)err);
-	return;
-    }
-    AEDesc desc;
-    err = AECreateDesc(typeFSRef, &fsref, sizeof(FSRef), &desc);
-    if ( err != noErr) {
-	fprintf(stderr, "AECreateDesc() failed: err=%d\n", (int)err);
-    }
-    err = NavCustomControl(cbparm->context, kNavCtlSetLocation, &desc);
-    if ( err != noErr) {
-	fprintf(stderr, "NavCustomControl() failed: err=%d\n", (int)err);
-    }
-    AEDisposeDesc(&desc);
-}
-
-// NAV CALLBACK EVENT HANDLER
-void FNFC_CLASS::event_handler(NavEventCallbackMessage callBackSelector, 
-			       NavCBRecPtr cbparm,
-			       void *data) {
-    FNFC_CLASS *nfb = (FNFC_CLASS*)data;
-    switch (callBackSelector) {
-	case kNavCBStart:
-	{
-	    if ( nfb->directory() ) {				// dir specified?
-	        PreselectPathname(cbparm, nfb->directory());	// use it first
-	    } else if ( nfb->preset_file() ) {			// file specified?
-	        PreselectPathname(cbparm, nfb->preset_file());	// use if no dir
-	    }
-	    if ( nfb->_btype == BROWSE_SAVE_FILE && nfb->preset_file() ) {
-		CFStringRef namestr = 
-		    CFStringCreateWithCString(NULL,
-					      nfb->preset_file(),
-					      kCFStringEncodingUTF8);
-		NavDialogSetSaveFileName(cbparm->context, namestr);
-		CFRelease(namestr);
-	    }
-	    NavCustomControl(cbparm->context,
-			     kNavCtlSetActionState,
-			     &nfb->_keepstate);
-	    // Select the right filter in pop-up menu
-	    if ( nfb->_filt_value == nfb->_filt_total ) {
-		// Select All Documents
-		NavPopupMenuItem kAll = kNavAllFiles;
-		NavCustomControl(cbparm->context, kNavCtlSelectAllType, &kAll);
-	    } else if (nfb->_filt_value < nfb->_filt_total) {
-		// Select custom filter
-		nfb->_tempitem.version = kNavMenuItemSpecVersion;
-		nfb->_tempitem.menuCreator = 'extn';
-		nfb->_tempitem.menuType = nfb->_filt_value;
-		*nfb->_tempitem.menuItemName = '\0';	// needed on 10.3+
-		NavCustomControl(cbparm->context,
-				kNavCtlSelectCustomType,
-				&(nfb->_tempitem));
-	    }
-	    break;
-	}
-	case kNavCBPopupMenuSelect:
-	{
-	    NavMenuItemSpecPtr ptr;
-	    // they really buried this one!
-	    ptr = (NavMenuItemSpecPtr)cbparm->eventData.eventDataParms.param;
-	    if ( ptr->menuCreator ) {
-		// Gets index to filter ( menuCreator = 'extn' )
-		nfb->_filt_value = ptr->menuType;
-	    } else {
-		// All docs filter selected ( menuCreator = '\0\0\0\0' )
-		nfb->_filt_value = nfb->_filt_total;
-	    }
-	    break;
-	}
-	case kNavCBSelectEntry:
-	{
-	    NavActionState astate;
-	    switch ( nfb->_btype ) {
-		// These don't need selection override
-		case BROWSE_MULTI_FILE:
-		case BROWSE_MULTI_DIRECTORY:
-		case BROWSE_SAVE_FILE:
-		{
-		    break;
-		}
-
-		// These need to allow only one item, so disable
-		// Open button if user tries to select multiple files
-		case BROWSE_SAVE_DIRECTORY:
-		case BROWSE_DIRECTORY:
-		case BROWSE_FILE:
-		{
-		    long selectcount;
-		    AECountItems((AEDescList*)cbparm->
-				 eventData.eventDataParms.param,
-				 &selectcount);
-		    if ( selectcount > 1 ) {
-			NavCustomControl(cbparm->context,
-					 kNavCtlSetSelection,
-					 NULL);
-			astate = nfb->_keepstate |
-				 kNavDontOpenState |
-				 kNavDontChooseState;
-			NavCustomControl(cbparm->context,
-					 kNavCtlSetActionState,
-					 &astate );
-		    } else {
-			astate= nfb->_keepstate | kNavNormalState;
-			NavCustomControl(cbparm->context,
-					 kNavCtlSetActionState,
-					 &astate );
-		    }
-		    break;
-		}
-	    }
-	}
-	break;
-    }
-}
-
-// CONSTRUCTOR
-FNFC_CLASS::FNFC_CTOR(int val) {
-    _btype          = val;
-    NavGetDefaultDialogCreationOptions(&_opts);
-    _opts.optionFlags |= kNavDontConfirmReplacement;	// no confirms for "save as"
-    _options        = NO_OPTIONS;
-    _ref            = NULL;
-    memset(&_tempitem, 0, sizeof(_tempitem));
-    _pathnames      = NULL;
-    _tpathnames     = 0;
-    _title          = NULL;
-    _filter         = NULL;
-    _filt_names     = NULL;
-    memset(_filt_patt, 0, sizeof(char*) * MAXFILTERS);
-    _filt_total     = 0;
-    _filt_value     = 0;
-    _directory      = NULL;
-    _preset_file    = NULL;
-    _errmsg         = NULL;
-    _keepstate      = kNavNormalState;
-}
-
-// DESTRUCTOR
-FNFC_CLASS::~FNFC_CTOR() {
-    // _opts			// nothing to manage
-    if (_ref) { NavDialogDispose(_ref); _ref = NULL; }
-    // _options			// nothing to manage
-    // _keepstate		// nothing to manage
-    // _tempitem		// nothing to manage
-    clear_pathnames();
-    _directory   = strfree(_directory);
-    _title       = strfree(_title);
-    _preset_file = strfree(_preset_file);
-    _filter      = strfree(_filter);
-    //_filt_names		// managed by clear_filters()
-    //_filt_patt[i]		// managed by clear_filters()
-    //_filt_total		// managed by clear_filters()
-    clear_filters();
-    //_filt_value		// nothing to manage
-    _errmsg = strfree(_errmsg);
-}
-
-// SET THE TYPE OF BROWSER
-void FNFC_CLASS::type(int val) {
-    _btype = val;
-}
-
-// GET TYPE OF BROWSER
-int FNFC_CLASS::type() const {
-    return(_btype);
-}
-
-// SET OPTIONS
-void FNFC_CLASS::options(int val) {
-    _options = val;
-}
-
-// GET OPTIONS
-int FNFC_CLASS::options() const {
-    return(_options);
-}
-
-// SHOW THE BROWSER WINDOW
-//     Returns:
-//         0 - user picked a file
-//         1 - user cancelled
-//        -1 - failed; errmsg() has reason
-//
-int FNFC_CLASS::show() {
-
-    // Make sure fltk interface updates before posting our dialog
-#ifdef FLTK1
-    Fl::flush();
-#else
-    fltk::flush();
-#endif
-
-    // BROWSER TITLE
-    CFStringRef cfs_title;
-    cfs_title = CFStringCreateWithCString(NULL,
-					  _title ? _title : "No Title",
-					  kCFStringEncodingUTF8);
-    _opts.windowTitle = cfs_title;
-
-    _keepstate = kNavNormalState;
-
-    // BROWSER FILTERS
-    CFArrayRef filter_array = NULL;
-
-    // One or more filters specified?
-    if ( _filt_total ) {
-	// NAMES -> CFArrayRef
-	CFStringRef tab = CFSTR("\t");
-	CFStringRef tmp_cfs;
-	tmp_cfs = CFStringCreateWithCString(NULL,
-					    _filt_names,
-					    kCFStringEncodingUTF8);
-	filter_array = CFStringCreateArrayBySeparatingStrings(NULL,
-					                      tmp_cfs,
-							      tab);
-	CFRelease(tmp_cfs);
-	CFRelease(tab);
-	_opts.popupExtension = filter_array;
-	_opts.optionFlags |= kNavAllFilesInPopup;
-    } else {
-	filter_array = NULL;
-	_opts.popupExtension = NULL;
-	_opts.optionFlags |= kNavAllFilesInPopup;
-    }
-
-    // HANDLE OPTIONS WE SUPPORT
-    if ( _options & SAVEAS_CONFIRM ) {
-        _opts.optionFlags &= ~kNavDontConfirmReplacement;	// enables confirm
-    } else {
-        _opts.optionFlags |= kNavDontConfirmReplacement;	// disables confirm
-    }
-
-    // POST BROWSER
-    int err = post();
-
-    // RELEASE _FILT_ARR
-    if ( filter_array ) CFRelease(filter_array);
-    filter_array = NULL;
-    _opts.popupExtension = NULL;
-    _filt_total = 0;
-
-    // RELEASE TITLE
-    if ( cfs_title ) CFRelease(cfs_title);
-    cfs_title = NULL;
-
-    return(err);
-}
-
-// POST BROWSER
-//     Internal use only.
-//     Assumes '_opts' has been initialized.
-//
-//     Returns:
-//         0 - user picked a file
-//         1 - user cancelled
-//        -1 - failed; errmsg() has reason
-//     
-int FNFC_CLASS::post() {
-
-    // INITIALIZE BROWSER
-    OSStatus err;
-    if ( _filt_total == 0 ) {			// Make sure they match
-	_filt_value = 0;			// TBD: move to someplace more logical?
-    }
-
-    if ( ! ( _options & NEW_FOLDER ) ) {
-	_keepstate |= kNavDontNewFolderState;
-    }
-
-    switch (_btype) {
-	case BROWSE_FILE:
-	case BROWSE_MULTI_FILE:
-	    // Prompt user for one or more files
-	    if ((err = NavCreateGetFileDialog(
-			  &_opts,		// options
-			  0, 			// file types
-			  event_handler,	// event handler
-			  0,			// preview callback
-			  filter_proc_cb,	// filter callback
-			  (void*)this,		// callback data
-			  &_ref)) != noErr ) {	// dialog ref
-		errmsg("NavCreateGetFileDialog: failed");
-		return(-1);
-	    }
-	    break;
-
-	case BROWSE_DIRECTORY:
-	case BROWSE_MULTI_DIRECTORY:
-	case BROWSE_SAVE_DIRECTORY:
-	    // Prompts user for one or more files or folders
-	    if ((err = NavCreateChooseFolderDialog(
-			  &_opts,		// options
-			  event_handler,	// event callback
-			  0,			// filter callback
-			  (void*)this,		// callback data
-			  &_ref)) != noErr ) {	// dialog ref
-		errmsg("NavCreateChooseFolderDialog: failed");
-		return(-1);
-	    }
-	    break;
-
-	case BROWSE_SAVE_FILE:
-	    // Prompt user for filename to 'save as'
-	    if ((err = NavCreatePutFileDialog(
-			  &_opts,		// options
-			  kNavGenericSignature,	// file types
-			  0,			// file creator
-			  event_handler,	// event handler
-			  (void*)this,		// callback data
-			  &_ref)) != noErr ) {	// dialog ref
-		errmsg("NavCreatePutFileDialog: failed");
-		return(-1);
-	    }
-	    break;
-    }
-
-    // SHOW THE DIALOG
-    if ( ( err = NavDialogRun(_ref) ) != 0 ) {
-	char msg[80];
-	sprintf(msg, "NavDialogRun: failed (err=%d)", (int)err);
-	errmsg(msg);
-	return(-1);
-    }
-
-    // WHAT ACTION DID USER CHOOSE?
-    NavUserAction act = NavDialogGetUserAction(_ref);
-    if ( act == kNavUserActionNone ) {
-	errmsg("Nothing happened yet (dialog still open)");
-	return(-1);
-    }
-    else if ( act == kNavUserActionCancel ) { 	// user chose 'cancel'
-	return(1);
-    }
-    else if ( act == kNavUserActionSaveAs ) {	// user chose 'save as'
-	return(get_saveas_basename(_ref));
-    }
-
-    // TOO MANY FILES CHOSEN?
-    int ret = get_pathnames(_ref);
-    if ( _btype == BROWSE_FILE && ret == 0 && _tpathnames != 1 ) {
-	char msg[80];
-	sprintf(msg, "Expected only one file to be chosen.. you chose %d.",
-	    (int)_tpathnames);
-	errmsg(msg);
-	return(-1);
-    }
-    return(err);
-}
-
-// SET ERROR MESSAGE
-//     Internal use only.
-//
-void FNFC_CLASS::errmsg(const char *msg) {
-    _errmsg = strfree(_errmsg);
-    _errmsg = strnew(msg);
-}
-
-// RETURN ERROR MESSAGE
-const char *FNFC_CLASS::errmsg() const {
-    return(_errmsg ? _errmsg : "No error");
-}
-
-// GET FILENAME
-const char* FNFC_CLASS::filename() const {
-    if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]);
-    return("");
-}
-
-// GET FILENAME FROM LIST OF FILENAMES
-const char* FNFC_CLASS::filename(int i) const {
-    if ( _pathnames && i < _tpathnames ) return(_pathnames[i]);
-    return("");
-}
-
-// GET TOTAL FILENAMES CHOSEN
-int FNFC_CLASS::count() const {
-    return(_tpathnames);
-}
-
-// PRESET PATHNAME
-//     Value can be NULL for none.
-//
-void FNFC_CLASS::directory(const char *val) {
-    _directory = strfree(_directory);
-    _directory = strnew(val);
-}
-
-// GET PRESET PATHNAME
-//     Returned value can be NULL if none set.
-//
-const char* FNFC_CLASS::directory() const {
-    return(_directory);
-}
-
-// SET TITLE
-//     Value can be NULL if no title desired.
-//
-void FNFC_CLASS::title(const char *val) {
-    _title = strfree(_title);
-    _title = strnew(val);
-}
-
-// GET TITLE
-//     Returned value can be NULL if none set.
-//
-const char *FNFC_CLASS::title() const {
-    return(_title);
-}
-
-// SET FILTER
-//     Can be NULL if no filter needed
-//
-void FNFC_CLASS::filter(const char *val) {
-    _filter = strfree(_filter);
-    _filter = strnew(val);
-
-    // Parse filter user specified
-    //     IN: _filter = "C Files\t*.{cxx,h}\nText Files\t*.txt"
-    //    OUT: _filt_names   = "C Files\tText Files"
-    //         _filt_patt[0] = "*.{cxx,h}"
-    //         _filt_patt[1] = "*.txt"
-    //         _filt_total   = 2
-    //
-    parse_filter(_filter);
-}
-
-// GET FILTER
-//     Returned value can be NULL if none set.
-//
-const char *FNFC_CLASS::filter() const {
-    return(_filter);
-}
-
-// CLEAR ALL FILTERS
-//    Internal use only.
-//
-void FNFC_CLASS::clear_filters() {
-    _filt_names = strfree(_filt_names);
-    for (int i=0; i<_filt_total; i++) {
-	_filt_patt[i] = strfree(_filt_patt[i]);
-    }
-    _filt_total = 0;
-}
-
-// PARSE USER'S FILTER SPEC
-//    Parses user specified filter ('in'),
-//    breaks out into _filt_patt[], _filt_names, and _filt_total.
-//
-//    Handles:
-//    IN:                                   OUT:_filt_names    OUT: _filt_patt
-//    ------------------------------------  ------------------ ---------------
-//    "*.{ma,mb}"                           "*.{ma,mb} Files"  "*.{ma,mb}"
-//    "*.[abc]"                             "*.[abc] Files"    "*.[abc]"
-//    "*.txt"                               "*.txt Files"      "*.c"
-//    "C Files\t*.[ch]"                     "C Files"          "*.[ch]"
-//    "C Files\t*.[ch]\nText Files\t*.cxx"  "C Files"          "*.[ch]"
-//
-//    Parsing Mode:
-//         IN:"C Files\t*.{cxx,h}"
-//             |||||||  |||||||||
-//       mode: nnnnnnn  wwwwwwwww
-//             \_____/  \_______/
-//              Name     Wildcard
-//
-void FNFC_CLASS::parse_filter(const char *in) {
-    clear_filters();
-    if ( ! in ) return;
-    int has_name = strchr(in, '\t') ? 1 : 0;
-
-    char mode = has_name ? 'n' : 'w';	// parse mode: n=title, w=wildcard
-    char wildcard[1024] = "";		// parsed wildcard
-    char name[1024] = "";
-
-    // Parse filter user specified
-    for ( ; 1; in++ ) {
-
-        //// DEBUG
-        //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n",
-	////                    *in,  mode,     name,     wildcard);
-	
-        switch (*in) {
-	    // FINISHED PARSING NAME?
-	    case '\t':
-	        if ( mode != 'n' ) goto regchar;
-		mode = 'w';
-		break;
-
-	    // ESCAPE NEXT CHAR
-	    case '\\':
-	        ++in;
-		goto regchar;
-
-	    // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
-	    case '\r':
-	    case '\n':
-	    case '\0':
-		// TITLE
-		//     If user didn't specify a name, make one
-		//
-		if ( name[0] == '\0' ) {
-		    sprintf(name, "%.*s Files", (int)sizeof(name)-10, wildcard);
-		}
-		// APPEND NEW FILTER TO LIST
-		if ( wildcard[0] ) {
-		    // Add to filtername list
-		    //     Tab delimit if more than one. We later break
-		    //     tab delimited string into CFArray with 
-		    //     CFStringCreateArrayBySeparatingStrings()
-		    //
-		    if ( _filt_total ) {
-			_filt_names = strapp(_filt_names, "\t");
-		    }
-		    _filt_names = strapp(_filt_names, name);
-
-		    // Add filter to the pattern array
-		    _filt_patt[_filt_total++] = strnew(wildcard);
-		}
-		// RESET
-		wildcard[0] = name[0] = '\0';
-		mode = strchr(in, '\t') ? 'n' : 'w';
-		// DONE?
-		if ( *in == '\0' ) return;	// done
-		else continue;			// not done yet, more filters
-
-	    // Parse all other chars
-	    default:				// handle all non-special chars
-	    regchar:				// handle regular char
-                switch ( mode ) {
-	            case 'n': chrcat(name, *in);     continue;
-	            case 'w': chrcat(wildcard, *in); continue;
-	        }
-		break;
-	}
-    }
-    //NOTREACHED
-}
-
-// STATIC: FILTER CALLBACK
-Boolean FNFC_CLASS::filter_proc_cb(AEDesc *theItem,
-				   void *info,
-				   void *callBackUD,
-				   NavFilterModes filterMode) {
-    return((FNFC_CLASS*)callBackUD)->filter_proc_cb2(theItem,
-    						     info,
-						     callBackUD,
-						     filterMode);
-}
-
-// FILTER CALLBACK
-//     Return true if match,
-//            false if no match.
-//
-Boolean FNFC_CLASS::filter_proc_cb2(AEDesc *theItem,
-				    void *info,
-				    void *callBackUD,
-				    NavFilterModes filterMode) {
-    // All files chosen or no filters
-    if ( _filt_value == _filt_total ) return(true);
-    
-    FSRef fsref;
-    char pathname[4096];
-    
-    // On fail, filter should return true by default
-    if ( AEDescToFSRef(theItem, &fsref) != noErr ) {
-        return(true);
-    }
-    FSRefMakePath(&fsref, (UInt8 *)pathname, sizeof(pathname)-1);
-
-    if ( fl_filename_isdir(pathname) ) return(true);
-    if ( fl_filename_match(pathname, _filt_patt[_filt_value]) ) return(true);
-    else return(false);
-}
-
-// SET PRESET FILE
-//     Value can be NULL for none.
-//
-void FNFC_CLASS::preset_file(const char* val) {
-    _preset_file = strfree(_preset_file);
-    _preset_file = strnew(val);
-}
-
-// PRESET FILE
-//     Returned value can be NULL if none set.
-//
-const char* FNFC_CLASS::preset_file() {
-    return(_preset_file);
-}
-
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser_WIN32.cxx b/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser_WIN32.cxx
deleted file mode 100644
index 51d708d..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/Fl_Native_File_Chooser_WIN32.cxx
+++ /dev/null
@@ -1,806 +0,0 @@
-//
-// Fl_Native_File_Chooser_WIN32.cxx -- FLTK native OS file chooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-// API changes + filter improvements by Nathan Vander Wilt 2005
-// FLTK2/WIN32 port by Greg Ercolano
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-// Please keep code 80 column compliant.
-//
-//      10        20        30        40        50        60        70
-//       |         |         |         |         |         |         |
-// 4567890123456789012345678901234567890123456789012345678901234567890123456789
-//
-
-// Any application to multi-folder implementation:
-//     http://www.codeproject.com/dialog/selectfolder.asp
-//
-
-#include <stdio.h>		// debugging
-#include "common.cxx"		// strnew/strfree/strapp/chrcat
-
-#ifdef FLTK1
-//
-// FLTK1
-//
-#include <FL/Fl_Native_File_Chooser.H>
-#define FNFC_CLASS Fl_Native_File_Chooser
-#define FNFC_CTOR  Fl_Native_File_Chooser
-#else
-//
-// FLTK2
-//
-#include <fltk/NativeFileChooser.h>
-#include <fltk/run.h>
-#define FNFC_CTOR  NativeFileChooser
-#define FNFC_CLASS fltk::FNFC_CTOR
-#endif
-
-#define LCURLY_CHR	'{'
-#define RCURLY_CHR	'}'
-#define LBRACKET_CHR	'['
-#define RBRACKET_CHR	']'
-#define MAXFILTERS	80
-
-// STATIC: PRINT WINDOWS 'DOUBLE NULL' STRING (DEBUG)
-static void dnullprint(char *wp) {
-    if ( ! wp ) return;
-    for ( int t=0; true; t++ ) {
-        if ( wp[t] == '\0' && wp[t+1] == '\0' ) {
-	    printf("\\0\\0");
-	    fflush(stdout);
-	    return;
-	} else if ( wp[t] == '\0' ) {
-	    printf("\\0");
-	} else { 
-	    printf("%c",wp[t]);
-	}
-    }
-}
-
-// RETURN LENGTH OF DOUBLENULL STRING
-//    Includes single nulls in count, excludes trailing doublenull.
-//
-//         1234 567
-//         |||/\|||
-//    IN: "one\0two\0\0"
-//   OUT: 7
-//
-static int dnulllen(const char *wp) {
-    int len = 0;
-    while ( ! ( *(wp+0) == 0 && *(wp+1) == 0 ) )
-        { ++wp; ++len; }
-    return(len);
-}
-
-// STATIC: Append a string to another, leaving terminated with DOUBLE NULL.
-//     Automatically handles extending length of string.
-//     wp can be NULL (a new wp will be allocated and initialized).
-//     string must be NULL terminated.
-//     The pointer wp may be modified on return.
-//
-static void dnullcat(char*&wp, const char *string, int n = -1 ) {
-    //DEBUG printf("DEBUG: dnullcat IN: <"); dnullprint(wp); printf(">\n");
-    int inlen = ( n < 0 ) ? strlen(string) : n;
-    if ( ! wp ) {
-        wp = new char[inlen + 4];
-	*(wp+0) = '\0';
-	*(wp+1) = '\0';
-    } else {
-        int wplen = dnulllen(wp);
-	// Make copy of wp into larger buffer
-	char *tmp = new char[wplen + inlen + 4];
-	memcpy(tmp, wp, wplen+2);	// copy of wp plus doublenull
-	delete [] wp;			// delete old wp
-	wp = tmp;			// use new copy
-	//DEBUG printf("DEBUG: dnullcat COPY: <"); dnullprint(wp); printf("> (wplen=%d)\n", wplen);
-    }
-
-    // Find end of double null string
-    //     *wp2 is left pointing at second null.
-    //
-    char *wp2 = wp;
-    if ( *(wp2+0) != '\0' && *(wp2+1) != '\0' ) {
-	for ( ; 1; wp2++ )
-	    if ( *(wp2+0) == '\0' && *(wp2+1) == '\0' )
-		{ wp2++; break; }
-    }
-
-    if ( n == -1 ) n = strlen(string);
-    strncpy(wp2, string, n);
-
-    // Leave string double-null terminated
-    *(wp2+n+0) = '\0';
-    *(wp2+n+1) = '\0';
-    //DEBUG printf("DEBUG: dnullcat OUT: <"); dnullprint(wp); printf(">\n\n");
-}
-
-// CTOR
-FNFC_CLASS::FNFC_CTOR(int val) {
-    _btype           = val;
-    _options         = NO_OPTIONS;
-    memset((void*)&_ofn, 0, sizeof(OPENFILENAME));
-    _ofn.lStructSize = sizeof(OPENFILENAME);
-    _ofn.hwndOwner   = NULL;
-    memset((void*)&_binf, 0, sizeof(BROWSEINFO));
-    _pathnames       = NULL;
-    _tpathnames      = 0;
-    _directory       = NULL;
-    _title           = NULL;
-    _filter          = NULL;
-    _parsedfilt      = NULL;
-    _nfilters        = 0;
-    _preset_file     = NULL;
-    _errmsg          = NULL;
-}
-
-// DTOR
-FNFC_CLASS::~FNFC_CTOR() {
-    //_pathnames                // managed by clear_pathnames()
-    //_tpathnames               // managed by clear_pathnames()
-    _directory   = strfree(_directory);
-    _title       = strfree(_title);
-    _filter      = strfree(_filter);
-    //_parsedfilt               // managed by clear_filters()
-    //_nfilters                 // managed by clear_filters()
-    _preset_file = strfree(_preset_file);
-    _errmsg      = strfree(_errmsg);
-    clear_filters();
-    clear_pathnames();
-    ClearOFN();
-    ClearBINF();
-}
-
-// SET TYPE OF BROWSER
-void FNFC_CLASS::type(int val) {
-    _btype = val;
-}
-
-// GET TYPE OF BROWSER
-int FNFC_CLASS::type() const {
-    return( _btype );
-}
-
-// SET OPTIONS
-void FNFC_CLASS::options(int val) {
-    _options = val;
-}
-
-// GET OPTIONS
-int FNFC_CLASS::options() const {
-    return(_options);
-}
-
-// PRIVATE: SET ERROR MESSAGE
-void FNFC_CLASS::errmsg(const char *val) {
-    _errmsg = strfree(_errmsg);
-    _errmsg = strnew(val);
-}
-
-// FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS
-void FNFC_CLASS::clear_pathnames() {
-    if ( _pathnames ) {
-	while ( --_tpathnames >= 0 ) {
-	    _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]);
-	}
-	delete [] _pathnames;
-	_pathnames = NULL;
-    }
-    _tpathnames = 0;
-}
-
-// SET A SINGLE PATHNAME
-void FNFC_CLASS::set_single_pathname(const char *s) {
-    clear_pathnames();
-    _pathnames = new char*[1];
-    _pathnames[0] = strnew(s);
-    _tpathnames = 1;
-}
-
-// ADD PATHNAME TO EXISTING ARRAY
-void FNFC_CLASS::add_pathname(const char *s) {
-    if ( ! _pathnames ) {
-        // Create first element in array
-	++_tpathnames;
-	_pathnames = new char*[_tpathnames];
-    } else {
-        // Grow array by 1
-        char **tmp = new char*[_tpathnames+1];		// create new buffer
-	memcpy((void*)tmp, (void*)_pathnames, 
-	                   sizeof(char*)*_tpathnames);	// copy old
-	delete [] _pathnames;				// delete old
-	_pathnames = tmp;				// use new
-	++_tpathnames;
-    }
-    _pathnames[_tpathnames-1] = strnew(s);
-}
-
-// FREE A PIDL (Pointer to IDentity List)
-void FNFC_CLASS::FreePIDL(ITEMIDLIST *pidl) {
-    IMalloc *imalloc = NULL;
-    if ( SUCCEEDED(SHGetMalloc(&imalloc)) )
-	{ imalloc->Free(pidl); imalloc->Release(); imalloc = NULL; }
-}
-
-// CLEAR MICROSOFT OFN (OPEN FILE NAME) CLASS
-void FNFC_CLASS::ClearOFN() {
-    // Free any previously allocated lpstrFile before zeroing out _ofn
-    if ( _ofn.lpstrFile ) {
-        _ofn.lpstrFile = strfree((char*)_ofn.lpstrFile);
-    }
-    if ( _ofn.lpstrInitialDir ) {
-        _ofn.lpstrInitialDir = (LPCSTR)strfree((char*)_ofn.lpstrInitialDir);
-    }
-    _ofn.lpstrFilter = NULL;		// (deleted elsewhere)
-    int temp = _ofn.nFilterIndex;	// keep the filter_value
-    memset((void*)&_ofn, 0, sizeof(_ofn));
-    _ofn.lStructSize  = sizeof(OPENFILENAME);
-    _ofn.nFilterIndex = temp;
-}
-
-// CLEAR MICROSOFT BINF (BROWSER INFO) CLASS
-void FNFC_CLASS::ClearBINF() {
-    if ( _binf.pidlRoot ) {
-	FreePIDL((ITEMIDLIST*)_binf.pidlRoot);
-	_binf.pidlRoot = NULL;
-    }
-    memset((void*)&_binf, 0, sizeof(_binf));
-}
-
-// CONVERT WINDOWS BACKSLASHES TO UNIX FRONTSLASHES
-void FNFC_CLASS::Win2Unix(char *s) {
-    for ( ; *s; s++ )
-	if ( *s == '\\' ) *s = '/';
-}
-
-// CONVERT UNIX FRONTSLASHES TO WINDOWS BACKSLASHES
-void FNFC_CLASS::Unix2Win(char *s) {
-    for ( ; *s; s++ )
-	if ( *s == '/' ) *s = '\\';
-}
-
-// SHOW FILE BROWSER
-int FNFC_CLASS::showfile() {
-    ClearOFN();
-    clear_pathnames();
-    size_t fsize = 2048;
-    _ofn.Flags |= OFN_NOVALIDATE;	// prevent disabling of front slashes
-    _ofn.Flags |= OFN_HIDEREADONLY;	// hide goofy readonly flag
-    // USE NEW BROWSER
-    _ofn.Flags |= OFN_EXPLORER;		// use newer explorer windows
-    _ofn.Flags |= OFN_ENABLESIZING;	// allow window to be resized (hey, why not?)
-
-    // XXX: The docs for OFN_NOCHANGEDIR says the flag is 'ineffective' on XP/2K/NT!
-    //      But let's set it anyway..
-    //
-    _ofn.Flags |= OFN_NOCHANGEDIR;	// prevent dialog for messing up the cwd
-
-    switch ( _btype ) {
-	case BROWSE_DIRECTORY:
-	case BROWSE_MULTI_DIRECTORY:
-	case BROWSE_SAVE_DIRECTORY:
-	    abort();			// never happens: handled by showdir()
-	case BROWSE_FILE:
-	    fsize = 65536;		// XXX: there must be a better way
-	    break;
-	case BROWSE_MULTI_FILE:
-	    _ofn.Flags |= OFN_ALLOWMULTISELECT;
-	    fsize = 65536;		// XXX: there must be a better way
-	    break;
-	case BROWSE_SAVE_FILE:
-	    if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) {
-		_ofn.Flags |= OFN_OVERWRITEPROMPT;
-	    }
-	    break;
-    }
-    // SPACE FOR RETURNED FILENAME
-    _ofn.lpstrFile    = new char[fsize];
-    _ofn.nMaxFile     = fsize-1;
-    _ofn.lpstrFile[0] = '\0';
-    _ofn.lpstrFile[1] = '\0';		// dnull
-    // PARENT WINDOW
-    _ofn.hwndOwner = GetForegroundWindow();
-    // DIALOG TITLE
-    _ofn.lpstrTitle = _title ? _title : NULL;
-    // FILTER
-    _ofn.lpstrFilter = _parsedfilt ? _parsedfilt : NULL;
-    // PRESET FILE
-    //     If set, supercedes _directory. See KB Q86920 for details
-    //
-    if ( _preset_file ) {
-        size_t len = strlen(_preset_file);
-	if ( len >= _ofn.nMaxFile ) {
-	    char msg[80];
-	    sprintf(msg, "preset_file() filename is too long: %ld is >=%ld", 
-	        (long)len, (long)fsize);
-	    return(-1);
-	}
-	strncpy(_ofn.lpstrFile, _preset_file, _ofn.nMaxFile);
-	Unix2Win(_ofn.lpstrFile);
-	_ofn.lpstrFile[len+0] = 0;	// multiselect needs dnull
-	_ofn.lpstrFile[len+1] = 0;
-    }
-    if ( _directory ) {
-	// PRESET DIR
-	//     XXX: See KB Q86920 for doc bug:
-	//     http://support.microsoft.com/default.aspx?scid=kb;en-us;86920
-	//
-	_ofn.lpstrInitialDir = strnew(_directory);
-	Unix2Win((char*)_ofn.lpstrInitialDir);
-    }
-    // SAVE THE CURRENT DIRECTORY
-    //     XXX: Save the cwd because GetOpenFileName() is probably going to
-    //     change it, in spite of the OFN_NOCHANGEDIR flag, due to its docs
-    //     saying the flag is 'ineffective'. %^(
-    //
-    char oldcwd[MAX_PATH];
-    GetCurrentDirectory(MAX_PATH, oldcwd);
-    oldcwd[MAX_PATH-1] = '\0';
-    // OPEN THE DIALOG WINDOW
-    int err;
-    if ( _btype == BROWSE_SAVE_FILE ) {
-	err = GetSaveFileName(&_ofn);
-    } else {
-	err = GetOpenFileName(&_ofn);
-    }
-    if ( err == 0 ) {
-	// EXTENDED ERROR CHECK
-	int err = CommDlgExtendedError();
-	// CANCEL?
-	if ( err == 0 ) 
-	    return(1);	// user hit 'cancel'
-	// AN ERROR OCCURRED
-	char msg[80];
-	sprintf(msg, "CommDlgExtendedError() code=%d", err);
-	errmsg(msg);
-	// XXX: RESTORE CWD
-	if ( oldcwd[0] ) SetCurrentDirectory(oldcwd);
-	return(-1);
-    }
-    // XXX: RESTORE CWD
-    if ( oldcwd[0] ) {
-        SetCurrentDirectory(oldcwd);
-    }
-    // PREPARE PATHNAMES FOR RETURN
-    switch ( _btype ) {
-	case BROWSE_FILE: 
-	case BROWSE_SAVE_FILE:
-	    set_single_pathname(_ofn.lpstrFile);
-	    Win2Unix(_pathnames[_tpathnames-1]);
-	    break;
-	case BROWSE_MULTI_FILE: {
-	    // EXTRACT MULTIPLE FILENAMES
-	    const char *dirname = _ofn.lpstrFile;
-	    int dirlen = strlen(dirname);
-	    if ( dirlen > 0 ) {
-		// WALK STRING SEARCHING FOR 'DOUBLE-NULL'
-		//     eg. "/dir/name\0foo1\0foo2\0foo3\0\0"
-		//
-		char pathname[2048]; 
-		for ( const char *s = _ofn.lpstrFile + dirlen + 1; 
-						      *s; s+= (strlen(s)+1)) {
-		    strcpy(pathname, dirname);
-		    strcat(pathname, "\\");
-		    strcat(pathname, s);
-		    add_pathname(pathname);
-		    Win2Unix(_pathnames[_tpathnames-1]);
-		}
-	    }
-	    // XXX
-	    //    Work around problem where pasted forward-slash pathname
-	    //    into the file browser causes new "Explorer" interface
-	    //    not to grok forward slashes, passing back as a 'filename'..!
-	    //
-	    if ( _tpathnames == 0 ) {
-		add_pathname(dirname); 
-		Win2Unix(_pathnames[_tpathnames-1]);
-	    }
-	    break;
-	}
-	case BROWSE_DIRECTORY:
-	case BROWSE_MULTI_DIRECTORY:
-	case BROWSE_SAVE_DIRECTORY:
-	    abort();			// never happens: handled by showdir()
-    }
-    return(0);
-}
-
-// Used by SHBrowseForFolder(), sets initial selected dir.
-// Ref: Usenet: microsoft.public.vc.mfc, Dec 8 2000, 1:38p David Lowndes
-//              Subject: How to specify to select an initial folder .."
-//
-int CALLBACK FNFC_CLASS::Dir_CB(HWND win, UINT msg, 
-                                            LPARAM param, LPARAM data) {
-    switch (msg) {
-	case BFFM_INITIALIZED:
-	    if (data) ::SendMessage(win, BFFM_SETSELECTION, TRUE, data);
-	    break;
-	case BFFM_SELCHANGED:
-	    TCHAR path[MAX_PATH];
-	    if ( SHGetPathFromIDList((ITEMIDLIST*)param, path) ) {
-	        ::SendMessage(win, BFFM_ENABLEOK, 0, 1);
-	    } else {
-		//disable ok button if not a path
-	        ::SendMessage(win, BFFM_ENABLEOK, 0, 0);
-	    }
-	    break;
-	case BFFM_VALIDATEFAILED:
-	    // we could pop up an annoying message here. 
-	    // also needs set ulFlags |= BIF_VALIDATE
-	    break;
-	default:
-	    break;
-    }
-    return(0);
-}
-
-// SHOW DIRECTORY BROWSER
-int FNFC_CLASS::showdir() {
-    OleInitialize(NULL);	// init needed by BIF_USENEWUI
-    ClearBINF();
-    clear_pathnames();
-    // PARENT WINDOW
-    _binf.hwndOwner = GetForegroundWindow();
-    // DIALOG TITLE
-    _binf.lpszTitle = _title ? _title : NULL;
-    // FLAGS
-    _binf.ulFlags = 0; 		// initialize
-
-    // TBD: make sure matches to runtime system, if need be.
-    //( what if _WIN32_IE doesn't match system? does the program not run? )
-    //
-    // TBD: match all 3 types of directories
-    //
-    // NOTE: *Don't* use BIF_SHAREABLE. It /disables/ mapped network shares
-    //       from being visible in BROWSE_DIRECTORY mode. 
-    //       See Walter Garm's comments in ./TODO.
-
-#if defined(BIF_NONEWFOLDERBUTTON)				// Version 6.0
-    if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags |= BIF_NONEWFOLDERBUTTON;
-    _binf.ulFlags |= BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
-#elif defined(BIF_USENEWUI)					// Version 5.0
-    if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags |= BIF_EDITBOX;
-    else if ( _btype == BROWSE_SAVE_DIRECTORY ) _binf.ulFlags |= BIF_USENEWUI;
-    _binf.ulFlags |= BIF_RETURNONLYFSDIRS;
-#elif defined(BIF_EDITBOX)					// Version 4.71
-    _binf.ulFlags |= BIF_RETURNONLYFSDIRS | BIF_EDITBOX;
-#else								// Version Old
-    _binf.ulFlags |= BIF_RETURNONLYFSDIRS;
-#endif
-
-    // BUFFER
-    char displayname[MAX_PATH];
-    _binf.pszDisplayName = displayname;
-    // PRESET DIR
-    char presetname[MAX_PATH];
-    if ( _directory ) {
-	strcpy(presetname, _directory);
-	Unix2Win(presetname);
-	_binf.lParam = (LPARAM)presetname;
-    }
-    else _binf.lParam = 0;
-    _binf.lpfn = Dir_CB;
-    // OPEN BROWSER
-    ITEMIDLIST *pidl = SHBrowseForFolder(&_binf);
-    // CANCEL?
-    if ( pidl == NULL ) return(1);
-
-    // GET THE PATHNAME(S) THE USER SELECTED
-    // TBD: expand NetHood shortcuts from this PIDL??
-    // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shbrowseforfolder.asp
-
-    TCHAR path[MAX_PATH];
-    if ( SHGetPathFromIDList(pidl, path) ) {
-        Win2Unix(path);
-	add_pathname(path);
-    }
-    FreePIDL(pidl);
-    if ( !strlen(path) ) return(1);             // don't return empty pathnames
-    return(0);
-}
-
-// RETURNS:
-//    0 - user picked a file
-//    1 - user cancelled
-//   -1 - failed; errmsg() has reason
-//
-int FNFC_CLASS::show() {
-    if ( _btype == BROWSE_DIRECTORY || 
-         _btype == BROWSE_MULTI_DIRECTORY || 
-	 _btype == BROWSE_SAVE_DIRECTORY ) {
-	return(showdir());
-    } else {
-	return(showfile());
-    }
-}
-
-// RETURN ERROR MESSAGE
-const char *FNFC_CLASS::errmsg() const {
-    return(_errmsg ? _errmsg : "No error");
-}
-
-// GET FILENAME
-const char* FNFC_CLASS::filename() const {
-    if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]);
-    return("");
-}
-
-// GET FILENAME FROM LIST OF FILENAMES
-const char* FNFC_CLASS::filename(int i) const {
-    if ( _pathnames && i < _tpathnames ) return(_pathnames[i]);
-    return("");
-}
-
-// GET TOTAL FILENAMES CHOSEN
-int FNFC_CLASS::count() const {
-    return(_tpathnames);
-}
-
-// PRESET PATHNAME
-//     Can be NULL if no preset is desired.
-//
-void FNFC_CLASS::directory(const char *val) {
-    _directory = strfree(_directory);
-    _directory = strnew(val);
-}
-
-// GET PRESET PATHNAME
-//    Can return NULL if none set.
-//
-const char *FNFC_CLASS::directory() const {
-    return(_directory);
-}
-
-// SET TITLE
-//     Can be NULL if no title desired.
-//
-void FNFC_CLASS::title(const char *val) {
-    _title = strfree(_title);
-    _title = strnew(val);
-}
-
-// GET TITLE
-//    Can return NULL if none set.
-//
-const char *FNFC_CLASS::title() const {
-    return(_title);
-}
-
-// SET FILTER
-//     Can be NULL if no filter needed
-//
-void FNFC_CLASS::filter(const char *val) {
-    _filter = strfree(_filter);
-    clear_filters();
-    if ( val ) {
-	_filter = strnew(val);
-	parse_filter(_filter);
-    }
-    add_filter("All Files", "*.*");	// always include 'all files' option
-
-#ifdef DEBUG
-    nullprint(_parsedfilt);
-#endif /*DEBUG*/
-}
-
-// GET FILTER
-//    Can return NULL if none set.
-//
-const char *FNFC_CLASS::filter() const {
-    return(_filter);
-}
-
-// CLEAR FILTERS
-void FNFC_CLASS::clear_filters() {
-    _nfilters = 0;
-    _parsedfilt = strfree(_parsedfilt);
-}
-
-// ADD A FILTER
-void FNFC_CLASS::add_filter(
-	   const char *name_in,	    // name of filter (optional: can be null)
-	   const char *winfilter    // windows style filter (eg. "*.cxx;*.h")
-	  ) {
-    // No name? Make one..
-    char name[1024];
-    if ( !name_in || name_in[0] == '\0' ) {
-	sprintf(name, "%.*s Files", sizeof(name)-10, winfilter);
-    } else {
-        sprintf(name, "%.*s", sizeof(name)-10, name_in);
-    }
-    dnullcat(_parsedfilt, name);
-    dnullcat(_parsedfilt, winfilter);
-    _nfilters++;
-    //DEBUG printf("DEBUG: ADD FILTER name=<%s> winfilter=<%s>\n", name, winfilter);
-}
-
-// CONVERT FLTK STYLE PATTERN MATCHES TO WINDOWS 'DOUBLENULL' PATTERN
-//    Handles:
-//        IN              OUT
-//        -----------     -----------------------------
-//        *.{ma,mb}       "*.{ma,mb} Files\0*.ma;*.mb\0\0"
-//        *.[abc]         "*.[abc] Files\0*.a;*.b;*.c\0\0"
-//        *.txt           "*.txt Files\0*.txt\0\0"
-//        C Files\t*.[ch] "C Files\0*.c;*.h\0\0"
-//
-//    Example:
-//         IN: "*.{ma,mb}"
-//        OUT: "*.ma;*.mb Files\0*.ma;*.mb\0All Files\0*.*\0\0"
-//              ---------------  ---------  ---------  ---
-//                     |             |          |       |
-//                   Title       Wildcards    Title    Wildcards
-//
-// Parsing Mode:
-//         IN:"C Files\t*.{cxx,h}"
-//             |||||||  |||||||||
-//       mode: nnnnnnn  ww{{{{{{{
-//             \_____/  \_______/
-//              Name     Wildcard
-//
-void FNFC_CLASS::parse_filter(const char *in) {
-    clear_filters();
-    if ( ! in ) return;
-
-    int has_name = strchr(in, '\t') ? 1 : 0;
-
-    char mode = has_name ? 'n' : 'w';	// parse mode: n=name, w=wildcard
-    int nwildcards = 0;
-    char wildcards[MAXFILTERS][1024];	// parsed wildcards (can be several)
-    char wildprefix[512] = "";
-    char name[512] = "";
-
-    // Init
-    int t;
-    for ( t=0; t<MAXFILTERS; t++ ) {
-        wildcards[t][0] = '\0';
-    }
-
-    // Parse
-    for ( ; 1; in++ ) {
-
-        //// DEBUG
-        //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildprefix=<%s> nwildcards=%d wildcards[n]=<%s>\n",
-	////        *in, mode, name, wildprefix, nwildcards, wildcards[nwildcards]);
-
-        switch (*in) {
-	    case ',':
-	    case '|':
-	        if ( mode == LCURLY_CHR ) {
-		    // create new wildcard, copy in prefix
-		    strcat(wildcards[nwildcards++], wildprefix);
-		    continue;
-		} else {
-		    goto regchar;
-		}
-		continue;
-
-	    // FINISHED PARSING A NAME?
-	    case '\t':
-	        if ( mode != 'n' ) goto regchar;
-		// finish parsing name? switch to wildcard mode
-		mode = 'w';
-		break;
-
-	    // ESCAPE NEXT CHAR
-	    case '\\':
-	        ++in;
-		goto regchar;
-
-	    // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
-	    case '\r':
-	    case '\n':
-	    case '\0':
-	    {
-	        if ( mode == 'w' ) {		// finished parsing wildcard?
-		    if ( nwildcards == 0 ) {
-		        strcpy(wildcards[nwildcards++], wildprefix);
-		    }
-		    // Append wildcards in Microsoft's "*.one;*.two" format
-		    char comp[4096] = "";
-		    for ( t=0; t<nwildcards; t++ ) {
-			if ( t != 0 ) strcat(comp, ";");
-			strcat(comp, wildcards[t]);
-		    }
-		    // Add if not empty
-		    if ( comp[0] ) {
-			add_filter(name, comp);
-		    }
-		}
-		// RESET
-		for ( t=0; t<MAXFILTERS; t++ ) {
-		    wildcards[t][0] = '\0';
-		}
-		nwildcards = 0;
-		wildprefix[0] = name[0] = '\0';
-		mode = strchr(in,'\t') ? 'n' : 'w';
-		// DONE?
-		if ( *in == '\0' ) return;	// done
-		continue;			// not done yet, more filters
-	    }
-
-	    // STARTING A WILDCARD?
-	    case LBRACKET_CHR:
-	    case LCURLY_CHR:
-	        mode = *in;
-		if ( *in == LCURLY_CHR ) {
-		    // create new wildcard
-		    strcat(wildcards[nwildcards++], wildprefix);
-		}
-		continue;
-
-	    // ENDING A WILDCARD?
-	    case RBRACKET_CHR:
-	    case RCURLY_CHR:
-		mode = 'w';	// back to wildcard mode
-		continue;
-
-	    // ALL OTHER NON-SPECIAL CHARACTERS
-	    default:
-	    regchar:		// handle regular char
-                switch ( mode ) {
-	            case LBRACKET_CHR: 
-			// create new wildcard
-		        ++nwildcards;
-			// copy in prefix
-			strcpy(wildcards[nwildcards-1], wildprefix);
-			// append search char
-			chrcat(wildcards[nwildcards-1], *in);
-			continue;
-
-	            case LCURLY_CHR:
-		        if ( nwildcards > 0 ) {
-			    chrcat(wildcards[nwildcards-1], *in);
-			}
-			continue;
-
-	            case 'n':
-		        chrcat(name, *in);
-			continue;
-
-	            case 'w':
-			chrcat(wildprefix, *in);
-		        for ( t=0; t<nwildcards; t++ ) {
-			    chrcat(wildcards[t], *in);
-			}
-			continue;
-	        }
-		break;
-	}
-    }
-}
-
-// SET 'CURRENTLY SELECTED FILTER'
-void FNFC_CLASS::filter_value(int i) {
-    _ofn.nFilterIndex = i + 1;
-}
-
-// RETURN VALUE OF 'CURRENTLY SELECTED FILTER'
-int FNFC_CLASS::filter_value() const {
-    return(_ofn.nFilterIndex ? _ofn.nFilterIndex-1 : _nfilters+1);
-}
-
-// PRESET FILENAME FOR 'SAVE AS' CHOOSER
-void FNFC_CLASS::preset_file(const char* val) {
-    _preset_file = strfree(_preset_file);
-    _preset_file = strnew(val);
-}
-
-// GET PRESET FILENAME FOR 'SAVE AS' CHOOSER
-const char* FNFC_CLASS::preset_file() const {
-    return(_preset_file);
-}
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile b/Utilities/FLTK/Fl_Native_File_Chooser/Makefile
deleted file mode 100644
index c33da8c..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# Fl_Native_File_Chooser -- Makefile
-#
-
-# UNCOMMENT FOR FLTK1 BUILD
-FLTKCONFIG=fltk-config
-
-# UNCOMMENT FOR FLTK2 BUILD
-FLTK2CONFIG=fltk2-config
-
-### REMOVE:END
-
-# Build Everything
-all: FORCE
-ifneq ($(FLTKCONFIG),)
-	@echo "***"; echo "*** FLTK1 BUILD"; echo "***"
-	( make -f Makefile-fltk1 all "FLTKCONFIG=$(FLTKCONFIG)")
-endif
-ifneq ($(FLTK2CONFIG),)
-	@echo "***"; echo "*** FLTK2 BUILD"; echo "***"
-	( make -f Makefile-fltk2 all "FLTK2CONFIG=$(FLTK2CONFIG)")
-endif
-
-# Libs
-Fl_Native_File_Chooser.o: FORCE
-	( make -f Makefile-fltk1 $@ "FLTKCONFIG=$(FLTKCONFIG)")
-
-NativeFileChooser.o: FORCE
-	( make -f Makefile-fltk2 $@ "FLTK2CONFIG=$(FLTK2CONFIG)")
-
-# Clean build
-clean: FORCE
-# BINARIES
-	-rm -f *.o                2> /dev/null
-	-rm -f *.obj              2> /dev/null
-	-rm -f *.exe              2> /dev/null
-	-rm -f test-browser       2> /dev/null
-	-rm -f test-browser-fltk2 2> /dev/null
-	-rm -f simple-app         2> /dev/null
-	-rm -f simple-app-fltk2   2> /dev/null
-# EDITOR CRAP
-	-rm -f *~     2> /dev/null
-	-rm -f .*.swp 2> /dev/null
-# WINDOWS CRAP
-	-rm -rf ii_files           2> /dev/null
-	-rm -f *.{ilk,pdb,sln,suo} 2> /dev/null
-	-rm -f *.{manifest,idb}    2> /dev/null
-# UNIX CRAP
-	-rm -f core         2> /dev/null
-	-rm -f core.*       2> /dev/null
-	-rm -f .nfs*        2> /dev/null
-	-rm -f .gdb_history 2> /dev/null
-# MAC CRAP
-	-rm -rf .DS_Store      2> /dev/null
-	-rm -f ._test-browser* 2> /dev/null
-	-rm -f ._simple-app*   2> /dev/null
-	-rm -f *.app/Contents/MacOS/*
-
-# Create distribution tar file (for maintainer only)
-tar: clean
-	if grep -q ERCODEBUG *.cxx FL/*.H ; then \
-	    echo '### NO DEBUG CODE IN RELEASE'; \
-	    exit 1; \
-	fi
-	sh .TAR_RELEASE.sh
-
-# FORCE TARGET -- Do not remove
-FORCE:
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk1 b/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk1
deleted file mode 100644
index 211b8ce..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk1
+++ /dev/null
@@ -1,94 +0,0 @@
-# Makefile that uses fltkconfig
-# Submitted by Ian MacArthur.
-# NOTE: This makes use of new features in fltk-config 1.1.6: --cxx and --cc flags.
-#########################################################
-
-# Assumes FLTKCONFIG has been set by main Makefile
-
-# flags for compiler:
-CFLAGS   = -Wall -O3 -I. $(shell $(FLTKCONFIG) --cflags) -DFLTK1
-CXXFLAGS = -Wall -O3 -I. $(shell $(FLTKCONFIG) --cxxflags) -DFLTK1
-
-# Possible steps after linking...
-STRIP      = strip
-POSTBUILD  = $(FLTKCONFIG) --post
-
-# libraries to link with:
-LDLIBS   = -lm
-LINKFLTK = $(shell $(FLTKCONFIG) --ldstaticflags)
-IMGLIB   = $(shell $(FLTKCONFIG) --use-images --ldstaticflags)
-GL_LIB   = $(shell $(FLTKCONFIG) --use-gl --ldstaticflags)
-
-# Other general settings
-CXX     = $(shell $(FLTKCONFIG) --cxx)
-CC      = $(shell $(FLTKCONFIG) --cc)
-
-# now we can make specific modifications based on the operating system and host
-UNAME := $(shell uname)
-
-NATIVESRCS=Fl_Native_File_Chooser.cxx \
-           Fl_Native_File_Chooser_WIN32.cxx \
-           Fl_Native_File_Chooser_MAC.cxx \
-           Fl_Native_File_Chooser_FLTK.cxx \
-           FL/Fl_Native_File_Chooser.H \
-           FL/Fl_Native_File_Chooser_WIN32.H \
-           FL/Fl_Native_File_Chooser_MAC.H \
-           FL/Fl_Native_File_Chooser_FLTK.H
-
-ifeq '$(OS)' "Windows_NT"
-EXE = .exe
-endif # end of WIN32 options
-
-ifeq ($(strip $(UNAME)),Linux)
-EXE = 
-endif # end of linux options
-
-ifeq ($(strip $(UNAME)),Darwin)
-EXE      =
-LDLIBS  += -framework CoreFoundation
-endif # end of OSX options
-
-#.SILENT: # Make the build run quietly
-
-all: test-browser$(EXE) simple-app$(EXE)
-
-#########################################################
-# make sure the basic rules are in place, just in case...
-# Build commands and filename extensions...
-.SUFFIXES: .c .cxx .cpp .cc .h .fl .o
-
-# Rule to build an object file from a C++ source file
-%.o : %.cxx
-	@echo Compile $@...
-	$(CXX) -c -o $@ $< $(CXXFLAGS)
-
-# Rule to build an object file from a C source file
-%.o : %.c
-	@echo Compile $@...
-	$(CC) -c -o $@ $< $(CFLAGS)
-
-#########################################################
-# define rules for the known targets...
-
-Fl_Native_File_Chooser.o: $(NATIVESRCS)
-	$(CXX) $(CXXFLAGS) $< -c
-
-test-browser.o: test-browser.cxx
-	$(CXX) $(CXXFLAGS) $< -c
-
-test-browser$(EXE): test-browser.o Fl_Native_File_Chooser.o
-	$(CXX) test-browser.o Fl_Native_File_Chooser.o $(IMGLIB) $(LDLIBS) -o $@
-	$(STRIP) $@
-	$(POSTBUILD) test-browser$(EXE)
-
-simple-app.o: simple-app.cxx
-	$(CXX) $(CXXFLAGS) $< -c
-
-simple-app$(EXE): simple-app.o Fl_Native_File_Chooser.o
-	$(CXX) simple-app.o Fl_Native_File_Chooser.o $(IMGLIB) $(LDLIBS) -o $@
-	$(STRIP) $@
-	$(POSTBUILD) simple-app$(EXE)
-
-# FORCE TARGET -- Do not remove
-FORCE:
-
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk1.MICROSOFT b/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk1.MICROSOFT
deleted file mode 100644
index 06c067a..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk1.MICROSOFT
+++ /dev/null
@@ -1,65 +0,0 @@
-###
-### FLTK1 MAKEFILE FOR MICROSOFT VS EXPRESS 8
-### This is Microsoft's native *free* compiler.
-###
-
-# Assumes FLTKDIR has been set by main Makefile.MICROSOFT
-
-# SUBSYSTEM
-#	"console" to see stdout/stderr, 
-#	"windows" to make regular windows app.
-#
-SUBSYSTEM=console
-
-# CHANGE THESE FLAGS AS NEEDED FOR YOUR COMPILER
-#   If unsure what to set these to, compile one of the FLTK test programs,
-#   and match these flags to those shown in the FLTK program's build log.
-#
-#   The default settings shown here are for "Visual Studio Express 8"
-#
-#    /MD = DYNAMIC: Multithreaded DLL; MSVCRT.DLL needed at runtime
-#    /MT = STATIC: Multithreaded; MSVCRT.LIB is used; no DLL needed at runtime
-#    /Wall = add for WAAAY too much info. Useful only if you grep out OS's errors!
-#    /W3   = somewhat verbose
-#
-CC=cl /MD /EHsc /DVS2000 /DVISUAL_STUDIO /D_CRT_SECURE_NO_DEPRECATE /D_WIN32
-CFLAGS= /I$(FLTKDIR) /I. /DFLTK1
-
-LIBS=/link $(FLTKDIR)/lib/fltk.lib \
-	wsock32.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib \
-	comdlg32.lib advapi32.lib shell32.lib winmm.lib ole32.lib oleaut32.lib \
-	uuid.lib imm32.lib /nologo /machine:I386
-
-NATIVESRCS=Fl_Native_File_Chooser.cxx \
-           Fl_Native_File_Chooser_WIN32.cxx \
-           FL/Fl_Native_File_Chooser.H \
-           FL/Fl_Native_File_Chooser_WIN32.H
-
-default: test-browser simple-app
-
-Fl_Native_File_Chooser.obj: $(NATIVESRCS)
-	$(CC) $(CFLAGS) /Tp Fl_Native_File_Chooser.cxx /c
-
-test-browser: test-browser.cxx Fl_Native_File_Chooser.obj
-	$(CC) $(CFLAGS) /Tp test-browser.cxx /c
-	$(CC) test-browser.obj Fl_Native_File_Chooser.obj $(LIBS) /subsystem:$(SUBSYSTEM)
-	-del $@.obj 2> nul
-
-simple-app: simple-app.cxx Fl_Native_File_Chooser.obj
-	$(CC) $(CFLAGS) /Tp simple-app.cxx /c
-	$(CC) simple-app.obj Fl_Native_File_Chooser.obj $(LIBS) /subsystem:$(SUBSYSTEM)
-	-del $@.obj 2> nul
-
-clean: FORCE
-	-del *.obj > NUL
-	-del *.pdb > NUL
-	-del *.ilk > NUL
-	-del *.idb > NUL
-	-del *.sln > NUL
-	-del *.suo > NUL
-	-del test-browser.exe > NUL
-	-del simple-app.exe > NUL
-
-# FORCE TARGET -- Do not remove
-FORCE:
-
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk2 b/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk2
deleted file mode 100644
index 8539e4b..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk2
+++ /dev/null
@@ -1,93 +0,0 @@
-# Makefile that uses fltkconfig
-# Submitted by Ian MacArthur.
-# NOTE: This makes use of new features in fltk-config 1.1.6: --cxx and --cc flags.
-#########################################################
-
-# Assumes FLTK2CONFIG has been set by main Makefile
-
-# flags for compiler:
-CFLAGS   = -Wall -O3 -I. $(shell $(FLTK2CONFIG) --cflags) -DFLTK2
-CXXFLAGS = -Wall -O3 -I. $(shell $(FLTK2CONFIG) --cxxflags) -DFLTK2
-
-# Possible steps after linking...
-STRIP      = strip
-POSTBUILD  = $(FLTK2CONFIG) --post
-
-# libraries to link with:
-LDLIBS   = -lm
-LINKFLTK = $(shell $(FLTK2CONFIG) --ldstaticflags)
-IMGLIB   = $(shell $(FLTK2CONFIG) --use-images --ldstaticflags)
-GL_LIB   = $(shell $(FLTK2CONFIG) --use-gl --ldstaticflags)
-
-# Other general settings
-CXX     = $(shell $(FLTK2CONFIG) --cxx)
-CC      = $(shell $(FLTK2CONFIG) --cc)
-
-# now we can make specific modifications based on the operating system and host
-UNAME := $(shell uname)
-
-NATIVESRCS=Fl_Native_File_Chooser.cxx \
-           Fl_Native_File_Chooser_WIN32.cxx \
-           Fl_Native_File_Chooser_MAC.cxx \
-           Fl_Native_File_Chooser_FLTK.cxx \
-           fltk/NativeFileChooser.h \
-           fltk/NativeFileChooser_WIN32.h \
-           fltk/NativeFileChooser_MAC.h \
-           fltk/NativeFileChooser_FLTK.h
-
-ifeq '$(OS)' "Windows_NT"
-EXE = .exe
-endif # end of WIN32 options
-
-ifeq ($(strip $(UNAME)),Linux)
-EXE = 
-endif # end of linux options
-
-ifeq ($(strip $(UNAME)),Darwin)
-EXE      =
-LDLIBS  += -framework CoreFoundation
-endif # end of OSX options
-
-#.SILENT: # Make the build run quietly
-
-all: test-browser-fltk2$(EXE) simple-app-fltk2$(EXE)
-
-#########################################################
-# make sure the basic rules are in place, just in case...
-# Build commands and filename extensions...
-.SUFFIXES: .c .cxx .cpp .cc .h .fl .o
-
-# Rule to build an object file from a C++ source file
-%.o : %.cxx
-	@echo Compile $@...
-	$(CXX) -c -o $@ $< $(CXXFLAGS)
-
-# Rule to build an object file from a C source file
-%.o : %.c
-	@echo Compile $@...
-	$(CC) -c -o $@ $< $(CFLAGS)
-
-#########################################################
-# define rules for the known targets...
-
-NativeFileChooser.o: $(NATIVESRCS)
-	$(CXX) $(CXXFLAGS) $< -c -o NativeFileChooser.o
-
-test-browser-fltk2.o: test-browser-fltk2.cxx
-	$(CXX) $(CXXFLAGS) $< -c
-
-test-browser-fltk2$(EXE): test-browser-fltk2.o NativeFileChooser.o
-	$(CXX) test-browser-fltk2.o NativeFileChooser.o $(IMGLIB) $(LDLIBS) -o $@
-	$(STRIP) $@
-	$(POSTBUILD) test-browser-fltk2$(EXE)
-
-simple-app-fltk2.o: simple-app-fltk2.cxx
-	$(CXX) $(CXXFLAGS) $< -c
-
-simple-app-fltk2$(EXE): simple-app-fltk2.o NativeFileChooser.o
-	$(CXX) simple-app-fltk2.o NativeFileChooser.o $(IMGLIB) $(LDLIBS) -o $@
-	$(STRIP) $@
-	$(POSTBUILD) simple-app-fltk2$(EXE)
-
-# FORCE TARGET -- Do not remove
-FORCE:
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk2.MICROSOFT b/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk2.MICROSOFT
deleted file mode 100644
index 08681e9..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile-fltk2.MICROSOFT
+++ /dev/null
@@ -1,62 +0,0 @@
-###
-### FLTK2 MAKEFILE FOR MICROSOFT VS EXPRESS 8
-### This is Microsoft's native *free* compiler.
-###
-
-# Assumes FLTK2DIR has been set by main Makefile.MICROSOFT
-
-# SUBSYSTEM
-#	"console" to see stdout/stderr, 
-#	"windows" to make regular windows app.
-#
-SUBSYSTEM=console
-
-# CHANGE THESE FLAGS AS NEEDED FOR YOUR COMPILER
-#   If unsure what to set these to, compile one of the FLTK test programs,
-#   and match these flags to those shown in the FLTK program's build log.
-#
-#   The default settings shown here are for "Visual Studio Express 8"
-#
-#    /MD = DYNAMIC: Multithreaded DLL; MSVCRT.DLL needed at runtime
-#    /MT = STATIC: Multithreaded; MSVCRT.LIB is used; no DLL needed at runtime
-#    /Wall = add for WAAAY too much info. Useful only if you grep out OS's errors!
-#    /W3   = somewhat verbose
-#
-CC=cl /EHsc /DVS2000 /DVISUAL_STUDIO /D_CRT_SECURE_NO_DEPRECATE
-CFLAGS= /I$(FLTK2DIR) /I. /DFLTK2
-
-LIBS=/link $(FLTK2DIR)/lib/fltk2.lib \
-	ws2_32.lib msimg32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib \
-	advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib
-
-NATIVESRCS=Fl_Native_File_Chooser.cxx \
-           Fl_Native_File_Chooser_WIN32.cxx \
-           fltk/NativeFileChooser.H \
-           fltk/NativeFileChooser_WIN32.H
-
-default: test-browser-fltk2 simple-app-fltk2
-
-NativeFileChooser.obj: $(NATIVESRCS)
-	$(CC) $(CFLAGS) /Tp Fl_Native_File_Chooser.cxx /c /FoNativeFileChooser.obj
-
-test-browser-fltk2: test-browser-fltk2.cxx NativeFileChooser.obj
-	$(CC) $(CFLAGS) /Tp test-browser-fltk2.cxx /c
-	$(CC) test-browser-fltk2.obj NativeFileChooser.obj $(LIBS) /subsystem:$(SUBSYSTEM)
-
-simple-app-fltk2: simple-app-fltk2.cxx NativeFileChooser.obj
-	$(CC) $(CFLAGS) /Tp simple-app-fltk2.cxx /c
-	$(CC) simple-app-fltk2.obj NativeFileChooser.obj $(LIBS) /subsystem:$(SUBSYSTEM)
-
-clean: FORCE
-	-del *.obj > NUL
-	-del *.pdb > NUL
-	-del *.ilk > NUL
-	-del *.idb > NUL
-	-del *.sln > NUL
-	-del *.suo > NUL
-	-del test-browser.exe > NUL
-	-del simple-app.exe > NUL
-
-# FORCE TARGET -- Do not remove
-FORCE:
-
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile.MICROSOFT b/Utilities/FLTK/Fl_Native_File_Chooser/Makefile.MICROSOFT
deleted file mode 100644
index 493945e..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/Makefile.MICROSOFT
+++ /dev/null
@@ -1,45 +0,0 @@
-###
-### Makefile for Windows - Fl_Native_File_Chooser
-###
-
-# CHANGE THESE PATHS AS NEEDED. (Comment out to disable)
-#          |
-#         \|/
-#          v
-FLTKDIR=C:/fltk-1.3.x-r6148
-FLTK2DIR=c:/fltk-2.x-svn
-
-all: FORCE
-ifneq ($(FLTKDIR),)
-	@echo ***
-	@echo *** FLTK1 BUILD
-	@echo ***
-	gmake -f Makefile-fltk1.MICROSOFT FLTKDIR=$(FLTKDIR)
-endif
-ifneq ($(FLTK2DIR),)
-	@echo ***
-	@echo *** FLTK2 BUILD ***
-	@echo ***
-	gmake -f Makefile-fltk2.MICROSOFT FLTK2DIR=$(FLTK2DIR)
-endif
-
-
-Fl_Native_File_Chooser.obj: FORCE
-	gmake -f Makefile-fltk1.MICROSOFT FLTKDIR=$(FLTKDIR) Fl_Native_File_Chooser.obj
-
-NativeFileChooser.obj: FORCE
-	gmake -f Makefile-fltk2.MICROSOFT FLTK2DIR=$(FLTK2DIR) NativeFileChooser.obj
-
-clean: FORCE
-	-del *.obj > NUL
-	-del *.pdb > NUL
-	-del *.ilk > NUL
-	-del *.idb > NUL
-	-del *.sln > NUL
-	-del *.suo > NUL
-	-del test-browser.exe > NUL
-	-del simple-app.exe > NUL
-
-# FORCE TARGET -- Do not remove
-FORCE:
-
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/README.txt b/Utilities/FLTK/Fl_Native_File_Chooser/README.txt
deleted file mode 100644
index fc9da1a..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/README.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-Fl_Native_File_Chooser -- Access platform's native file choosers in FLTK
-------------------------------------------------------------------------
-
-
-WHAT IS "Fl_Native_File_Chooser"?
-=================================
-
-    Fl_Native_File_Chooser is a 'widget' wrapper to access the
-    different platform's native file choosers. On platforms that
-    don't have a 'native' file chooser (linux), we use FLTK's own.
-
-    The purpose of this library is to make a consistent interface
-    for accessing the different native file choosers.
-
-    Tested under Linux, Mac OSX and Windows with fltk 1.1.6.
-    Tested under Linux with fltk 2.x.
-
-
-LICENSING
-=========
-
-    Fl_Native_File_Chooser comes with complete free source code. 
-    Fl_Native_File_Chooser is available under the terms of the 
-    GNU Library General Public License. See COPYING for more info.
-
-    Yes, it can be used in commercial software! Free! Imagine that.
-
-
-BUILD INSTRUCTIONS
-==================
-
-    1. Which version of FLTK?
-
-    Fl_Native_File_Chooser now supports fltk1 and fltk2 as of 0.83e.
-
-    Edit the Makefile and uncomment/modify the FLTKCONFIG and FLTK2CONFIG
-    variables as needed.
-    
-    If both variables are uncommented, both versions of
-    Fl_Native_File_Chooser will be built.
-
-    For instance, if you have both fltk1 and fltk2 installed on your
-    system, the top of your Makefile settings might look like:
-
-FLTKCONFIG=/usr/local/src/fltk-1.1.x-svn/fltk-config
-FLTK2CONFIG=/usr/local/src/fltk-2.0-svn/fltk2-config
-    
-    Then you can build both with just:
-
-	make
-
-   These test programs are created, depending on if you have
-   configured the above for fltk1, fltk2, or both:
-
-       	./test-browser            -- fltk1 exerciser demo
-	./simple-app              -- fltk1 simple app
-
-       	./test-browser-fltk2      -- fltk2 exerciser demo
-	./simple-app-fltk2        -- fltk2 simple app
-
-   Originally Fl_Native_File_Chooser was designed for FLTK1, 
-   so there may be some left over FLTK1 specific references
-   in the docs. Please report these as bugs (see below)
-
-
-PLATFORM SPECIFIC NOTES
-=======================
-
-   For linux and osx the default compilers are used.
-
-   For Windows, tested with VS Express 8 + make.bat / Makefile.MICROSOFT.
-   Ian confirmed it compiled OK under Windows with mingw using the default
-   unix Makefile.
-
-
-WHERE'S THE DOCUMENTATION?
-==========================
-
-    ./documentation/index.html
-
-
-HOW DO I LINK Fl_Native_File_Chooser INTO MY OWN APPLICATION?
-=============================================================
-
-    ./documentation/how-to-use.html
-
-
-FILE LAYOUT
-===========
-
-    ./Makefile                 -- main Makefile for unix builds
-    ./Makefile.MICROSOFT       -- main Makefile for native Microsoft builds
-
-    ./documentation/index.html -- public documentation for fltk1 + fltk2
-
-    ./FL                       \__ fltk1 include files and lib
-    ./Fl_Native_File_Chooser.o /   (for your app to include and link)
-
-    ./fltk                     \__ fltk2 include files and lib
-    ./NativeFileChooser.o      /   (for your app to include and link)
-
-    ./reference                 -- project's reference docs (internal use)
-
-    *_FLTK.{cxx,H,h}            -- Platforms that don't have native choosers
-    *_MAC.{cxx,H,h}             -- Mac platform specific source code
-    *_WIN32.{cxx,H,h}           -- Windows platform specific source code
-
-
-RELEASE NOTES/VERSION INFORMATION
-=================================
-    
-    See ./CHANGES.
-
-
-BUGS? FEATURE REQUESTS?
-=======================
-    
-    Send bugs and RFE's to erco at seriss dot com
-
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/TODO b/Utilities/FLTK/Fl_Native_File_Chooser/TODO
deleted file mode 100644
index 2a11d78..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/TODO
+++ /dev/null
@@ -1,318 +0,0 @@
-> Under OSX, the 'simple-app' program can't open up the file browser
-  with the preset_file() selected in the browser. WHY??
-  It selects the dir ok, but not the file.
-
-> Christophe points out differences with FLTK's API:
-
-    * type enums are different (Fl_File_Chooser::MULTI vs. Fl_Native_File_Chooser::BROWSE_MULTI_FILE)
-      SOLUTION: mark old names legacy, implement FLTK's names as alternate, modify docs.
-
-    * show() works differently (Native's show() blocks)
-      SOLUTION: Meh, not sure there is one, native choosers have to block.
-
-    * filters have slightly different syntax ("type (*.ext)\t" vs.  "type\t*.ext\n")
-      SOLUTION: Might be as simple as just ignoring parens around filter when specified.
-                Document FLTK's syntax, and indicate old syntax is legacy.
-
-    * filename() is indexed from 0 instead of 1
-    * filename() should be changed to value()
-
-      SOLUTION: Kill above two birds with one stone:
-                Mark filename() as obsolete/legacy in docs, keep method code.
-                Implement value(int) and friends to replace filename(),
-                making sure value(int) is 1 based. Make docs and for() loop
-		example 1 based.
-   
-> Christophe points out that adding but->shortcut(FL_META+'o');
-  to simple-app.cxx causes FLTK/MAC to theink the meta key is still down
-  after invoking the short cut, then cancelling out of the chooser.
-  (Just hitting 'o' after the chooser closes will re-open the browser)
-
-  Probably the native chooser for MAC/Leopard is eating the keyup
-  events. Had christophe repost question to fltk.general on 01/07/08.
-
-  CHECK HISTORY TO SEE IF THIS WAS SOLVED.
-
-> Add an option to control enable/disable of 'New Folder' button on Mac.
-  See:
-	_keepstate = kNavDontNewFolderState;
-
-  ..in the file Fl_Native_File_Chooser_MAC.cxx. Maybe change that to:
-  	     if ( ! ( _options & NEW_FOLDER ) ) {
-		 _keepstate |= kNavDontNewFolderState;
-	     }
-
-> Determine why WIN32 and OSX don't open browser with preset file selected.
-
-  09/04/2009 MAC: It is years later, and I still can't figure this out.
-              Several sources on the net say the pathname can only
-	      be a directory, not a filename for preselect to work.
-
-  XX/XX/XXXX WIN: tried to make this work, but it just doesn't support it!
-           Even calling GetOpenFileName(&_ofn); twice in a row.
-
-
-
-	    ### NOT SURE ###			### NOT SURE ###
-	    ### NOT SURE ###			### NOT SURE ###
-	    ### NOT SURE ###			### NOT SURE ###
-
-
-
-(?) > 0.83d: WINDOWS/FILE BROWSE: 
-(?) 	If simple-app's preset filename doesn't end in a backslash,
-(?)     browser shows contents of parent dir, not dir itself.
-(?) 	Maybe append a slash if stat() shows preset filename is a DIR?
-
--- 0.82c --
-
-
-(?) > 0.82c: Windows "Save As" is not setting correct directory in browser
-
-
-(?) > 0.82: Andreas reports problem with Mac chooser not showing thumbnails
-(?)         that live on remote drives even though the Finder does. 
-(?)         Files located on the local file system show up OK.
-(?)         (See Reference #1 below for Apple's SimpleText.c excerpts?)
-(?)         Also, see Andreas' email 12/05/2005 (Reference #2 below)
-
-(?) > 0.82: Presetting value() under linux causes chooser to open with file 
-(?)         highlighted in the chooser, but not in windows or mac.
-
-(?) > 0.82: Fl_Native_File_Chooser: WINDOWS doesn't handle returning UTF8 from
-(?)         native windows file chooser.. comes back as garbage, possibly as non-UTF8?
-(?)         (Found problem on Japanese localized machine by browsing to a dir
-(?)         with Japanese chars. Shows OK in windows browser, but when returned
-(?)         to Fl_Input, comes up as garbage, even though the Fl_Input is capable
-(?)         of showing text correctly if japanese text pasted as text into the 
-(?)         Fl_Input from Windows URL input)
-
-
-	    #### DONE ####			    #### DONE ####
-	    #### DONE ####			    #### DONE ####
-	    #### DONE ####			    #### DONE ####
-
-> 0.84: Ian MacArthur indicated mingw warns about strapp and strdump
-	being "defined but not used" cause it's a static. Should
-	probably make a lib, disable this warning, or reference 
-	the calls in an unused subroutine.
-
-> 0.83d: Namespace pollution: Yuri wants Carbon.h/win32.h
-  to not be in the public .H files.  Can probably make an 'underbar'
-  version of the class to isolate them.  See erco's post on 
-  fltk.general 06/24/07.
-
-> 0.83d: MAC / Save File:
-  If:
-      1) /tmp/foo.xxx exists
-      2) Directory: set to /tmp
-      3) Preset File set to foo.xxx
-  ..when browser opens, foo.xxx is GRAYED OUT, even though filter
-  appears to be on. Can still click on grayed out items to pick them,
-  and Save As: name changes. Weird!
-  Looks OK when 'Single File' is selected.
-*** DONE ***
-(DONE) > 0.82c: "Save As" + "Show Confirm Dialog" is not showing the confirm dialog..!
-(DONE)          TESTED ON LINUX AND OSX TO WORK OK.
-
-(DONE) > 0.83c: Shane Hill on 02/07/06 reports that under Windows, doing regular
-(DONE)   file browsing results in the current working dir being changed.
-(DONE)   Luckily there appears to be a WIN32 flag for this, but the docs
-(DONE)   say it's ineffective..!?
-(DONE)     OFN_NOCHANGEDIR
-(DONE) 	Restores the current directory to its original value if the user changed
-(DONE) 	the directory while searching for files.
-(DONE) 	Windows NT 4.0/2000/XP: This flag is ineffective for GetOpenFileName.
-(DONE) 				^^^^^^^^^^^^^^^^^^^^^^^^
-
-(DONE) > 0.82: Alessandro: uses very long wildcard strings..
-(DONE)         Replace fixed arrays (char wildcard[80]) with new strapp() stuff.
-
-------------------------------------------------------------------------
-				Reference #1
-------------------------------------------------------------------------
-
-	// REFERENCE FROM SimpleText.c for erco..
-
-	short		numTypes;
-	OSType		typeList[20];
-	OSType		fileType = '\?\?\?\?';
-	NavDialogRef	navDialog;
-
-	DetermineWindowTypeOrOpen( nil, fileType, &typeList[0], &numTypes, nil );
-	
-	// Open as many documents as the user wishes through Appleevents
-	return OpenFileDialog( 'ttxt', numTypes, typeList, &navDialog );
-
-	    OSType	typeList[20];
-	    OSType	docList[20];
-
-		    pFileTypes[*numTypes]	= 'MooV';
-		    pDocumentTypes[*numTypes] 	= kMovieWindow;
-		    (*numTypes)++;
-
-
-OSStatus OpenFileDialog(
-	OSType applicationSignature, 
-	short numTypes, 
-	OSType typeList[], 
-	NavDialogRef *outDialog )
-{
-	OSStatus theErr = noErr;
-	if ( gOpenFileDialog == NULL )
-	{
-		NavDialogCreationOptions	dialogOptions;
-		NavTypeListHandle		openList = NULL;
-	
-		NavGetDefaultDialogCreationOptions( &dialogOptions );
-	
-		dialogOptions.modality = kWindowModalityNone;
-		dialogOptions.clientName = CFStringCreateWithPascalString( 
-						NULL, LMGetCurApName(), GetApplicationTextEncoding());
-		
-		openList = (NavTypeListHandle)NewOpenHandle( applicationSignature, numTypes, typeList );
-		
-		theErr = NavCreateGetFileDialog( &dialogOptions, openList,
-		                                 GetPrivateEventUPP(),
-						 NULL, NULL, NULL, &gOpenFileDialog );
-
-------------------------------------------------------------------------
-				Reference #2
-------------------------------------------------------------------------
-
-Andreas Schömann wrote:
-> Greg Ercolano wrote:
->
->> Andreas Schömann wrote:
->>
->>> I've found a problem: when loading images (jpg) via network, no thumbnail is shown in the file chooser. Actual loading works. The network device is NTFS formatted. I thought it might be an access rights problem, but with 'Finder' it works fine...
-
-    BTW, Andreas is specifically referring to the MAC file browser;
-    when you have it in 'column' mode, when you highlight eg. a jpg
-    image, the preview that normally displays off to the right
-    doesn't show up.
-
-    I looked at the SimpleText.c code that comes with the OSX
-    developer toolkit, ie:
-    /Developer//Examples/Carbon/SimpleText/*
-
-    ..and it looks like they use a few options to NavCreateGetFileDialog()
-    that I don't use, namely arg2 and arg3 to set a list of files
-    and a callback.
-
-    I have to admit I don't fully understand the Mac stuff when it
-    comes to this sort of thing. Apparently there's a global database
-    somewhere of 4 character file types that dates back to the 1980's,
-    and it appears one needs to know these names and hard code them
-    into your app (as is done in SimpleText.cxx).
-
-    I think I'll leave this unfinished, since it's not really a show
-    stopper, and I'm not sure how to make it work correctly.
-
-> 4) Here on my machine Fl_Native_File_Chooser displays a preview for _local_ images (e.g. .jpeg, .tiff and .png) 
-
-    Really?
-
-    I actually couldn't get that to work on my 10.4.3 box.
-
-    When I single click on a jpeg, png, or other image format,
-    it shows a generic image, but the correct text info about
-    the image's file type.
-
-    What does work is if I click on .c or .cxx files it shows
-    correctly, and if I click on a .rm file (Real Media),
-    it shows Real's icon logo.. (shrug)
-
-    In the Finder, when you click on images, it shows a thumbnail
-    of the actual image.
-
-> Hmmmh, somewhat confusing results...
-> Especially the different behaviour of Finder and File Chooser is a mystery to me. Why did Apple do that? Maybe this has changed with Tiger?
-> 1) and 2) tell me that one can disable file preview with 'Navigation Services', though probably not by intention.
-
-    It might be I'm missing some args to NavCreateGetFileDialog()
-    (arg2 and 3?) Unfortunately I'm not sure what is the correct
-    code to make that work, if that's even the cause.
-
-    Or maybe I need to link in some apple framework that's missing
-    to make that stuff work.
-
-> I also had a look into the documentation ( http://developer.apple.com/documentation/Carbon/Conceptual/ProvidingNavigationDialogs/index.html ) and it says that 'Navigation Services' offers to specify a 'preview callback' with 'NavCreateGetFileDialog'. This is called when the user selects a file and offers a way to preview custom file types. But Fl_Native_File_Chooser does not use this feature and in that case 'Navigation Services' inspects the file.
-
-    Right, as described above.
-    However, I'd think there'd be defaults for things like jpeg/png/etc.
-
-    I'd hate to think I have to manually provide callbacks for each
-    image type..!
-
-------------------------------------------------------------------------
-				Reference #3
-------------------------------------------------------------------------
-
--- 0.86 --
-
-> (DONE -- 0.86) ADDITIONS REQUESTED BY MANOLO OCT 08 2008
-
-    Hi Greg,
-
-    I have been using your Fl_Native_File_Chooser with general satisfaction
-    but had to make 3 changes in Fl_Native_File_Chooser_MAC.cxx for it to
-    suit my needs, and would like to present them to you.
-
-    1) using a BROWSE_SAVE_FILE displays the list of file formats as set by the
-    filter member function plus a "Default" format that I wanted
-    to get rid of.  The solution to that is to put kNavGenericSignature
-    as 3rg argument of the NavCreatePutFileDialog call in your		<-- (DONE 0.86)
-    post() function.  Because the initially selected file format
-    can be controlled by the filter_value member function, I don't
-    see what can be the purpose of having a Default format in
-    addition to a programmable set of formats. Furthermore, presence
-    of the Default format renders the call to filter_value ignored
-    by the navigation dialog window.  Thus, I would think that using
-    this kNavGenericSignature argument would benefit
-    Fl_Native_Fie_Chooser_MAC without loss of functionality.
-    Alternatively, an accessor function to the 3rd argument of the
-    NavCreatePutFileDialog call would be helpful.
-
-    2) using a BROWSE_SAVE_FILE, with a call to the preset_file member function,
-    often fails to correctly display the desired preset filename in the navigation
-    dialog. This happens in your event_handler function, case kNavCBStart, that
-    attempts to get the FSSpec of the preset file and fails because this file
-    does not exist yet.  I thus changed the 1st statement of the kNavCBStart 
-    clause as follows:
-		if ( nfb->directory() /* || nfb->preset_file() */) {	<-- (DONE 0.86)
-
-    3) the preset_file member function does not work correctly with 
-    non-ascii containing filenames. This is easily repaired, without
-    side effect, using kCFStringEncodingUTF8 instead of			<-- (DONE 0.86)
-    kCFStringEncodingASCII in the statement just before the
-    NavDialogSetSaveFileName call.
-
-    I take this opportunity to mention to you my XCode plug-in that
-    fully drives a Win32 C/C++ cross-compiler within Apple's Xcode
-    development environment:
-    http://pbil.univ-lyon1.fr/members/mgouy/XCodeWin32Plugin/
-
-    Many thanks for your Fl_Native_Fie_Chooser,
-    and best wishes,
-
-> (DONE -- 0.86) Walter Garms points out mapped network shares (eg. Z:) don't show up
-  in 'BROWSE_DIRECTORY' mode unless the code is modified. See emails 
-  dated 05/12/2008:
-
-    --- Garms, Walter (GE EntSol, Security) wrote:
-    With your help I was able to solve the problem of the network drives. 
-    For Version 6.0, at least, the BIF_SHAREABLE flag seems to have the
-    opposite sense:  With BIF_SHAREABLE not set I see the mapped network
-    drives, and with BIF_SHAREABLE set I do not. 
-    ---
-
-    ie. he removed BIF_SHAREABLE from this section:
-
-    #if defined(BIF_NONEWFOLDERBUTTON)                              // Version 6.0
-	if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags |= BIF_NONEWFOLDERBUTTON;
-	_binf.ulFlags |= BIF_USENEWUI | BIF_SHAREABLE | BIF_RETURNONLYFSDIRS;
-					^^^^^^^^^^^^^
-    #elif defined(BIF_USENEWUI)  
-
-
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/common.cxx b/Utilities/FLTK/Fl_Native_File_Chooser/common.cxx
deleted file mode 100644
index efde487..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/common.cxx
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-// common.cxx -- common string subs for Fl_Native_File_Chooser
-//
-// Copyright 2004 by Greg Ercolano.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-// Please keep code 80 column compliant.
-//
-//      10        20        30        40        50        60        70
-//       |         |         |         |         |         |         |
-// 4567890123456789012345678901234567890123456789012345678901234567890123456789
-//
-
-#include <string.h>
-
-// COPY A STRING WITH 'new'
-//    Value can be NULL
-//
-static char *strnew(const char *val) {
-    if ( val == NULL ) return(NULL);
-    char *s = new char[strlen(val)+1];
-    strcpy(s, val);
-    return(s);
-}
-
-// FREE STRING CREATED WITH strnew(), NULLS OUT STRING
-//    Value can be NULL
-//
-static char *strfree(char *val) {
-    if ( val ) delete [] val;
-    return(NULL);
-}
-
-// 'DYNAMICALLY' APPEND ONE STRING TO ANOTHER
-//    Returns newly allocated string, or NULL 
-//    if s && val == NULL.
-//    's' can be NULL; returns a strnew(val).
-//    'val' can be NULL; s is returned unmodified.
-//
-//    Usage:
-//	char *s = strnew("foo");	// s = "foo"
-//      s = strapp(s, "bar");		// s = "foobar"
-//
-static char *strapp(char *s, const char *val) {
-    if ( ! val ) {
-        return(s);              // Nothing to append? return s
-    }
-    if ( ! s ) {
-        return(strnew(val));    // New string? return copy of val
-    }
-    char *news = new char[strlen(s)+strlen(val)+1];
-    strcpy(news, s);
-    strcat(news, val);
-    delete [] s;		// delete old string
-    return(news);		// return new copy
-}
-
-// APPEND A CHARACTER TO A STRING
-//     This does NOT allocate space for the new character.
-//
-static void chrcat(char *s, char c) {
-    char tmp[2] = { c, '\0' };
-    strcat(s, tmp);
-}
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/Fl_Native_File_Chooser.html b/Utilities/FLTK/Fl_Native_File_Chooser/documentation/Fl_Native_File_Chooser.html
deleted file mode 100644
index 7978660..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/Fl_Native_File_Chooser.html
+++ /dev/null
@@ -1,361 +0,0 @@
-<html>
-<head>
-<title>[Fltk-1.x] Fl_Native_File_Chooser</title>
-</head>
-<body>
-<H1>[Fltk-1.x] Fl_Native_File_Chooser</H1>
-
-<h2>class Fl_Native_File_Chooser</a></h2>
-<!--
-<h3>Class Hierarchy</h3>
-<ul>
-  <pre>
-  Fl_Native_File_Chooser
-  </pre>
-</ul>
--->
-
-<h3>Include Files</h3>
-<ul>
-  <pre>
-  #include <FL/Fl_Native_File_Chooser.H>
-  </pre>
-</ul>
-Dowload latest source from <a href="http://seriss.com/people/erco/fltk/Fl_Native_File_Chooser/">here</a>.
-<br>
-<h3>Description</h3>
-This class lets an FLTK application easily and consistently access
-the local operating system's native file chooser. Some operating systems
-have very complex and specific file choosers that many users want access
-to specifically, instead of FLTK's default file chooser(s).
-<p>
-<h3>Methods</h3>
-<center>
-<table width="90%" summary="Fl_Native_File_Chooser methods">
-<tr><td align="left" valign="top">
-<ul>
-  <li> <a href="#Fl_Native_File_Chooser">Fl_Native_File_Chooser</a>
-  <li> <a href="#~Fl_Native_File_Chooser">~Fl_Native_File_Chooser</a>
-  <li> <a href="#count">count</a>
-</ul>
-</td><td align="left" valign="top">
-<ul>
-  <li> <a href="#directory">directory</a>
-  <li> <a href="#errmsg">errmsg</a>
-  <li> <a href="#filename">filename</a>
-</ul>
-</td><td align="left" valign="top">
-<ul>
-  <li> <a href="#filter">filter</a>
-  <li> <a href="#filter_value">filter_value</a>
-  <li> <a href="#filters">filters</a>
-</ul>
-</td><td align="left" valign="top">
-<ul>
-  <li> <a href="#options">options</a>
-  <li> <a href="#preset_file">preset_file</a>
-  <li> <a href="#show">show</a>
-</ul>
-</td><td align="left" valign="top">
-<ul>
-  <li> <a href="#title">title</a>
-  <li> <a href="#type">type</a>
-</ul>
- <br>
- <br>
-</td> </tr> </table>
-</center>
-
-<h4><a name="Fl_Native_File_Chooser">
-Fl_Native_File_Chooser::Fl_Native_File_Chooser()<br>
-Fl_Native_File_Chooser::Fl_Native_File_Chooser(type)
-</h4>
-<ul>
-    The constructor for the Fl_Native_File_Chooser.
-    <p>
-    If the optional <tt>type</tt> is not specified,
-    BROWSE_FILE (browse to open a file) is assumed.  
-    The type can also be set later with <a href="#type">type()</a>.
-</ul>
-
-<h4><a name="~Fl_Native_File_Chooser">
-Fl_Native_File_Chooser::~Fl_Native_File_Chooser()
-</h4>
-<ul>
-    The destructor; destroys any resources allocated to this widget.
-</ul>
-
-<h4>
-<a name="count"></a>
-int Fl_Native_File_Chooser::count() const
-</h4>
-<ul>
-    Returns the number of filenames (or directory names) the user
-    selected. These are zero-indexed. 
-    See this example of <a href="#multi_example">how to retrieve
-    multiple filenames</a>.
-</ul>
-
-
-<h4>
-<a name="directory"></a>
-void Fl_Native_File_Chooser::directory(const char*)<br>
-const char* Fl_Native_File_Chooser::directory() const;<br>
-</h4>
-<ul>
-    Sets the directory with which to start the chooser.
-    If NULL is passed, or if no directory is specified,
-    the chooser will attempt to use the last non-cancelled folder.<br>
-</ul>
-
-<h4>
-<a name="errmsg"></a>
-const char *Fl_Native_File_Chooser::errmsg() const<br>
-</h4>
-<ul>
-    Returns a system dependent error message for the last
-    method that failed. This message should at least be flagged
-    to the user in a dialog box, or to some kind of error log.
-</ul>
-
-<h4>
-<a name="filename"></a>
-const char *Fl_Native_File_Chooser::filename() const<br>
-const char *Fl_Native_File_Chooser::filename(int) const<br>
-</h4>
-<ul>
-    The first form returns the single filename selected
-    by the user from the browser. (In a multiple browser
-    context, this returns the first filename the user selected).
-    <p>
-    The second form should be used to return multiple filenames,
-    and is normally used inside a loop to retrieve all the files
-    the user selected, eg:
-    <p>
-    <a name="multi_example">
-    <pre>
-        if ( <b>chooser->show()</b> == 0 ) {
-            // HANDLE MULTIPLE FILENAMES
-            for (int n = 0; n < <b>chooser->count()</b>; n++ ) {
-      	        fprintf(stderr, "%d) '%s'\n", n, <b>chooser->filename(n)</b>);
-            }
-	}
-    </pre>
-    You can preset the directory with 
-    <a href="#directory">directory()</a> method, and the filename using the
-    <a href="#preset_file">preset_file()</a> method.<br>
-</ul>
-
-<h4>
-<a name="filter"></a>
-const char *Fl_Native_File_Chooser::filter() const<br>
-void Fl_Native_File_Chooser::filter(const char*)
-</h4>
-<ul>
-    Gets or sets the filename filters used for browsing.
-    The default is NULL, which browses all files.
-    <p>
-    The filter string can be any of:
-    <p>
-    <ul>
-        <li> A single wildcard (eg. "*.txt")
-	     </li>
-	<li> Multiple wildcards (eg. "*.{cxx,h,H})
-	     </li>
-	<li> A descriptive name followed by a '\t' and a wildcard
-	     (eg. "Text Files\t*.txt")
-	     </li>
-	<li> A list of separate wildcards with a \n between each (eg. "*.{cxx,H}\n*.txt")
-	     </li>
-	<li> A list of descriptive names and wildcards 
-	     (eg. "C++ Files\t*.{cxx,H}\nTxt Files\t*.txt")
-	     </li>
-    </ul>
-    <p>
-    The format of each filter is a wildcard, or an optional
-    user description followed by '\t' and the wildcard.
-    <p>
-    On most platforms, each filter is available to the user
-    via a pulldown menu in the file chooser. The 'All Files'
-    option is always available to the user.
-</ul>
-
-<h4>
-<a name="filter_value"></a>
-void Fl_Native_File_Chooser::filter_value(int)<br>
-int Fl_Native_File_Chooser::filter_value()<br>
-</h4>
-<ul>
-    The first form sets which filter will be initially selected.<br>
-    The second returns which filter was chosen. This is only valid
-    if the chooser returns success.<br>
-    <p>
-    The first filter is indexed as 0. If filter_value()==filters(),
-    then "All Files" was chosen. If filter_value() > filters(), then
-    a custom filter was set.<br>
-</ul>
-
-<h4>
-<a name="filters"></a>
-int Fl_Native_File_Chooser::filters()<br>
-</h4>
-<ul>
-    Gets how many filters were available, not including "All Files"
-</ul>
-
-<h4>
-<a name="options"></a>
-void Fl_Native_File_Chooser::options(int)<br>
-int Fl_Native_File_Chooser::options()<br>
-</h4>
-<ul>
-    Sets/gets the platform specific chooser options.
-    <p>
-    Some platforms have file choosers with specific functions
-    that can be enabled/disabled via this method.
-    <p>
-    Flags can be ORed together to enable several features. Flags currently supported:
-    <p>
-    <center><table cellpadding=3>
-        <tr><td BGCOLOR=#8888cc align=left>Flag          </td><td BGCOLOR=#8888cc>Description                                                        </td><td BGCOLOR=#8888cc>Win</td><td BGCOLOR=#8888cc>Mac</td><td BGCOLOR=#8888cc>Other</td></tr>
-        <tr><td BGCOLOR=#dddddd align=left><tt>Fl_Native_File_Chooser::SAVEAS_CONFIRM</td><td BGCOLOR=#dddddd>With a BROWSE_SAVEAS chooser, prompts a confirmation if file exists</td><td BGCOLOR=#dddddd>Ignored </td><td BGCOLOR=#88dd88>Used   </td><td BGCOLOR=#dddddd>Ignored</td></tr>
-        <tr><td BGCOLOR=#dddddd align=left><tt>Fl_Native_File_Chooser::NEW_FOLDER    </td><td BGCOLOR=#dddddd>Shows the 'New Folder' button                                      </td><td BGCOLOR=#dddddd>Ignored </td><td BGCOLOR=#88dd88>Used</td><td BGCOLOR=#88dd88>Used</td></tr>
-        <tr><td BGCOLOR=#dddddd align=left><tt>Fl_Native_File_Chooser::PREVIEW       </td><td BGCOLOR=#dddddd>Enables the 'Preview' mode by default                              </td><td BGCOLOR=#dddddd>Ignored </td><td BGCOLOR=#dddddd>Ignored</td><td BGCOLOR=#88dd88>Used</td></tr>
-    </table></center>
-</ul>
-
-<h4>
-<a name="preset_file"></a>
-void Fl_Native_File_Chooser::preset_file(const char*)<br>
-const char* Fl_Native_File_Chooser::preset_file()<br>
-</h4>
-<ul>
-    Sets a default filename for the chooser. 
-    (Use <a href="#directory">directory()</a> to set the default directory)
-    <br>
-    Mainly used to preset the filename for save dialogs, 
-    and on most platforms can be used for opening files as well.
-</ul>
-
-<h4>
-<a name="show"></a>
-int Fl_Native_File_Chooser::show() const<br>
-</h4>
-<ul>
-    Opens the current file chooser on the screen. This method
-    will block until the user has chosen something, or cancelled.
-    <p>
-    Return value:
-    <ul type=disc>
-        <li> 0 - user picked a file, filename() will have the result
-        <li> 1 - user hit 'cancel'
-        <li>-1 - failed; <a href="#errmsg">errmsg()</a> has reason
-    </ul>
-</ul>
-
-<h4>
-<a name="title"></a>
-const char *Fl_Native_File_Chooser::title() const<br>
-void Fl_Native_File_Chooser::title(const char*)
-</h4>
-<ul>
-    Gets or sets the title of the file chooser's window.
-    <p>
-    The default title varies according to the platform, so you
-    are advised to set the title explicitly.
-</ul>
-
-<h4><a name="type"></a>
-int Fl_Native_File_Chooser::type() const<br>
-Fl_Native_File_Chooser::type(int)
-</h4>
-<ul>
-    Gets or sets the current type of browser. Possible choices are:
-    <p>
-    <center><table cellpadding=3>
-        <tr>
-	  <td BGCOLOR=#8888cc align=left>Flag</td>
-	  <td BGCOLOR=#8888cc>Description</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>Fl_Native_File_Chooser::BROWSE_FILE</td>
-	  <td BGCOLOR=#dddddd>Browse for a single file</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>Fl_Native_File_Chooser::BROWSE_DIRECTORY</td>
-	  <td BGCOLOR=#dddddd>Browse for a single directory</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>Fl_Native_File_Chooser::BROWSE_MULTI_FILE</td>
-	  <td BGCOLOR=#dddddd>Browse for multiple files</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY</td>
-	  <td BGCOLOR=#dddddd>Browse for multiple directories (implementation varies)</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>Fl_Native_File_Chooser::BROWSE_SAVE_FILE</td>
-	  <td BGCOLOR=#dddddd>Browse to save a single file</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY</td>
-	  <td BGCOLOR=#dddddd>Browse for a directory, allowing creation</td>
-        </tr>
-    </table></center>
-    <p>
-    These may be changed in future versions of Fl_Native_File_Chooser.
-</ul>
-
-<h3>Typical Usage</h3>
-<ul>
-    <pre>
-#include <Fl_Native_File_Chooser.H>
-:
-Fl_Native_File_Chooser *chooser = <b>new Fl_Native_File_Chooser</b>();
-<b>chooser->type</b>(Fl_Native_File_Chooser::BROWSE_FILE);   <i>// let user browse a single file</i>
-<b>chooser->title</b>("Open a file");                        <i>// optional title</i>
-<b>chooser->preset_file</b>("/var/tmp/somefile.txt");        <i>// optional filename preset</i>
-<b>chooser->filter</b>("Text Files\t*.txt");                 <i>// optional filter</i>
-switch ( <b>chooser->show</b>() ) {
-    case -1:    // ERROR
-	fprintf(stderr, "*** ERROR show() failed:%s\n", <b>chooser->errmsg</b>());
-	break;
-    case 1:     // CANCEL
-	fprintf(stderr, "*** CANCEL\n");
-	break;
-    default:    // USER PICKED A FILE
-        fprintf(stderr, "Filename was '%s'\n", <b>chooser->filename</b>());
-	break;
-}
-<p><hr><p>
-<b>// EXAMPLE 'SAVEAS' FILE BROWSER</b>
-#include <Fl_Native_File_Chooser.H>
-:
-Fl_Native_File_Chooser *chooser = <b>new Fl_Native_File_Chooser</b>();
-<b>chooser->type</b>(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);   <i>// 'saveas' browser</i>
-<b>chooser->title</b>("Save As..");                               <i>// optional title for chooser window</i>
-<b>chooser->directory</b>("/var/tmp");                            <i>// optional starting directory</i>
-<b>chooser->preset_file</b>("untitled.txt");                      <i>// optional default filename</i>
-<b>chooser->filter</b>("Text Files\t*.txt");                      <i>// optional filter</i>
-switch ( <b>chooser->show</b>() ) {
-    case -1:    // ERROR
-	fprintf(stderr, "*** ERROR show() failed:%s\n", <b>chooser->errmsg</b>());
-	break;
-    case 1:     // CANCEL
-	fprintf(stderr, "*** CANCEL\n");
-	break;
-    default:    // USER PICKED A FILE
-        fprintf(stderr, "Filename was '%s'\n", <b>chooser->filename</b>());
-	break;
-}
-    </pre>
-</ul>
-
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-
-</body>
-</html>
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/NativeFileChooser.html b/Utilities/FLTK/Fl_Native_File_Chooser/documentation/NativeFileChooser.html
deleted file mode 100644
index 002424e..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/NativeFileChooser.html
+++ /dev/null
@@ -1,361 +0,0 @@
-<html>
-<head>
-<title>[Fltk-2.x] NativeFileChooser</title>
-</head>
-<body>
-<H1>[Fltk-2.x] NativeFileChooser</H1>
-
-<h2>class fltk::NativeFileChooser</a></h2>
-<!--
-<h3>Class Hierarchy</h3>
-<ul>
-  <pre>
-  NativeFileChooser
-  </pre>
-</ul>
--->
-
-<h3>Include Files</h3>
-<ul>
-  <pre>
-  #include <fltk/NativeFileChooser.h>
-  </pre>
-</ul>
-Dowload latest source from <a href="http://seriss.com/people/erco/fltk/Fl_Native_File_Chooser/">here</a>.
-<br>
-<h3>Description</h3>
-This class lets an FLTK2 application easily and consistently access
-the local operating system's native file chooser. Some operating systems
-have very complex and specific file choosers that many users want access
-to specifically, instead of FLTK2's default file chooser(s).
-<p>
-<h3>Methods</h3>
-<center>
-<table width="90%" summary="fltk::NativeFileChooser methods">
-<tr><td align="left" valign="top">
-<ul>
-  <li> <a href="#NativeFileChooser">NativeFileChooser</a>
-  <li> <a href="#~NativeFileChooser">~NativeFileChooser</a>
-  <li> <a href="#count">count</a>
-</ul>
-</td><td align="left" valign="top">
-<ul>
-  <li> <a href="#directory">directory</a>
-  <li> <a href="#errmsg">errmsg</a>
-  <li> <a href="#filename">filename</a>
-</ul>
-</td><td align="left" valign="top">
-<ul>
-  <li> <a href="#filter">filter</a>
-  <li> <a href="#filter_value">filter_value</a>
-  <li> <a href="#filters">filters</a>
-</ul>
-</td><td align="left" valign="top">
-<ul>
-  <li> <a href="#options">options</a>
-  <li> <a href="#preset_file">preset_file</a>
-  <li> <a href="#show">show</a>
-</ul>
-</td><td align="left" valign="top">
-<ul>
-  <li> <a href="#title">title</a>
-  <li> <a href="#type">type</a>
-</ul>
- <br>
- <br>
-</td> </tr> </table>
-</center>
-
-<h4><a name="NativeFileChooser">
-fltk::NativeFileChooser::NativeFileChooser()<br>
-fltk::NativeFileChooser::NativeFileChooser(type)
-</h4>
-<ul>
-    The constructor for the fltk::NativeFileChooser.
-    <p>
-    If the optional <tt>type</tt> is not specified,
-    BROWSE_FILE (browse to open a file) is assumed.  
-    The type can also be set later with <a href="#type">type()</a>.
-</ul>
-
-<h4><a name="~NativeFileChooser">
-fltk::NativeFileChooser::~NativeFileChooser()
-</h4>
-<ul>
-    The destructor; destroys any resources allocated to this widget.
-</ul>
-
-<h4>
-<a name="count"></a>
-int fltk::NativeFileChooser::count() const
-</h4>
-<ul>
-    Returns the number of filenames (or directory names) the user
-    selected. These are zero-indexed. 
-    See this example of <a href="#multi_example">how to retrieve
-    multiple filenames</a>.
-</ul>
-
-
-<h4>
-<a name="directory"></a>
-void fltk::NativeFileChooser::directory(const char*)<br>
-const char* fltk::NativeFileChooser::directory() const;<br>
-</h4>
-<ul>
-    Sets the directory with which to start the chooser.
-    If NULL is passed, or if no directory is specified,
-    the chooser will attempt to use the last non-cancelled folder.<br>
-</ul>
-
-<h4>
-<a name="errmsg"></a>
-const char *fltk::NativeFileChooser::errmsg() const<br>
-</h4>
-<ul>
-    Returns a system dependent error message for the last
-    method that failed. This message should at least be flagged
-    to the user in a dialog box, or to some kind of error log.
-</ul>
-
-<h4>
-<a name="filename"></a>
-const char *fltk::NativeFileChooser::filename() const<br>
-const char *fltk::NativeFileChooser::filename(int) const<br>
-</h4>
-<ul>
-    The first form returns the single filename selected
-    by the user from the browser. (In a multiple browser
-    context, this returns the first filename the user selected).
-    <p>
-    The second form should be used to return multiple filenames,
-    and is normally used inside a loop to retrieve all the files
-    the user selected, eg:
-    <p>
-    <a name="multi_example">
-    <pre>
-        if ( <b>chooser->show()</b> == 0 ) {
-            // HANDLE MULTIPLE FILENAMES
-            for (int n = 0; n < <b>chooser->count()</b>; n++ ) {
-      	        fprintf(stderr, "%d) '%s'\n", n, <b>chooser->filename(n)</b>);
-            }
-	}
-    </pre>
-    You can preset the directory with 
-    <a href="#directory">directory()</a> method, and the filename using the
-    <a href="#preset_file">preset_file()</a> method.<br>
-</ul>
-
-<h4>
-<a name="filter"></a>
-const char *fltk::NativeFileChooser::filter() const<br>
-void fltk::NativeFileChooser::filter(const char*)
-</h4>
-<ul>
-    Gets or sets the filename filters used for browsing.
-    The default is NULL, which browses all files.
-    <p>
-    The filter string can be any of:
-    <p>
-    <ul>
-        <li> A single wildcard (eg. "*.txt")
-	     </li>
-	<li> Multiple wildcards (eg. "*.{cxx,h,H})
-	     </li>
-	<li> A descriptive name followed by a '\t' and a wildcard
-	     (eg. "Text Files\t*.txt")
-	     </li>
-	<li> A list of separate wildcards with a \n between each (eg. "*.{cxx,H}\n*.txt")
-	     </li>
-	<li> A list of descriptive names and wildcards 
-	     (eg. "C++ Files\t*.{cxx,H}\nTxt Files\t*.txt")
-	     </li>
-    </ul>
-    <p>
-    The format of each filter is a wildcard, or an optional
-    user description followed by '\t' and the wildcard.
-    <p>
-    On most platforms, each filter is available to the user
-    via a pulldown menu in the file chooser. The 'All Files'
-    option is always available to the user.
-</ul>
-
-<h4>
-<a name="filter_value"></a>
-void fltk::NativeFileChooser::filter_value(int)<br>
-int fltk::NativeFileChooser::filter_value()<br>
-</h4>
-<ul>
-    The first form sets which filter will be initially selected.<br>
-    The second returns which filter was chosen. This is only valid
-    if the chooser returns success.<br>
-    <p>
-    The first filter is indexed as 0. If filter_value()==filters(),
-    then "All Files" was chosen. If filter_value() > filters(), then
-    a custom filter was set.<br>
-</ul>
-
-<h4>
-<a name="filters"></a>
-int fltk::NativeFileChooser::filters()<br>
-</h4>
-<ul>
-    Gets how many filters were available, not including "All Files"
-</ul>
-
-<h4>
-<a name="options"></a>
-void fltk::NativeFileChooser::options(int)<br>
-int fltk::NativeFileChooser::options()<br>
-</h4>
-<ul>
-    Sets/gets the platform specific chooser options.
-    <p>
-    Some platforms have file choosers with specific functions
-    that can be enabled/disabled via this method.
-    <p>
-    Flags can be ORed together to enable several features. Flags currently supported:
-    <p>
-    <center><table cellpadding=3>
-        <tr><td BGCOLOR=#8888cc align=left>Flag          </td><td BGCOLOR=#8888cc>Description                                                        </td><td BGCOLOR=#8888cc>Win</td><td BGCOLOR=#8888cc>Mac</td><td BGCOLOR=#8888cc>Other</td></tr>
-        <tr><td BGCOLOR=#dddddd align=left><tt>fltk::NativeFileChooser::SAVEAS_CONFIRM</td><td BGCOLOR=#dddddd>With a BROWSE_SAVEAS chooser, prompts a confirmation if file exists</td><td BGCOLOR=#dddddd>Ignored </td><td BGCOLOR=#88dd88>Used   </td><td BGCOLOR=#dddddd>Ignored</td></tr>
-        <tr><td BGCOLOR=#dddddd align=left><tt>fltk::NativeFileChooser::NEW_FOLDER    </td><td BGCOLOR=#dddddd>Shows the 'New Folder' button                                      </td><td BGCOLOR=#dddddd>Ignored </td><td BGCOLOR=#88dd88>Used</td><td BGCOLOR=#88dd88>Used</td></tr>
-        <tr><td BGCOLOR=#dddddd align=left><tt>fltk::NativeFileChooser::PREVIEW       </td><td BGCOLOR=#dddddd>Enables the 'Preview' mode by default                              </td><td BGCOLOR=#dddddd>Ignored </td><td BGCOLOR=#dddddd>Ignored</td><td BGCOLOR=#88dd88>Used</td></tr>
-    </table></center>
-</ul>
-
-<h4>
-<a name="preset_file"></a>
-void fltk::NativeFileChooser::preset_file(const char*)<br>
-const char* fltk::NativeFileChooser::preset_file()<br>
-</h4>
-<ul>
-    Sets a default filename for the chooser. 
-    (Use <a href="#directory">directory()</a> to set the default directory)
-    <br>
-    Mainly used to preset the filename for save dialogs, 
-    and on most platforms can be used for opening files as well.
-</ul>
-
-<h4>
-<a name="show"></a>
-int fltk::NativeFileChooser::show() const<br>
-</h4>
-<ul>
-    Opens the current file chooser on the screen. This method
-    will block until the user has chosen something, or cancelled.
-    <p>
-    Return value:
-    <ul type=disc>
-        <li> 0 - user picked a file, filename() will have the result
-        <li> 1 - user hit 'cancel'
-        <li>-1 - failed; <a href="#errmsg">errmsg()</a> has reason
-    </ul>
-</ul>
-
-<h4>
-<a name="title"></a>
-const char *fltk::NativeFileChooser::title() const<br>
-void fltk::NativeFileChooser::title(const char*)
-</h4>
-<ul>
-    Gets or sets the title of the file chooser's window.
-    <p>
-    The default title varies according to the platform, so you
-    are advised to set the title explicitly.
-</ul>
-
-<h4><a name="type"></a>
-int fltk::NativeFileChooser::type() const<br>
-fltk::NativeFileChooser::type(int)
-</h4>
-<ul>
-    Gets or sets the current type of browser. Possible choices are:
-    <p>
-    <center><table cellpadding=3>
-        <tr>
-	  <td BGCOLOR=#8888cc align=left>Flag</td>
-	  <td BGCOLOR=#8888cc>Description</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>fltk::NativeFileChooser::BROWSE_FILE</td>
-	  <td BGCOLOR=#dddddd>Browse for a single file</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>fltk::NativeFileChooser::BROWSE_DIRECTORY</td>
-	  <td BGCOLOR=#dddddd>Browse for a single directory</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>fltk::NativeFileChooser::BROWSE_MULTI_FILE</td>
-	  <td BGCOLOR=#dddddd>Browse for multiple files</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>fltk::NativeFileChooser::BROWSE_MULTI_DIRECTORY</td>
-	  <td BGCOLOR=#dddddd>Browse for multiple directories (implementation varies)</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>fltk::NativeFileChooser::BROWSE_SAVE_FILE</td>
-	  <td BGCOLOR=#dddddd>Browse to save a single file</td>
-	</tr><tr>
-	  <td BGCOLOR=#dddddd align=left><tt>fltk::NativeFileChooser::BROWSE_SAVE_DIRECTORY</td>
-	  <td BGCOLOR=#dddddd>Browse for a directory, allowing creation</td>
-        </tr>
-    </table></center>
-    <p>
-    These may be changed in future versions of fltk::NativeFileChooser.
-</ul>
-
-<h3>Typical Usage</h3>
-<ul>
-    <pre>
-#include <fltk/NativeFileChooser.h>
-:
-fltk::NativeFileChooser *chooser = <b>new fltk::NativeFileChooser</b>();
-<b>chooser->type</b>(fltk::NativeFileChooser::BROWSE_FILE);   <i>// let user browse a single file</i>
-<b>chooser->title</b>("Open a file");                           <i>// optional title</i>
-<b>chooser->preset_file</b>("/var/tmp/somefile.txt");           <i>// optional filename preset</i>
-<b>chooser->filter</b>("Text Files\t*.txt");                    <i>// optional filter</i>
-switch ( <b>chooser->show</b>() ) {
-    case -1:    // ERROR
-	fprintf(stderr, "*** ERROR show() failed:%s\n", <b>chooser->errmsg</b>());
-	break;
-    case 1:     // CANCEL
-	fprintf(stderr, "*** CANCEL\n");
-	break;
-    default:    // USER PICKED A FILE
-        fprintf(stderr, "Filename was '%s'\n", <b>chooser->filename</b>());
-	break;
-}
-<p><hr><p>
-<b>// EXAMPLE 'SAVEAS' FILE BROWSER</b>
-#include <fltk/NativeFileChooser.h>
-:
-fltk::NativeFileChooser *chooser = <b>new fltk::NativeFileChooser</b>();
-<b>chooser->type</b>(fltk::NativeFileChooser::BROWSE_SAVE_FILE);   <i>// 'saveas' browser</i>
-<b>chooser->title</b>("Save As..");                                  <i>// optional title for chooser window</i>
-<b>chooser->directory</b>("/var/tmp");                               <i>// optional starting directory</i>
-<b>chooser->preset_file</b>("untitled.txt");                         <i>// optional default filename</i>
-<b>chooser->filter</b>("Text Files\t*.txt");                         <i>// optional filter</i>
-switch ( <b>chooser->show</b>() ) {
-    case -1:    // ERROR
-	fprintf(stderr, "*** ERROR show() failed:%s\n", <b>chooser->errmsg</b>());
-	break;
-    case 1:     // CANCEL
-	fprintf(stderr, "*** CANCEL\n");
-	break;
-    default:    // USER PICKED A FILE
-        fprintf(stderr, "Filename was '%s'\n", <b>chooser->filename</b>());
-	break;
-}
-    </pre>
-</ul>
-
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-<br> <br> <br> <br> <br> <br>
-
-</body>
-</html>
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/build-output-FEDORA3.txt b/Utilities/FLTK/Fl_Native_File_Chooser/documentation/build-output-FEDORA3.txt
deleted file mode 100644
index 72c838b..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/build-output-FEDORA3.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-***
-*** FLTK1 BUILD
-***
-( make -f Makefile-fltk1 all "FLTKCONFIG=/usr/local/src/fltk-1.1.x-svn/fltk-config --use-images")
-make[1]: Entering directory `/meade/net/erco/src/Fl_Native_File_Chooser'
-g++ -Wall -O3 -I. -I/usr/local/src/fltk-1.1.x-svn -I/usr/X11R6/include -DFLTK1 test-browser.cxx -c
-g++ -Wall -O3 -I. -I/usr/local/src/fltk-1.1.x-svn -I/usr/X11R6/include -DFLTK1 Fl_Native_File_Chooser.cxx -c
-g++ test-browser.o Fl_Native_File_Chooser.o -L/usr/X11R6/lib -L/usr/local/src/fltk-1.1.x-svn/lib /usr/local/src/fltk-1.1.x-svn/lib/libfltk_images.a -lpng -lz -ljpeg /usr/local/src/fltk-1.1.x-svn/lib/libfltk.a -ldl -lm -lXext -lX11 -lm -o test-browser
-strip test-browser
-/usr/local/src/fltk-1.1.x-svn/fltk-config --use-images --post test-browser
-g++ -Wall -O3 -I. -I/usr/local/src/fltk-1.1.x-svn -I/usr/X11R6/include -DFLTK1 simple-app.cxx -c
-g++ simple-app.o Fl_Native_File_Chooser.o -L/usr/X11R6/lib -L/usr/local/src/fltk-1.1.x-svn/lib /usr/local/src/fltk-1.1.x-svn/lib/libfltk_images.a -lpng -lz -ljpeg /usr/local/src/fltk-1.1.x-svn/lib/libfltk.a -ldl -lm -lXext -lX11 -lm -o simple-app
-strip simple-app
-/usr/local/src/fltk-1.1.x-svn/fltk-config --use-images --post simple-app
-make[1]: Leaving directory `/meade/net/erco/src/Fl_Native_File_Chooser'
-***
-*** FLTK2 BUILD
-***
-( make -f Makefile-fltk2 all "FLTK2CONFIG=/usr/local/src/fltk-2.0-svn/fltk2-config --use-images")
-make[1]: Entering directory `/meade/net/erco/src/Fl_Native_File_Chooser'
-gcc -Wall -O3 -I. -I/usr/local/src/fltk-2.0-svn -I/usr/include/freetype2 -I/usr/X11R6/include -Wno-non-virtual-dtor -DFLTK2 test-browser-fltk2.cxx -c
-gcc -Wall -O3 -I. -I/usr/local/src/fltk-2.0-svn -I/usr/include/freetype2 -I/usr/X11R6/include -Wno-non-virtual-dtor -DFLTK2 Fl_Native_File_Chooser.cxx -c -o NativeFileChooser.o
-gcc test-browser-fltk2.o NativeFileChooser.o -L/usr/local/src/fltk-2.0-svn/lib /usr/local/src/fltk-2.0-svn/lib/libfltk2_images.a /usr/local/src/fltk-2.0-svn/lib/libfltk2.a -L/usr/X11R6/lib -lX11 -lXi -lXinerama -lXft -lpthread -lm -lXext -lsupc++ -lpng -lfltk2_images -ljpeg -lz -lm -o test-browser-fltk2
-strip test-browser-fltk2
-/usr/local/src/fltk-2.0-svn/fltk2-config --use-images --post test-browser-fltk2
-gcc -Wall -O3 -I. -I/usr/local/src/fltk-2.0-svn -I/usr/include/freetype2 -I/usr/X11R6/include -Wno-non-virtual-dtor -DFLTK2 simple-app-fltk2.cxx -c
-gcc simple-app-fltk2.o NativeFileChooser.o -L/usr/local/src/fltk-2.0-svn/lib /usr/local/src/fltk-2.0-svn/lib/libfltk2_images.a /usr/local/src/fltk-2.0-svn/lib/libfltk2.a -L/usr/X11R6/lib -lX11 -lXi -lXinerama -lXft -lpthread -lm -lXext -lsupc++ -lpng -lfltk2_images -ljpeg -lz -lm -o simple-app-fltk2
-strip simple-app-fltk2
-/usr/local/src/fltk-2.0-svn/fltk2-config --use-images --post simple-app-fltk2
-make[1]: Leaving directory `/meade/net/erco/src/Fl_Native_File_Chooser'
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/build-output-MAC.txt b/Utilities/FLTK/Fl_Native_File_Chooser/documentation/build-output-MAC.txt
deleted file mode 100644
index 0640882..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/build-output-MAC.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-***
-*** FLTK1 BUILD
-***
-( make -f Makefile-fltk1 all "FLTKCONFIG=/usr/local/src/fltk-1.1.x-svn/fltk-config --use-images")
-g++ -Wall -O3 -I. -I/usr/local/src/fltk-1.1.x-svn -I/usr/local/src/fltk-1.1.x-svn/png -DFLTK1 test-browser.cxx -c
-g++ -Wall -O3 -I. -I/usr/local/src/fltk-1.1.x-svn -I/usr/local/src/fltk-1.1.x-svn/png -DFLTK1 Fl_Native_File_Chooser.cxx -c
-g++ test-browser.o Fl_Native_File_Chooser.o -L/usr/local/src/fltk-1.1.x-svn/lib /usr/local/src/fltk-1.1.x-svn/lib/libfltk_images.a -lfltk_png -lz -ljpeg /usr/local/src/fltk-1.1.x-svn/lib/libfltk.a -framework Carbon -framework ApplicationServices -lm -framework CoreFoundation -o test-browser
-strip test-browser
-/usr/local/src/fltk-1.1.x-svn/fltk-config --use-images --post test-browser
-g++ -Wall -O3 -I. -I/usr/local/src/fltk-1.1.x-svn -I/usr/local/src/fltk-1.1.x-svn/png -DFLTK1 simple-app.cxx -c
-g++ simple-app.o Fl_Native_File_Chooser.o -L/usr/local/src/fltk-1.1.x-svn/lib /usr/local/src/fltk-1.1.x-svn/lib/libfltk_images.a -lfltk_png -lz -ljpeg /usr/local/src/fltk-1.1.x-svn/lib/libfltk.a -framework Carbon -framework ApplicationServices -lm -framework CoreFoundation -o simple-app
-strip simple-app
-/usr/local/src/fltk-1.1.x-svn/fltk-config --use-images --post simple-app
-***
-*** FLTK2 BUILD
-***
-( make -f Makefile-fltk2 all "FLTK2CONFIG=/usr/local/src/fltk-2.0-svn/fltk2-config --use-images")
-g++ -Wall -O3 -I. -I/usr/local/src/fltk-2.0-svn -Wno-non-virtual-dtor -DFLTK2 test-browser-fltk2.cxx -c
-g++ -Wall -O3 -I. -I/usr/local/src/fltk-2.0-svn -Wno-non-virtual-dtor -DFLTK2 Fl_Native_File_Chooser.cxx -c -o NativeFileChooser.o
-g++ test-browser-fltk2.o NativeFileChooser.o -L/usr/local/src/fltk-2.0-svn/lib /usr/local/src/fltk-2.0-svn/lib/libfltk2_images.a /usr/local/src/fltk-2.0-svn/lib/libfltk2.a -lpthread -framework Carbon -framework ApplicationServices -lpng -lfltk2_images -ljpeg -lz -lm -framework CoreFoundation -o test-browser-fltk2
-strip test-browser-fltk2
-/usr/local/src/fltk-2.0-svn/fltk2-config --use-images --post test-browser-fltk2
-g++ -Wall -O3 -I. -I/usr/local/src/fltk-2.0-svn -Wno-non-virtual-dtor -DFLTK2 simple-app-fltk2.cxx -c
-g++ simple-app-fltk2.o NativeFileChooser.o -L/usr/local/src/fltk-2.0-svn/lib /usr/local/src/fltk-2.0-svn/lib/libfltk2_images.a /usr/local/src/fltk-2.0-svn/lib/libfltk2.a -lpthread -framework Carbon -framework ApplicationServices -lpng -lfltk2_images -ljpeg -lz -lm -framework CoreFoundation -o simple-app-fltk2
-strip simple-app-fltk2
-/usr/local/src/fltk-2.0-svn/fltk2-config --use-images --post simple-app-fltk2
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/build-output-WIN32.txt b/Utilities/FLTK/Fl_Native_File_Chooser/documentation/build-output-WIN32.txt
deleted file mode 100644
index 983e4c0..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/build-output-WIN32.txt
+++ /dev/null
@@ -1,86 +0,0 @@
-***
-*** FLTK1 BUILD
-***
-gmake -f Makefile-fltk1.MICROSOFT FLTKDIR=c:/fltk-1.1.7
-gmake[1]: Entering directory `Z:/erco/src/Fl_Native_File_Chooser'
-cl /MD /EHsc /DVS2000 /DVISUAL_STUDIO /Zi /D_CRT_SECURE_NO_DEPRECATE /Ic:/fltk-1.1.7 /I. /DFLTK1 /Tp test-browser.cxx /c
-Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86
-Copyright (C) Microsoft Corporation.  All rights reserved.
-
-test-browser.cxx
-cl /MD /EHsc /DVS2000 /DVISUAL_STUDIO /Zi /D_CRT_SECURE_NO_DEPRECATE test-browser.obj Fl_Native_File_Chooser.obj /link c:/fltk-1.1.7/lib/fltk.lib wsock32.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib winmm.lib ole32.lib oleaut32.lib uuid.lib imm32.lib /nologo /machine:I386 /subsystem:console
-del test-browser.obj 2> nul
-cl /MD /EHsc /DVS2000 /DVISUAL_STUDIO /Zi /D_CRT_SECURE_NO_DEPRECATE /Ic:/fltk-1.1.7 /I. /DFLTK1 /Tp simple-app.cxx /c
-Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86
-Copyright (C) Microsoft Corporation.  All rights reserved.
-
-simple-app.cxx
-cl /MD /EHsc /DVS2000 /DVISUAL_STUDIO /Zi /D_CRT_SECURE_NO_DEPRECATE simple-app.obj Fl_Native_File_Chooser.obj /link c:/fltk-1.1.7/lib/fltk.lib wsock32.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib winmm.lib ole32.lib oleaut32.lib uuid.lib imm32.lib /nologo /machine:I386 /subsystem:console
-del simple-app.obj 2> nul
-gmake[1]: Leaving directory `Z:/erco/src/Fl_Native_File_Chooser'
-***
-*** FLTK2 BUILD ***
-***
-gmake -f Makefile-fltk2.MICROSOFT FLTK2DIR=c:/fltk-2.x-svn
-gmake[1]: Entering directory `Z:/erco/src/Fl_Native_File_Chooser'
-cl /EHsc /ZI /DVS2000 /DVISUAL_STUDIO /D_CRT_SECURE_NO_DEPRECATE /Ic:/fltk-2.x-svn /I. /DFLTK2 /Tp test-browser-fltk2.cxx /c
-Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86
-Copyright (C) Microsoft Corporation.  All rights reserved.
-
-test-browser-fltk2.cxx
-cl /EHsc /ZI /DVS2000 /DVISUAL_STUDIO /D_CRT_SECURE_NO_DEPRECATE test-browser-fltk2.obj NativeFileChooser.obj /link c:/fltk-2.x-svn/lib/fltk2.lib ws2_32.lib msimg32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /subsystem:console
-Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86
-Copyright (C) Microsoft Corporation.  All rights reserved.
-
-Microsoft (R) Incremental Linker Version 8.00.50727.42
-Copyright (C) Microsoft Corporation.  All rights reserved.
-
-/out:test-browser-fltk2.exe 
-/debug 
-c:/fltk-2.x-svn/lib/fltk2.lib 
-ws2_32.lib 
-msimg32.lib 
-kernel32.lib 
-user32.lib 
-gdi32.lib 
-winspool.lib 
-comdlg32.lib 
-advapi32.lib 
-shell32.lib 
-ole32.lib 
-oleaut32.lib 
-uuid.lib 
-/subsystem:console 
-test-browser-fltk2.obj 
-NativeFileChooser.obj 
-cl /EHsc /ZI /DVS2000 /DVISUAL_STUDIO /D_CRT_SECURE_NO_DEPRECATE /Ic:/fltk-2.x-svn /I. /DFLTK2 /Tp simple-app-fltk2.cxx /c
-Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86
-Copyright (C) Microsoft Corporation.  All rights reserved.
-
-simple-app-fltk2.cxx
-cl /EHsc /ZI /DVS2000 /DVISUAL_STUDIO /D_CRT_SECURE_NO_DEPRECATE simple-app-fltk2.obj NativeFileChooser.obj /link c:/fltk-2.x-svn/lib/fltk2.lib ws2_32.lib msimg32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /subsystem:console
-Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86
-Copyright (C) Microsoft Corporation.  All rights reserved.
-
-Microsoft (R) Incremental Linker Version 8.00.50727.42
-Copyright (C) Microsoft Corporation.  All rights reserved.
-
-/out:simple-app-fltk2.exe 
-/debug 
-c:/fltk-2.x-svn/lib/fltk2.lib 
-ws2_32.lib 
-msimg32.lib 
-kernel32.lib 
-user32.lib 
-gdi32.lib 
-winspool.lib 
-comdlg32.lib 
-advapi32.lib 
-shell32.lib 
-ole32.lib 
-oleaut32.lib 
-uuid.lib 
-/subsystem:console 
-simple-app-fltk2.obj 
-NativeFileChooser.obj 
-gmake[1]: Leaving directory `Z:/erco/src/Fl_Native_File_Chooser'
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/how-to-use.html b/Utilities/FLTK/Fl_Native_File_Chooser/documentation/how-to-use.html
deleted file mode 100644
index a611daf..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/how-to-use.html
+++ /dev/null
@@ -1,69 +0,0 @@
-<html><head></head><body><h2>How To Install Fl_Native_File_Chooser Into Your Own Project</h2>
-<blockquote>
-    The Fl_Native_File_Chooser project can either be added to FLTK, or
-    installed as a subdirectory either inside your own project,
-    or in a separate directory that all your projects can refer to.
-    <p>
-    Just be sure to compile with the -I (include) flag pointing
-    to where the Fl_Native_File_Chooser directory is, and to link in the
-    Fl_Native_File_Chooser.o file left in that directory after doing a 'make'.
-</p></blockquote>
-<p>
-</p><h3>Installing Fl_Native_File_Chooser Into Your Project's Directory</h3>
-<blockquote>
-    Here's an example of how to install Fl_Native_File_Chooser into your project's
-    own directory:
-</blockquote>
-<pre>        ../src/YourApp/
-	        |
-	        |-- YourApp.C
-		|-- YourApp.H		     -- Contains <b>"#include <FL/Fl_Native_File_Chooser.H>"</b>
-		|-- Makefile		     -- Compiles with <b>"-I./Fl_Native_File_Chooser", </b>
-		|                               links with <b>./Fl_Native_File_Chooser/Fl_Native_File_Chooser.o</b>
-		|-- <font color="RED">Fl_Native_File_Chooser</font>   -- Fl_Native_File_Chooser installed as a subdirectory<font color="RED">
-		:       |
-		        |-- FL
-			|   |
-			|   |-- Fl_Native_File_Chooser.H
-			|   :
-			|
-			|-- Fl_Native_File_Chooser.o
-			|-- Makefile
-			:</font>
-</pre>
-<blockquote>
-    This way you can still just have <b><tt>"#include <FL/Fl_Native_File_Chooser.H>"</tt></b> 
-    in your C++ files.. just use <b><tt>"-I./Fl_Native_File_Chooser"</tt></b> as one of the 
-    compile flags, and the #include will resolve correctly.
-    <p>
-    During linking, be sure to link in 
-    <b><tt>"./Fl_Native_File_Chooser/Fl_Native_File_Chooser.o"</tt></b>
-    as part of the link instructions for your app.
-</blockquote>
-
-</p><h3>Recommendations</h3>
-<blockquote>
-    It is advised you locate Fl_Native_File_Chooser in the same source directory
-    your FLTK version(s) are installed, eg:
-    <pre>
-    /usr/local/src/fltk-1.1.x-svn/		     <I><-- some rev of fltk</I>
-    /usr/local/src/fltk-2.0-svn/		     <I><-- some other rev of fltk</I>
-    /usr/local/src/Fl_Native_File_Chooser-0.84/  <I><-- put Fl_Native_File_Chooser here</I>
-    </pre>
-    In your Makefile, just add the Fl_Native_File_Chooser directory to your
-    include path, and add the Fl_Native_File_Chooser.o to your link line, eg:
-    <pre>
-    # FLTK1
-    INCLUDES = -I/usr/local/src/Fl_Native_File_Chooser-0.84/
-    LIBS     = /usr/local/src/Fl_Native_File_Chooser-0.84/Fl_Native_File_Chooser.o
-
-    # FLTK2
-    INCLUDES = -I/usr/local/src/Fl_Native_File_Chooser-0.84/
-    LIBS     = /usr/local/src/Fl_Native_File_Chooser-0.84/NativeFileChooser.o
-
-    foo: foo.cxx
-	    g++ $(INCLUDES) foo.cxx -c
-	    g++ foo.o $(LIBS) ..
-    </pre>
-</blockquote>
-</body></html>
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/images/native-small.png b/Utilities/FLTK/Fl_Native_File_Chooser/documentation/images/native-small.png
deleted file mode 100644
index d1b4d32..0000000
Binary files a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/images/native-small.png and /dev/null differ
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/index.html b/Utilities/FLTK/Fl_Native_File_Chooser/documentation/index.html
deleted file mode 100644
index 7d4e6e7..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/documentation/index.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<html>
-<head>
-<title>Fl_Native_File_Chooser Documentation</title>
-</head>
-<body>
-<h1>Fl_Native_File_Chooser Documentation</h1>
-<p>
-    <center>
-        <img src="images/native-small.png" border=noshade><br>
-	<i>Examples of Native_File_Chooser on different platforms.</i>
-    </center>
-<ul>
-    Fl_Native_File_Chooser now supports both versions of fltk:
-    <p>
-    <ul type=disc>
-       <li> <a href="Fl_Native_File_Chooser.html">fltk-1.x</a></li>
-       <li> <a href="NativeFileChooser.html">fltk-2.x</a></li>
-    </ul>
-    <p>
-    To link the chooser into your own apps, please look at the 
-    <a href="how-to-use.html">how to link</a> instructions to follow
-    the intended philosophy for linking.
-    <P>
-    For example build output on the various platforms, see:
-    <ul type=disc>
-       <li> <a href="build-output-FEDORA3.txt">Fedora3</a></li>
-       <li> <a href="build-output-MAC.txt">Mac (Tiger)</a></li>
-       <li> <a href="build-output-WIN32.txt">Windows (VS Express 8)</a></li>
-    </ul>
-    <p>
-</ul>
-
-</body>
-</html>
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser.h b/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser.h
deleted file mode 100644
index a9611fc..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser.h
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// NativeFileChooser.H -- FLTK native OS file chooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-
-#ifndef FLTK_NATIVE_FILE_CHOOSER_H
-#define FLTK_NATIVE_FILE_CHOOSER_H
-
-// Use Windows' chooser
-#ifdef _WIN32
-#include <fltk/NativeFileChooser_WIN32.h>
-#endif
-
-// Use Apple's chooser
-#ifdef __APPLE__
-#include <fltk/NativeFileChooser_MAC.h>
-#endif
-
-// All else falls back to FLTK's own chooser
-#if ! defined(__APPLE__) && !defined(_WIN32)
-#include <fltk/NativeFileChooser_FLTK.h>
-#endif
-
-#endif /*FLTK_NATIVE_FILE_CHOOSER_H*/
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser_FLTK.h b/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser_FLTK.h
deleted file mode 100644
index 6f22197..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser_FLTK.h
+++ /dev/null
@@ -1,100 +0,0 @@
-//
-// NativeFileChooser_FLTK.h -- FLTK native OS file chooser widget
-//
-// Copyright 2004 by Nathan Vander Wilt
-// Port to FLTK2 by Frederic Hoerni and Greg Ercolano 2007
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-
-#include <fltk/FileChooser.h>
-#include <string.h>
-
-namespace fltk {
-
-class NativeFileChooser {
-public:
-    enum Type {
-	BROWSE_FILE = 0,
-	BROWSE_DIRECTORY,
-	BROWSE_MULTI_FILE,
-	BROWSE_MULTI_DIRECTORY,
-	BROWSE_SAVE_FILE,
-	BROWSE_SAVE_DIRECTORY
-    };
-    enum Option {
-        NO_OPTIONS     = 0x0000,	// no options enabled
-	SAVEAS_CONFIRM = 0x0001,	// Show native 'Save As' overwrite
-					// confirm dialog (if supported)
-	NEW_FOLDER     = 0x0002,	// Show 'New Folder' icon
-					// (if supported)
-	PREVIEW        = 0x0004		// enable preview mode
-    };
-private:
-    int   _btype;			// kind-of browser to show()
-    int   _options;			// general options
-    char *_filter;			// user supplied filter
-    char *_parsedfilt;			// parsed filter
-    int   _filtvalue;			// selected filter
-    char *_preset_file;
-    char *_prevvalue;			// Returned filename
-    char *_directory;
-    char *_errmsg;			// error message
-
-    fltk::FileChooser *file_chooser;
-    int exist_dialog() {
-	return(fltk::choice("File exists. Are you sure you want to overwrite?",
-			    "Cancel", "   OK   ", NULL));
-    }
-    void load_system_icons() {
-	fltk::FileIcon::load_system_icons();
-    }
-    int _nfilters;
-
-    // Private methods
-    void errmsg(const char *msg);
-    int type_fl_file(int);
-    void parse_filter();
-    void keeplocation();
-
-public:
-    NativeFileChooser(int val=BROWSE_FILE);
-    ~NativeFileChooser();
-
-    // Public methods
-    void type(int);
-    int type() const;
-    void options(int);
-    int options() const;
-    int count() const;
-    const char *filename() const;
-    const char *filename(int i) const;
-    void directory(const char *val);
-    const char *directory() const;
-    void title(const char *);
-    const char* title() const;
-    const char *filter() const;
-    void filter(const char *);
-    int filters() const { return(_nfilters); }
-    void filter_value(int i);
-    int filter_value() const;
-    void preset_file(const char*);
-    const char* preset_file() const;
-    const char *errmsg() const;
-    int show();
-};
-
-}   // namespace fltk
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser_MAC.h b/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser_MAC.h
deleted file mode 100644
index b7a58ef..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser_MAC.h
+++ /dev/null
@@ -1,142 +0,0 @@
-//
-// NativeFileChooser_MAC.H -- FLTK native OS file chooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-// FLTK2 port by Greg Ercolano 2007
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-//      10        20        30        40        50        60        70
-//       |         |         |         |         |         |         |
-// 4567890123456789012345678901234567890123456789012345678901234567890123456789
-
-// OSX-SPECIFIC NATIVE BROWSER
-#ifdef __APPLE_CC__
-#include <Carbon/Carbon.h>
-#else
-#include <Carbon.h>
-#endif
-
-#define MAXFILTERS	80
-
-namespace fltk {
-
-class NativeFileChooser {
-public:
-    enum Type {
-	BROWSE_FILE = 0,
-	BROWSE_DIRECTORY,
-	BROWSE_MULTI_FILE,
-	BROWSE_MULTI_DIRECTORY,
-	BROWSE_SAVE_FILE,
-	BROWSE_SAVE_DIRECTORY
-    };
-    enum Option {
-        NO_OPTIONS     = 0x0000,	// no options enabled
-	SAVEAS_CONFIRM = 0x0001,	// Show native 'Save As' overwrite
-					// confirm dialog (if supported)
-	NEW_FOLDER     = 0x0002,	// Show 'New Folder' icon
-					// (if supported)
-	PREVIEW        = 0x0004,	// enable preview mode
-    };
-protected:
-    NavDialogCreationOptions _opts;	// file navigation options
-private:
-    int             _btype;		// kind-of browser to show()
-    int             _options;		// general options
-    NavDialogRef    _ref;		// file navigation reference
-    NavActionState  _keepstate;		// holds button permissions
-    NavMenuItemSpec _tempitem;   	// Popup menu selection
-    char          **_pathnames;		// array of pathnames
-    int             _tpathnames;	// total pathnames
-    char           *_directory;		// default pathname to use
-    char           *_title;		// title for window
-    char           *_preset_file;	// the 'save as' filename
-
-    char           *_filter;		// user-side search filter, eg:
-					// C Files\t*.[ch]\nText Files\t*.txt"
-
-    char           *_filt_names;	// filter names (tab delimited)
-    					// eg. "C Files\tText Files"
-
-    char           *_filt_patt[MAXFILTERS];
-                                        // array of filter patterns, eg:
-					//     _filt_patt[0]="*.{cxx,h}"
-					//     _filt_patt[1]="*.txt"
-
-    int             _filt_total;	// parse_filter() # of filters loaded
-    int             _filt_value;	// index of the selected filter
-    char           *_errmsg;		// error message
-
-    // PRIVATE CLASS TO HANDLE NAVIGATION DIALOG REPLY STRUCT
-    //     Class-ified, mainly to ensure proper cleanup.
-    //
-    class NavReply {
-        int _valid_reply;
-	NavReplyRecord _reply;
-    public:
-        NavReply();
-	~NavReply();
-	int get_reply(NavDialogRef& ref);
-	int get_saveas_basename(char *s, int slen);
-	int get_dirname(char *s, int slen);
-	int get_pathnames(char **&pathnames, int& tpathnames);
-    };
-
-    // Private methods
-    void errmsg(const char *msg);
-    void clear_pathnames();
-    void set_single_pathname(const char *s);
-    int get_saveas_basename(NavDialogRef& ref);
-    int get_pathnames(NavDialogRef& ref);
-    static void event_handler(NavEventCallbackMessage callBackSelector, 
-    					     NavCBRecPtr cbparm, void *data);
-
-    void clear_filters();
-    void add_filter(const char *, const char *);
-    void parse_filter(const char *from);
-    static Boolean filter_proc_cb(AEDesc *, void *, void *, NavFilterModes);
-    Boolean filter_proc_cb2(AEDesc*, void*, void*, NavFilterModes);
-    int post();
-    
-public:
-    NativeFileChooser(int val = BROWSE_FILE);
-    ~NativeFileChooser();
-
-    // Public methods
-    void type(int);
-    int type() const;
-    void options(int);
-    int options() const;
-    int count() const;
-    const char *filename() const;
-    const char *filename(int i) const;
-    void directory(const char *);
-    const char *directory() const;
-    void title(const char *);
-    const char *title() const;
-    const char *filter() const;
-    void filter(const char *);
-    void filter_value(int i) { _filt_value = i; }
-    int filter_value() { return(_filt_value); }
-    int filters() { return(_filt_total); }
-    void preset_file(const char *);
-    const char *preset_file();
-    const char *errmsg() const;
-    int show();
-};
-
-}
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser_WIN32.h b/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser_WIN32.h
deleted file mode 100644
index 4840218..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/fltk/NativeFileChooser_WIN32.h
+++ /dev/null
@@ -1,113 +0,0 @@
-//
-// NativeFileChooser_WINDOWS.h -- FLTK native OS file chooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-// API changes + filter improvements by Nathan Vander Wilt 2005
-// FLTK2 port by Greg Ercolano 2007
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-
-// #define _WIN32_WINNT	0x0501	// needed for OPENFILENAME's 'FlagsEx'
-#include <stdio.h>
-#include <stdlib.h>		// malloc
-#include <windows.h>
-#include <commdlg.h>		// OPENFILENAME, GetOpenFileName()
-#include <shlobj.h>		// BROWSEINFO, SHBrowseForFolder()
-
-namespace fltk {
-
-class NativeFileChooser {
-public:
-    enum Type {
-	BROWSE_FILE = 0,
-        BROWSE_DIRECTORY,
-	BROWSE_MULTI_FILE,
-	BROWSE_MULTI_DIRECTORY,
-	BROWSE_SAVE_FILE,
-	BROWSE_SAVE_DIRECTORY
-    };
-    enum Option {
-        NO_OPTIONS     = 0x0000,	// no options enabled
-	SAVEAS_CONFIRM = 0x0001,	// Show native 'Save As' overwrite
-					// confirm dialog (if supported)
-	NEW_FOLDER     = 0x0002,	// Show 'New Folder' icon
-					// (if supported)
-	PREVIEW        = 0x0004,	// enable preview mode
-    };
-private:
-    int  _btype;		// kind-of browser to show()
-    int  _options;		// general options
-    OPENFILENAME _ofn;		// GetOpenFileName() & GetSaveFileName() struct
-    BROWSEINFO   _binf;		// SHBrowseForFolder() struct
-    char  **_pathnames;		// array of pathnames
-    int     _tpathnames;	// total pathnames
-    char   *_directory;		// default pathname to use
-    char   *_title;		// title for window
-    char   *_filter;		// user-side search filter
-    char   *_parsedfilt;	// filter parsed for Windows dialog
-    int     _nfilters;		// number of filters parse_filter counted
-    char   *_preset_file;	// the file to preselect
-    char   *_errmsg;		// error message
-
-    // Private methods
-    void errmsg(const char *msg);
-
-    void clear_pathnames();
-    void set_single_pathname(const char *s);
-    void add_pathname(const char *s);
-
-    void FreePIDL(ITEMIDLIST *pidl);
-    void ClearOFN();
-    void ClearBINF();
-    void Win2Unix(char *s);
-    void Unix2Win(char *s);
-    int showfile();
-    static int CALLBACK Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data);
-    int showdir();
-
-    void parse_filter(const char *);
-    void clear_filters();
-    void add_filter(const char *, const char *);
-
-public:
-    NativeFileChooser(int val = BROWSE_FILE);
-    ~NativeFileChooser();
-
-    // Public methods
-    void type(int val);
-    int type() const;
-    void options(int);
-    int options() const;
-    int count() const;
-    const char *filename() const;
-    const char *filename(int i) const;
-    void directory(const char *val);
-    const char *directory() const;
-    void title(const char *val);
-    const char *title() const;
-    const char *filter() const;
-    void filter(const char *val);
-    int filters() const { return _nfilters; }
-    void filter_value(int i);
-    int filter_value() const;
-    void preset_file(const char *);
-    const char *preset_file() const;
-    const char *errmsg() const;
-    int show();
-};
-
-}		// namespace fltk
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/make.bat b/Utilities/FLTK/Fl_Native_File_Chooser/make.bat
deleted file mode 100644
index e82129e..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/make.bat
+++ /dev/null
@@ -1,2 +0,0 @@
- at set PATH=C:\BIN;%PATH%
- at gmake -f Makefile.MICROSOFT %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/reference/README-natev-mods.txt b/Utilities/FLTK/Fl_Native_File_Chooser/reference/README-natev-mods.txt
deleted file mode 100644
index 22122ec..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/reference/README-natev-mods.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-===Fl_Native_File_Chooser===
-  A library to simplify creation of user-friendly file and directory choosers.
-
-
-//
-// This library 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
-// Library General Public License for more details.
-//
-
-
-===LOG===
- 2/Apr/2005 took Greg Ercolano's version 0.62, added FLTK support, changed API and added multiple filter selection
- 4/Apr/2005 Win32 nullncat fix applied, improved input filter checking
- 9/Apr/2005 a lot of Mac filter work done, yet no setting initial filter 
-14/Apr/2005 Mac set initial filter, disallow multi-select by disabling 'Choose' button
-15/Apr/2005 Win32 disable non-folder locations, got set of initial filter working
-20/Apr/2005 Passed event handler to all Mac choosers to fix modal problems, minor Mac tidies
-21/Apr/2005 Some minor fixes to Win32 code. Thanks Don!
- 3/May/2005 Added one line to enable setting selected filter on 10.3
-14/May/2005 Added preset_file which enables setting a default filename**, added AWOL ctor on Mac, made FLTK browser (usually***) keep its place
-20/July/2005 Made FLTK-side preset_file not apply to directories, since that was weird looking
-20/Aug/2005 merged Ian MacArthur's fix and makefile with my current tree. much thanks a.rburgers and Ian for taking the time to create makefiles!
-26/Aug/2005 fixed another warning, removed a CFString.h include, thanks again Ian!
-30/Aug/2005 fixed another little bug in the Win32 code, thanks Alessandro!
-10/Oct/2005 updated documentation
-11/Oct/2005 Fixed bug that could return bad value from the FLTK ::filename() method
-11/Oct/2005 Fixed nativefc.cxx to include proper file
-26/Oct/2005 Modified makefile
-27/Oct/2005 fixed missing return in FLTK filename(int) method
-27/Oct/2005 shushed signedness warning in _FLTK chooser for loop
-
-
-TBD: ensure Windows code will both compile and run across all platforms ( tested a WinXP-compiled version on Win98 with no trouble )
-TBD?: implement multi-folder selection on Win32 if possible
-TBD?: enable preset selection on Mac OS X open dialogs
-TBD: try working around ugly inactive filtered OS X items, again*
-TBD: tidy code if possible (there might be some debug/development leftovers)
-TBD: make sure errmsg is always set to suitable end-user messages
-TBD: add a fuller constructor
-TBD: make sure directory() reports the directory the dialog will display
-TBD: test, test, test.
-
-
-===USE===
-If you have compiled and installed the FLTK source, you should be able to compile this package using 'make'
-The package does not install any files, but will build an object file and tester for your platform. Your platform's header file will be copied to Fl_Native_File_Chooser.H
-To compile into your program, include the header file and link with Fl_Native_File_Chooser.o
-
-
-===NOTES / KNOWN ISSUES===
-OS X:
- *A glitch in Mac OS X (pre-Tiger) causes only the icons to activate/deactivate after the initial filter selection.
-  The names of files keep their original higlights. A few attempts at a workaround failed, patches welcome!
- *On OS X, using preset_filename() only works for saving files now.
- *Some apparent bugs in Apple's Spotlight code cause trouble with the leftmost Spotlight results column:
-  - even when the Native_Chooser is supposed to be allowing only single selection, it is unable to catch multiple selections there
-  - (!) if a directory is picked from that column, the Native_Chooser seems to be told that there were NO PATHNAMES RETURNED
-FLTK:
- *If preset_filename() and a NULL directory() is used with the FLTK browser, the cwdir rather than the previous directory will be used
-
-This library is almost beta, see the TBD's above. This library may have undiscovered bugs, use at your own risk.
-
-I suppose one place for bug reports would be via the fltk.general newsgroup, 
-although this library is not currently an official part of FLTK. Feel free to e-mail me.
-
-Enjoy!
--natevw
-(at yahoo dot com)
-http://homepages.dordt.edu/~nthnlvnd/projects.html
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/reference/REFERENCE-MAC.txt b/Utilities/FLTK/Fl_Native_File_Chooser/reference/REFERENCE-MAC.txt
deleted file mode 100644
index e91b747..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/reference/REFERENCE-MAC.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-Mac reference:
-
-    Top Level:
-    http://developer.apple.com/documentation/Carbon/Conceptual/ProvidingNavigationDialogs/nsx_concepts/chapter_2_section_2.html#//apple_ref/doc/uid/TP30001147-CH202-CHDEDCBD
-
-    Functions:
-    http://developer.apple.com/documentation/Carbon/Conceptual/ProvidingNavigationDialogs/nsx_tasks/chapter_3_section_3.html#//apple_ref/doc/uid/TP30001147-CH203-BEIGBDGD
-
-    Nav Tasks:
-    http://developer.apple.com/documentation/Carbon/Conceptual/ProvidingNavigationDialogs/nsx_tasks/chapter_3_section_1.html#//apple_ref/doc/uid/TP30001147-CH203-BABGIAGG
-
-    Preload:
-    http://groups.google.com/groups?q=NavCreateGetFileDialog+directory&hl=en&lr=&c2coff=1&selm=oster-A486E7.08390422102002%40newssvr21-ext.news.prodigy.com&rnum=1
-
-    http://developer.apple.com/qa/qa2001/qa1151.html
-
-    CFString:
-    file:///Developer/Documentation/CoreFoundation/Reference/CFStringRef/index.html#//apple_ref/doc/uid/20001211
-//
-    http://developer.apple.com/documentation/Carbon/Reference/Navigation_Services_Ref/index.html
-    http://lists.apple.com/archives/carbon-dev/2005/Feb/msg01230.html
-    http://www.mactech.com/macintosh-c/chap18-1.html
-    http://developer.apple.com/documentation/Carbon/Reference/Navigation_Services_Ref/nav_serv_ref/chapter_1.4_section_2.html -block New Folder button
-    http://developer.apple.com/documentation/Carbon/Reference/Navigation_Services_Ref/nav_serv_ref/chapter_1.4_section_9.html
-    http://developer.apple.com/documentation/Carbon/Reference/Navigation_Services_Ref/nav_serv_ref/chapter_1.4_section_6.html
-    http://lists.apple.com/archives/nav-serv-developers/2003/Apr/msg00003.html
-    http://developer.apple.com/datatype/creatorcode.html
-    http://developer.apple.com/documentation/Carbon/Conceptual/ProvidingNavigationDialogs/nsx_tasks/chapter_3_section_3.html
-//
-
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/reference/erco-merge-trick.cxx b/Utilities/FLTK/Fl_Native_File_Chooser/reference/erco-merge-trick.cxx
deleted file mode 100644
index cbc667e..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/reference/erco-merge-trick.cxx
+++ /dev/null
@@ -1,49 +0,0 @@
-#define FLTK1
-
-#include <stdio.h>
-
-#ifdef FLTK1
-#define FOO_CLASS Fl_Foo
-#else
-#define FOO_CLASS fltk::Foo
-#endif
-
-#ifdef FLTK1
-class Fl_Foo {
-#else
-namespace fltk {
-class Foo {
-#endif
-
-public:
-    void aaa();
-    void bbb();
-
-#ifdef FLTK1
-};
-#else
-};
-}
-#endif
-
-void FOO_CLASS::aaa() {
-   printf("aaa\n");
-}
-
-void FOO_CLASS::bbb() {
-   printf("bbb\n");
-}
-
-#ifdef FLTK1
-int main() {
-   Fl_Foo foo;
-   foo.aaa();
-   foo.bbb();
-}
-#else
-int main() {
-   fltk::Foo foo;
-   foo.aaa();
-   foo.bbb();
-}
-#endif
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/simple-app-fltk2.cxx b/Utilities/FLTK/Fl_Native_File_Chooser/simple-app-fltk2.cxx
deleted file mode 100644
index 6f33e90..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/simple-app-fltk2.cxx
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-// simple-app.cxx -- simple example application
-//
-// Copyright 2004 by Greg Ercolano.
-// FLTK2 port by Frederic Hoerni 2007.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-// Please keep code 80 column compliant.
-//
-//      10        20        30        40        50        60        70
-//       |         |         |         |         |         |         |
-// 4567890123456789012345678901234567890123456789012345678901234567890123456789
-//
-#include <stdio.h>
-#include <fltk/run.h>
-#include <fltk/ask.h>
-#include <fltk/Window.h>
-#include <fltk/Widget.h>
-#include <fltk/Button.h>
-#include <fltk/Input.h>
-#include <fltk/NativeFileChooser.h>
-
-// GLOBALS
-fltk::Input *G_filename = NULL;
-
-void Butt_CB(fltk::Widget*, void*) {
-    // Create native chooser
-    fltk::NativeFileChooser native;
-    native.title("Pick a file");
-    native.type(fltk::NativeFileChooser::BROWSE_FILE);
-    native.filter("C Files\t*.{cxx,h,c}\n"
-                  "C Files\t*.{cxx,h,c}");
-    native.preset_file(G_filename->value());
-    // Show native chooser
-    switch ( native.show() ) {
-	case -1: fprintf(stderr, "ERROR: %s\n", native.errmsg()); break;	// ERROR
-	case  1: fprintf(stderr, "*** CANCEL\n"); fltk::beep(); break;		// CANCEL
-	default: 								// PICKED FILE
-	    if ( native.filename() )
-		G_filename->value(native.filename());
-	    else
-		G_filename->value("NULL");
-	    break;
-    }
-}
-
-int main() {
-    fltk::Window *win = new fltk::Window(600, 100, "FLTK Window");
-    win->begin();
-    {
-	int y = 10;
-	G_filename = new fltk::Input(80, y, win->w()-80-10, 25, "Filename");
-	G_filename->value(".");
-	G_filename->tooltip("Default filename");
-	y += G_filename->h() + 5;
-	fltk::Button *but = 
-	    new fltk::Button(win->w()-80-10, win->h()-25-10, 80, 25, "Pick File");
-	but->callback(Butt_CB);
-    }
-    win->end();
-    win->resizable(win);
-    win->show();
-    return(fltk::run());
-}
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/simple-app.app/Contents/Info.plist b/Utilities/FLTK/Fl_Native_File_Chooser/simple-app.app/Contents/Info.plist
deleted file mode 100644
index b283bd2..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/simple-app.app/Contents/Info.plist
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<plist version="0.9">
-    <dict>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleExecutable</key>
-	<string>simple-app</string>
-	<key>CFBundleIdentifier</key>
-	<string>org.fltk.simple-app</string>
-	<key>CFBundleName</key>
-	<string>simple-app</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-    </dict>
-</plist>
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/simple-app.cxx b/Utilities/FLTK/Fl_Native_File_Chooser/simple-app.cxx
deleted file mode 100644
index 3fccb25..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/simple-app.cxx
+++ /dev/null
@@ -1,76 +0,0 @@
-//
-// simple-app.cxx -- simple example application
-//
-// Copyright 2004 by Greg Ercolano.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-// Please keep code 80 column compliant.
-//
-//      10        20        30        40        50        60        70
-//       |         |         |         |         |         |         |
-// 4567890123456789012345678901234567890123456789012345678901234567890123456789
-//
-#include <stdio.h>
-#include <FL/Fl.H>
-#include <FL/fl_ask.H>
-#include <FL/Fl_Window.H>
-#include <FL/Fl_Button.H>
-#include <FL/Fl_Input.H>
-#include <FL/Fl_Native_File_Chooser.H>
-
-// GLOBALS
-Fl_Input *G_filename = NULL;
-
-void Butt_CB(Fl_Widget*, void*) {
-    // Create native chooser
-    Fl_Native_File_Chooser native;
-    native.title("Pick a file");
-    native.type(Fl_Native_File_Chooser::BROWSE_FILE);
-    native.filter("Text\t*.txt\n"
-                  "C Files\t*.{cxx,h,c}");
-    native.preset_file(G_filename->value());
-    // Show native chooser
-    switch ( native.show() ) {
-	case -1: fprintf(stderr, "ERROR: %s\n", native.errmsg()); break;	// ERROR
-	case  1: fprintf(stderr, "*** CANCEL\n"); fl_beep(); break;		// CANCEL
-	default: 								// PICKED FILE
-	    if ( native.filename() )
-		G_filename->value(native.filename());
-	    else
-		G_filename->value("NULL");
-	    break;
-    }
-}
-
-int main() {
-    Fl_Window *win = new Fl_Window(600, 100, "FLTK Window");
-    win->begin();			// (for symmetry with fltk2)
-    {
-	int y = 10;
-	G_filename = new Fl_Input(80, y, win->w()-80-10, 25, "Filename");
-	G_filename->value(".");
-	G_filename->tooltip("Default filename");
-	y += G_filename->h() + 5;
-	Fl_Button *but = 
-	    new Fl_Button(win->w()-80-10, win->h()-25-10, 80, 25, "Pick File");
-	but->callback(Butt_CB);
-    }
-    win->end();
-    win->resizable(win);
-    win->show();
-    return(Fl::run());
-}
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/test-browser-fltk2.cxx b/Utilities/FLTK/Fl_Native_File_Chooser/test-browser-fltk2.cxx
deleted file mode 100644
index 395c4d4..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/test-browser-fltk2.cxx
+++ /dev/null
@@ -1,299 +0,0 @@
-//
-// test-browser.cxx -- test the NativeFileChooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-// FLTK2 port by Frederic Hoerni 2007.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-// Please keep code 80 column compliant.
-//
-//      10        20        30        40        50        60        70
-//       |         |         |         |         |         |         |
-// 4567890123456789012345678901234567890123456789012345678901234567890123456789
-//
-#include <fltk/run.h>
-#include <fltk/Window.h>
-#include <fltk/Widget.h>
-#include <fltk/Button.h>
-#include <fltk/Choice.h>
-#include <fltk/Input.h>
-#include <fltk/MultiLineInput.h>
-#include <fltk/MultiLineOutput.h>
-#include <fltk/ValueInput.h>
-#include <fltk/MultiBrowser.h>
-#include <fltk/NativeFileChooser.h>
-
-#ifdef _WIN32
-// WINDOWS //
-#include <direct.h>
-#define getcwd _getcwd
-#define MAXPATHLEN MAX_PATH
-#else
-// UNIX //
-#include <sys/param.h>
-#include <unistd.h>
-#include <stdlib.h>
-#endif
-
-// GLOBALS
-fltk::NativeFileChooser *G_choo = NULL;
-fltk::Browser             *G_type = NULL;
-fltk::MultiBrowser        *G_options = NULL;
-fltk::Input               *G_directory = NULL;
-fltk::Input               *G_title = NULL;
-fltk::Input               *G_preset_file = NULL;
-fltk::MultiLineOutput     *G_result = NULL;
-fltk::MultiLineInput      *G_filter = NULL;
-fltk::ValueInput          *G_filter_value = NULL;
-
-void Butt_CB(fltk::Widget*w, void*) {
-
-    // TYPE OF CHOOSER
-    switch ( G_type->value() ) {
-	case 0: G_choo->type(fltk::NativeFileChooser::BROWSE_FILE);            break;
-	case 1: G_choo->type(fltk::NativeFileChooser::BROWSE_DIRECTORY);       break;
-	case 2: G_choo->type(fltk::NativeFileChooser::BROWSE_MULTI_FILE);      break;
-	case 3: G_choo->type(fltk::NativeFileChooser::BROWSE_MULTI_DIRECTORY); break;
-	case 4: G_choo->type(fltk::NativeFileChooser::BROWSE_SAVE_FILE);       break;
-    }
-
-    // OPTIONS
-    {
-	int flags = 0;
-	if ( G_options->selected(0) ) flags |= fltk::NativeFileChooser::SAVEAS_CONFIRM;
-	if ( G_options->selected(1) ) flags |= fltk::NativeFileChooser::NEW_FOLDER;
-	if ( G_options->selected(2) ) flags |= fltk::NativeFileChooser::PREVIEW;
-	G_choo->options(flags);
-    }
-
-    // DIRECTORY
-    if ( G_directory->value()[0] ) {
-	if ( strcmp(G_directory->value(), "NULL") == 0 ) {
-	    G_choo->directory(NULL);
-	} else {
-	    G_choo->directory(G_directory->value());
-	}
-    } else {
-	G_choo->directory(NULL);
-    }
-
-    // PRESET FILE
-    if ( G_preset_file->value()[0] ) {
-	if ( strcmp(G_preset_file->value(), "NULL") == 0 ) {
-	    G_choo->preset_file(NULL);
-	} else {
-	    G_choo->preset_file(G_preset_file->value());
-	}
-    } else {
-	G_choo->preset_file(NULL);
-    }
-
-    // TITLE
-    if ( G_title->value()[0] ) {
-	if ( strcmp(G_title->value(), "NULL") == 0 ) {
-	    G_choo->title(NULL);
-	} else {
-	    G_choo->title(G_title->value());
-	}
-    } else {
-	G_choo->title("");
-    }
-
-    // FILTERS
-    if ( G_filter->value()[0] ) {
-	if ( strcmp(G_filter->value(), "NULL") == 0 ) {
-	    G_choo->filter(NULL);
-	} else {
-	    G_choo->filter(G_filter->value());
-	}
-    } else {
-	G_choo->filter("");		// all files
-    }
-
-    G_choo->filter_value((int)G_filter_value->value());
-
-    switch ( G_choo->show() ) {
-	case -1:	// ERROR
-	    fprintf(stderr, "*** ERROR show():%s\n", G_choo->errmsg());
-	    break;
-
-	case 1:		// CANCEL
-	    fprintf(stderr, "*** CANCEL\n");
-	    break;
-
-	default:
-	    break;
-    }
-
-    // UPDATE SETTINGS RETURNED BY CHOOSER INTO BROWSER
-
-    // RESULT
-    {
-	int count = G_choo->count();
-	int bytes = 0;
-	if ( count > 0 ) {
-	    int t;
-	    for ( t=0; t<count; t++ ) {
-	        bytes += strlen(G_choo->filename(t)) + 2;
-		if ( count > 1 )
-		    fprintf(stderr, "MULTI FILENAME RESULT %d) '%s'\n",
-			t, G_choo->filename(t));
-		else
-		    fprintf(stderr, "FILENAME RESULT '%s'\n",
-			G_choo->filename(t));
-	    }
-	    char *s = new char[bytes];
-	    s[0] = '\0';
-	    for ( t=0; t<count; t++ ) {
-	        strcat(s, G_choo->filename(t));
-		strcat(s, "\n");
-	    }
-	    G_result->value(s);
-	    delete [] s;
-	}
-    }
-
-    // FILTER VALUE
-    G_filter_value->value(G_choo->filter_value());
-    fprintf(stderr, "FILTER VALUE USED: %d\n", G_choo->filter_value());
-
-    // PRESET FILE
-    {
-	const char *s = G_choo->preset_file();
-	G_preset_file->value(s ? s : "NULL");
-	fprintf(stderr, "    PRESET_FILE(): %s\n", G_choo->preset_file());
-    }
-
-    // DIRECTORY
-    {
-	const char *s = G_choo->directory();
-	G_directory->value(s ? s : "NULL");
-	fprintf(stderr, "      DIRECTORY(): %s\n", G_choo->directory());
-    }
-
-    fprintf(stderr, "\n");
-}
-
-int main() {
-    char *start_filter =
-      "Source Code\t*.{cxx,h,H,cpp}\n"\
-      "Cxx Only\t*.cxx\n"\
-      "Text\t*.{txt}\n"\
-      "Makefiles\tMakefile*\n"\
-      "All image files \t*.{BMP,CUT,DDS,GIF,ICO,IFF,LBM,JNG,JPG,JPEG,JPE,JIF,KOA,"
-                          "MNG,PBM,PCD,PCX,PGM,PNG,PPM,PSD,RAS,TGA,TIF,TIFF,WBMP,"
-                          "XBM,XPM}\n"\
-      "Windows, OS/2 Bitmap (*.BMP)\n"\
-      "Dr. Halo (*.CUT)\n"\
-      "DirectDraw Surface (*.DDS)\t*.DDS\n"\
-      "Graphic Interchange Format (*.GIF)\t*.GIF\n"\
-      "Windows Icon (*.ICO)\t*.ICO\n"\
-      "Amiga IFF (*.IFF;*.LBM)\t*.{IFF,LBM}\n"\
-      "JBIG (*.JBIG)\t*.JBIG\n"\
-      "JPEG Network Graphics (*.JNG)\t*.JNG\n"\
-      "Independent JPEG Group (*.JPG;*.JPEG;*.JPE;*.JIF)\t*.{JPG,JIF,JPEG,JPE}\n"\
-      "Commodore 64 Koala (*.KOA)\t*.KOA\n"\
-      "Multiple Network Graphics (*.MNG)\t*.MNG\n"\
-      "Portable Bitmap (*.PBM)\t*.PBM\n"\
-      "Kodak PhotoCD (*.PCD)\t*.PCD\n"\
-      "PC Paintbrush Bitmap (*.PCX)\t*.PCX\n"\
-      "Portable Graymap (*.PGM)\t*.PGM\n"\
-      "Portable Network Graphics (*.PNG)\t*.PNG\n"\
-      "Portable Pixelmap (*.PPM)\t*.PPM\n"\
-      "Photoshop Document (*.PSD)\t*.PSD\n"\
-      "Sun Raster Graphic (*.RAS)\t*.RAS\n"\
-      "Targa (*.TGA)\t*.TGA\n"\
-      "Tagged Image File Format (*.TIF;*.TIFF)\t*.{TIF,TIFF}\n"\
-      "Wireless Bitmap (*.WBMP)\t*.WBMP\n"\
-      "X11 Bitmap (*.XBM)\t*.XBM\n"\
-      "X11 Pixmap (*.XPM)\t*.XPM";
-
-    char start_dir[MAXPATHLEN + 1];
-    getcwd(start_dir, MAXPATHLEN);
-
-    char start_file[MAXPATHLEN + 1];
-    strcpy(start_file, "testfile");
-
-    fltk::Window *win = new fltk::Window(600, 520, "Test Browser (FLTK2)");
-
-    win->begin();
-    {
-	int y = 20;
-
-	G_type = new fltk::Browser(10,y,180,120,"Type");
-	G_type->add("Single File");
-	G_type->add("Single Directory");
-	G_type->add("Multi File");
-	G_type->add("Multi Directory");
-	G_type->add("Save File");
-	G_type->textsize(12);
-	G_type->value(0);
-	G_type->tooltip("Type of browser to use");
-
-	G_options = new fltk::MultiBrowser(win->w()-180-10,y,180,120,"Options");
-	G_options->add("Show SaveAs Confirm");
-	G_options->add("Show New Folder");
-	G_options->add("Show Previews");
-	G_options->tooltip("Platform specific options.\nSeveral can be selected.");
-	G_options->textsize(12);
-	
-	y += G_type->h() + 10 + 20;
-
-	G_title = new fltk::Input(80, y, win->w()-80-10, 25, "Title");
-	G_title->value("Title Of Window");
-	G_title->tooltip("Sets title of browser window\nSet this to 'NULL' for a NULL setting");
-	y += G_title->h() + 5;
-
-	G_directory = new fltk::Input(80, y, win->w()-80-10, 25, "Directory");
-	G_directory->value(start_dir);
-	G_directory->tooltip("Starting directory shown in browser\nSet this to 'NULL' for a NULL setting");
-	y += G_directory->h() + 5;
-
-	G_preset_file = new fltk::Input(80, y, win->w()-80-10, 25, "Preset File");
-	G_preset_file->value(start_file);
-	G_preset_file->tooltip("Default filename used for 'Save File' chooser\nSet this to 'NULL' for a NULL setting");
-	y += G_preset_file->h() + 5;
-
-	G_filter = new fltk::MultiLineInput(80, y, win->w()-80-10, 75, "Filter");
-	G_filter->value(start_filter);
-	G_filter->tooltip("Filter(s) to be available to user\n"
-			      "Multiple filters should be specified on separate lines\n"
-			      "Set this to 'NULL' for a NULL setting");
-	y += G_filter->h() + 5;
-
-	G_filter_value = new fltk::ValueInput(80, y, win->w()-80-10, 25, "Filter Value");
-	G_filter_value->value(0);
-	G_filter_value->step(1.0);
-	G_filter_value->range(0.0,50.0);
-	G_filter_value->tooltip("Index number of the filter to be applied when browser opens.");
-	y += G_filter_value->h() + 5;
-
-	G_result = new fltk::MultiLineOutput(80, y, win->w()-80-10, 100, "Result");
-	G_result->color(51);
-
-	fltk::Button *but = new fltk::Button(win->w()-80-10, win->h()-25-10, 80, 25, "Browser");
-	but->callback(Butt_CB);
-	y += but->h() + 10;
-
-	G_choo = new fltk::NativeFileChooser();
-	G_choo->type(fltk::NativeFileChooser::BROWSE_FILE);
-    }
-    win->end();
-    win->resizable(win);
-    win->show();
-    return(fltk::run());
-}
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/test-browser.app/Contents/Info.plist b/Utilities/FLTK/Fl_Native_File_Chooser/test-browser.app/Contents/Info.plist
deleted file mode 100644
index 2b642d5..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/test-browser.app/Contents/Info.plist
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<plist version="0.9">
-    <dict>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleExecutable</key>
-	<string>test-browser</string>
-	<key>CFBundleIdentifier</key>
-	<string>org.fltk.test-browser</string>
-	<key>CFBundleName</key>
-	<string>test-browser</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-    </dict>
-</plist>
diff --git a/Utilities/FLTK/Fl_Native_File_Chooser/test-browser.cxx b/Utilities/FLTK/Fl_Native_File_Chooser/test-browser.cxx
deleted file mode 100644
index 587103b..0000000
--- a/Utilities/FLTK/Fl_Native_File_Chooser/test-browser.cxx
+++ /dev/null
@@ -1,304 +0,0 @@
-//
-// test-browser.cxx -- test the Fl_Native_File_Chooser widget
-//
-// Copyright 2004 by Greg Ercolano.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-// Please keep code 80 column compliant.
-//
-//      10        20        30        40        50        60        70
-//       |         |         |         |         |         |         |
-// 4567890123456789012345678901234567890123456789012345678901234567890123456789
-//
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include <FL/Fl_Button.H>
-#include <FL/Fl_Choice.H>
-#include <FL/Fl_Input.H>
-#include <FL/Fl_Multiline_Input.H>
-#include <FL/Fl_Multiline_Output.H>
-#include <FL/Fl_Value_Input.H>
-#include <FL/Fl_Hold_Browser.H>
-#include <FL/Fl_Multi_Browser.H>
-#include <FL/Fl_Native_File_Chooser.H>
-
-#ifdef _WIN32
-// WINDOWS //
-#include <direct.h>
-#define getcwd _getcwd
-#define MAXPATHLEN MAX_PATH
-#else
-// UNIX //
-#include <sys/param.h>
-#include <unistd.h>
-#include <stdlib.h>
-#endif
-
-// GLOBALS
-Fl_Native_File_Chooser *G_choo = NULL;
-Fl_Hold_Browser        *G_type = NULL;
-Fl_Multi_Browser       *G_options = NULL;
-Fl_Input               *G_directory = NULL;
-Fl_Input               *G_title = NULL;
-Fl_Input               *G_preset_file = NULL;
-Fl_Multiline_Output    *G_result = NULL;
-Fl_Multiline_Input     *G_filter = NULL;
-Fl_Value_Input         *G_filter_value = NULL;
-
-void Butt_CB(Fl_Widget*w, void*) {
-
-    // TYPE OF CHOOSER
-    switch ( G_type->value() ) {
-	case 1: G_choo->type(Fl_Native_File_Chooser::BROWSE_FILE);            break;
-	case 2: G_choo->type(Fl_Native_File_Chooser::BROWSE_DIRECTORY);       break;
-	case 3: G_choo->type(Fl_Native_File_Chooser::BROWSE_MULTI_FILE);      break;
-	case 4: G_choo->type(Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY); break;
-	case 5: G_choo->type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);       break;
-    }
-
-    // OPTIONS
-    {
-	int flags = 0;
-	if ( G_options->selected(1) ) 
-	    flags |= Fl_Native_File_Chooser::SAVEAS_CONFIRM;
-	if ( G_options->selected(2) )
-	    flags |= Fl_Native_File_Chooser::NEW_FOLDER;
-	if ( G_options->selected(3) )
-	    flags |= Fl_Native_File_Chooser::PREVIEW;
-	G_choo->options(flags);
-    }
-
-    // DIRECTORY
-    if ( G_directory->value()[0] ) {
-	if ( strcmp(G_directory->value(), "NULL") == 0 ) {
-	    G_choo->directory(NULL);
-	} else {
-	    G_choo->directory(G_directory->value());
-	}
-    } else {
-	G_choo->directory(NULL);
-    }
-
-    // PRESET FILE
-    if ( G_preset_file->value()[0] ) {
-	if ( strcmp(G_preset_file->value(), "NULL") == 0 ) {
-	    G_choo->preset_file(NULL);
-	} else {
-	    G_choo->preset_file(G_preset_file->value());
-	}
-    } else {
-	G_choo->preset_file(NULL);
-    }
-
-    // TITLE
-    if ( G_title->value()[0] ) {
-	if ( strcmp(G_title->value(), "NULL") == 0 ) {
-	    G_choo->title(NULL);
-	} else {
-	    G_choo->title(G_title->value());
-	}
-    } else {
-	G_choo->title("");
-    }
-
-    // FILTERS
-    if ( G_filter->value()[0] ) {
-	if ( strcmp(G_filter->value(), "NULL") == 0 ) {
-	    G_choo->filter(NULL);
-	} else {
-	    G_choo->filter(G_filter->value());
-	}
-    } else {
-	G_choo->filter("");		// all files
-    }
-
-    G_choo->filter_value((int)G_filter_value->value());
-
-    switch ( G_choo->show() ) {
-	case -1:	// ERROR
-	    fprintf(stderr, "*** ERROR show():%s\n", G_choo->errmsg());
-	    break;
-
-	case 1:		// CANCEL
-	    fprintf(stderr, "*** CANCEL\n");
-	    break;
-
-	default:
-	    break;
-    }
-
-    // UPDATE SETTINGS RETURNED BY CHOOSER INTO BROWSER
-
-    // RESULT
-    {
-	int count = G_choo->count();
-	int bytes = 0;
-	if ( count > 0 ) {
-	    int t;
-	    for ( t=0; t<count; t++ ) {
-	        bytes += strlen(G_choo->filename(t)) + 2;
-		if ( count > 1 )
-		    fprintf(stderr, "MULTI FILENAME RESULT %d) '%s'\n",
-			t, G_choo->filename(t));
-		else
-		    fprintf(stderr, "FILENAME RESULT '%s'\n",
-			G_choo->filename(t));
-	    }
-	    char *s = new char[bytes];
-	    s[0] = '\0';
-	    for ( t=0; t<count; t++ ) {
-	        strcat(s, G_choo->filename(t));
-		strcat(s, "\n");
-	    }
-	    G_result->value(s);
-	    delete [] s;
-	}
-    }
-
-    // FILTER VALUE
-    G_filter_value->value(G_choo->filter_value());
-    fprintf(stderr, "FILTER VALUE USED: %d\n", G_choo->filter_value());
-
-    // PRESET FILE
-    {
-	const char *s = G_choo->preset_file();
-	G_preset_file->value(s ? s : "NULL");
-	fprintf(stderr, "    PRESET_FILE(): %s\n", G_choo->preset_file());
-    }
-
-    // DIRECTORY
-    {
-	const char *s = G_choo->directory();
-	G_directory->value(s ? s : "NULL");
-	fprintf(stderr, "      DIRECTORY(): %s\n", G_choo->directory());
-    }
-
-    fprintf(stderr, "\n");
-}
-
-int main() {
-    
-//  char *start_filter = "Text\t*.txt\nC Files\t*.{cxx,h,c}";
-    char *start_filter =
-      "Source Code\t*.{cxx,h,H,cpp}\n"\
-      "Cxx Only\t*.cxx\n"\
-      "Text\t*.{txt}\n"\
-      "Makefiles\tMakefile*\n"\
-      "All image files\t*.{BMP,CUT,DDS,GIF,ICO,IFF,LBM,JNG,JPG,JPEG,JPE,JIF,KOA,"
-                          "MNG,PBM,PCD,PCX,PGM,PNG,PPM,PSD,RAS,TGA,TIF,TIFF,WBMP,"
-                          "XBM,XPM}\n"\
-      "Windows, OS/2 Bitmap (*.BMP)\t*.bmp\n"\
-      "Dr. Halo (*.CUT)\t*.CUT\n"\
-      "DirectDraw Surface (*.DDS)\t*.DDS\n"\
-      "Graphic Interchange Format (*.GIF)\t*.GIF\n"\
-      "Windows Icon (*.ICO)\t*.ICO\n"\
-      "Amiga IFF (*.IFF;*.LBM)\t*.{IFF,LBM}\n"\
-      "JBIG (*.JBIG)\t*.JBIG\n"\
-      "JPEG Network Graphics (*.JNG)\t*.JNG\n"\
-      "Independent JPEG Group (*.JPG;*.JPEG;*.JPE;*.JIF)\t*.{JPG,JIF,JPEG,JPE}\n"\
-      "Commodore 64 Koala (*.KOA)\t*.KOA\n"\
-      "Multiple Network Graphics (*.MNG)\t*.MNG\n"\
-      "Portable Bitmap (*.PBM)\t*.PBM\n"\
-      "Kodak PhotoCD (*.PCD)\t*.PCD\n"\
-      "PC Paintbrush Bitmap (*.PCX)\t*.PCX\n"\
-      "Portable Graymap (*.PGM)\t*.PGM\n"\
-      "Portable Network Graphics (*.PNG)\t*.PNG\n"\
-      "Portable Pixelmap (*.PPM)\t*.PPM\n"\
-      "Photoshop Document (*.PSD)\t*.PSD\n"\
-      "Sun Raster Graphic (*.RAS)\t*.RAS\n"\
-      "Targa (*.TGA)\t*.TGA\n"\
-      "Tagged Image File Format (*.TIF;*.TIFF)\t*.{TIF,TIFF}\n"\
-      "Wireless Bitmap (*.WBMP)\t*.WBMP\n"\
-      "X11 Bitmap (*.XBM)\t*.XBM\n"\
-      "X11 Pixmap (*.XPM)\t*.XPM";
-
-    char start_dir[MAXPATHLEN + 1];
-    getcwd(start_dir, MAXPATHLEN);
-
-    char start_file[MAXPATHLEN + 1];
-    strcpy(start_file, "testfile");
-
-    Fl_Window *win = new Fl_Window(600, 520, "Test Browser (FLTK1)");
-
-    int y = 20;
-
-    G_type = new Fl_Hold_Browser(10,y,180,120,"Type");
-    G_type->add("Single File");
-    G_type->add("Single Directory");
-    G_type->add("Multi File");
-    G_type->add("Multi Directory");
-    G_type->add("Save File");
-    G_type->textsize(12);
-    G_type->value(1);
-    G_type->tooltip("Type of browser to use");
-
-    G_options = new Fl_Multi_Browser(win->w()-180-10,y,180,120,"Options");
-    G_options->add("Show SaveAs Confirm");
-    G_options->add("Show New Folder");
-    G_options->add("Show Previews");
-    G_options->tooltip("Platform specific options.\nSeveral can be selected.");
-    G_options->textsize(12);
-
-    y += G_type->h() + 10 + 20;
-
-    G_title = new Fl_Input(80, y, win->w()-80-10, 25, "Title");
-    G_title->value("Title Of Window");
-    G_title->tooltip("Sets title of browser window\n"
-                     "Set this to 'NULL' for a NULL setting");
-    y += G_title->h() + 5;
-
-    G_directory = new Fl_Input(80, y, win->w()-80-10, 25, "Directory");
-    G_directory->value(start_dir);
-    G_directory->tooltip("Starting directory shown in browser\n"
-                         "Set this to 'NULL' for a NULL setting");
-    y += G_directory->h() + 5;
-
-    G_preset_file = new Fl_Input(80, y, win->w()-80-10, 25, "Preset File");
-    G_preset_file->value(start_file);
-    G_preset_file->tooltip("Default filename used for 'Save File' chooser\n"
-                           "Set this to 'NULL' for a NULL setting");
-    y += G_preset_file->h() + 5;
-
-    G_filter = new Fl_Multiline_Input(80, y, win->w()-80-10, 75, "Filter");
-    G_filter->value(start_filter);
-    G_filter->tooltip("Filter(s) to be available to user\n"
-		      "Multiple filters should be specified on separate lines\n"
-		      "Set this to 'NULL' for a NULL setting");
-    y += G_filter->h() + 5;
-
-    G_filter_value = 
-        new Fl_Value_Input(80, y, win->w()-80-10, 25, "Filter Value");
-    G_filter_value->value(0);
-    G_filter_value->tooltip("Index number of the filter to be applied "
-                            "when browser opens.");
-    y += G_filter_value->h() + 5;
-
-    G_result = new Fl_Multiline_Output(80, y, win->w()-80-10, 100, "Result");
-    G_result->color(51);
-
-    Fl_Button *but = 
-        new Fl_Button(win->w()-80-10, win->h()-25-10, 80, 25, "Browser");
-    but->callback(Butt_CB);
-    y += but->h() + 10;
-
-    G_choo = new Fl_Native_File_Chooser();
-    G_choo->type(Fl_Native_File_Chooser::BROWSE_FILE);
-
-    win->resizable(win);
-    win->show();
-    return(Fl::run());
-}
diff --git a/Utilities/FLTK/Fl_Table/CHANGES b/Utilities/FLTK/Fl_Table/CHANGES
deleted file mode 100644
index 186b3fe..0000000
--- a/Utilities/FLTK/Fl_Table/CHANGES
+++ /dev/null
@@ -1,289 +0,0 @@
-3.13 -- 04/08/09 -- Non-critical additions to example programs
-
-	o Added simple-display-table.cxx example
-
-	o Added cell fg/bg color control to exercisetablerow example
-
-	o Added 'documentation/how-to-use.html' (snuck into tar file 05/07/09)
-
-	o Converted Makefile's to use 'fltk-config'
-
-	o Fix for Ivica Lazarevic's row_position() bug report on 03/16/09
-
-	o Converted all code to FLTK brace and 2-space indent style
-
-	o Added some comments to documentation examples
-
-3.12 -- 04/02/06 -- Misc optimizations and non-critical additions
-
-        o 04/02/06: Small fix to exercisetablerow's Type: menu
-
-        o 04/02/06: Added Ori Berger's optimizations for push_back() -> size()/fill
-
-        o 04/02/06: default compiles for FLTK 1.1.7
-
-        o 04/02/06: [INTERNAL] 'make tar' now inserts version# into tarfile
-
-        o 02/21/05: John Taber's modifications for singleinput draw_cell() prototype
-
-3.11 -- 08/13/04 erco: added box(val) which now calls resize() to recalculate table.
-
-3.10 -- 02/22/04 erco: misc fixes, added Jean Marc's keyboard nav!
-
-	o Merged in Jean Marc's keyboard navigation and
-	  rectangular mouse selection. Tested OK on IRIX/LINUX/WINDOWS/OSX.
-
-	o Added Jean Marc's testkeyboardnav.cxx example showing how to use
-	  new keyboard nav and mouse region selection.
-
-	o TODO: Need to make mouse region selection controllable via
-	  'or'able flags:
-
-	  	> Single cell					(SELECT_CELL)
-		> Row of cells (eg. Fl_Browser, Fl_Table_Row)	(SELECT_ROW)
-		> Column of cells		      		(SELECT_COL)
-		> Freeform row/col (current behavior) 		(SELECT_MULTI)
-
-	  Implement as Fl_Table::type().
-	  
-	o Erco's mods to Jean Marc's additions:
-
-	    > Re-enabled resizing cursor
-
-	    > Some whitespace reformatting, added some comments
-
-	    > Added //FALLTHROUGH comments
-
-	    > Moved auto_drag_cb2() to just above auto_drag_cb()
-
-	    > Added Windows specific code to Fl_Table::change_cursor() to 
-	      work around a cursor problem with fltk-utf8-1.1.4.
-
-	o Added SINGLE/MULTI/NONE selection behavior.
-	  See Fl_Table_Row::type()
-
-	o Doc fixes as per dsnpa's email on 08/11/03
-
-	o CONTEXT_NEWPAGE retired as per obsolete warnings.
-	  Use CONTEXT_STARTPAGE instead.
-
-3.01 -- 08/10/03 erco: minor fixes
-
-	o Fl_Table::children() return a number two less than
-	  table->children(), to skip over Fl_Scroll's scrollbars.
-
-        o Fl_Table::handle(): prevented unwanted callback() for 
-	  downclick event during interactive resize. This was 
-	  causing sort buttons to be triggered unexpectedly 
-	  during interactive column resizing.
-
-	o sortapp: changed sort arrow from black triangle 
-	  to an engraved triangle.
-
-	o Added Fl_Table::is_interactive_resize()
-
-	o Docs updated to elaborate on callback() management.
-
-	o callback() now invoked with CONTEXT_RC_RESIZE 
-	  when columns or rows are resized via the API,
-	  eg. with col_width() or row_height().
-
-        o Fixed doc bug: Fl_Table::child() and Fl_Table::children() 
-	  were not documented, and some old development ideas were 
-	  in their place. Fixed, and added to the web docs.
-
-3.00 -- 06/28/03 erco: Major changes, callback() API modified
-
-        o Prevented unwanted auto-scrolling during col/row resizing
-
-        o No longer invokes callback if mouse button pressed in
-	  one row, and released in another.
-
-	o Fl_Table::visible_cells() added for irush and for Ori Berger 
-	  (fltk.general, 06/25/03)
-
-	o Fl_Table::rows() and cols() are now virtual for Glenn Ramsey 
-	  (fltk.general 06/25/03)
-
-	o Fl_Table::clear() made virtual.
-
-	o Now handles drawing row_headers when there are no rows,
-	  and handles drawing col_headers when there are no columns.
-
-	o On FL_LEAVE, force cursor to normal 'just in case'
-
-        o Fixed clipping when window sized /very/ small, so scroll
-	  bars don't 'leak' outside the widget.
-
-	o OPTIMIZATION: Fl_Table::table_resized() no longer 
-	  calls redraw(). If you want redraw() after calling
-	  table_resized(), you must call it explicitly.
-
-	o OPTIMIZATION: Adding rows which are offscreen no
-	  longer causes entire table to redraw, only the vertical
-	  scrollbar.
-
-        o callback() system called when rows/cols interactively
-	  resized too, sent CONTEXT_RC_RESIZE.
-
-	o Fl_Table and Fl_Table_Row: moved handle()'s static state vars
-	  into the class to avoid crosstalk between multiple instances.
-
-3.00 alpha 2 -- 06/01/03 erco
-
-        o Also modified exercisetablerow.cxx, sortapp.cxx and
-	  singleinput.cxx to follow the fltk callback() convention.
-
-	o Fixed Makefile.IRIX -- missing REZCOMMAND
-
-3.00 alpha -- 06/01/03 erco
-
-        o Refitted with the normal fltk callback() / when() conventions,
-	  to replace the old Fl_Table callback() virtual stuff.
-
-	  ALPHA TESTERS: Please see table_cb() function in testtablerow.cxx,
-	  and docs in documentation/Fl_Table.html for new methods:
-
-	       callback() -- set the callback
-	       callback_row() -- row the user clicked on
-	       callback_col() -- column the user clicked on
-	       callback_context() -- where on table the user clicked
-
-2.15 -- 05/28/03 erco
-        
-	o Docs for select_row() includes documenting 2=toggle.
-
-	o select_all_rows() modified to include 2=toggle, docs modified.
-
-2.14 -- 05/27/03 erco
-
-	o Reduced flicker for row selections, added some private 
-	  methods (Fl_Table::_redraw_cell()) and data (_redraw_leftcol),
-	  and a protected method redraw_range() to Fl_Table. 
-	  Fl_Table::draw() modified to use damage(FL_DAMAGE_CHILD).
-
-	o Updated Fl_Table_Row docs: docs for all public methods
-
-	o Added Fl_Table::clear() method
-
-	o Fl_Table::scroll_cb() now calls recalc_dimensions();
-	  vars like tix, tiy weren't being recalculated.
-
-	o Changed Fl_Table_Row::handle() from private -> protected
-
-	o Optimizations to row_scroll_position() and col_scroll_position()
-	  to allow 100,000 x 100,000 element tables to redraw quickly:
-	      BEFORE: ~5 sec redraws for the lower right corner of the table.
-	      AFTER: imperceptible redraw time for entire table.
-	  Added two private vars (toprow_scrollpos, leftcol_scrollpos)
-
-	o Updated README to include a 'What is Fl_Table?' section, 
-	  as there seems to be some confusion about what Fl_Table is
-	  and is not.
-
-	o 'singleinput' compile instructions were missing from the
-	  Makefile.MICROSOFT
-
-        o fltk-config: tried to implement in unix Makefiles, but
-          encountered a hitch with multiple FLTK versions. 
-	  Holding back on adding fltk-config until resolved.
-
-2.13 -- 05/17/03 erco
-
-        o Removed all iostream stuff -- sick of all that noise
-	  about 'deprecated headers' under Redhat 9.0 and VS .NET.
-
-        o Changed having Fl_Table_Row::handle() from returning if
-	  a child handled an event; caused new FL_PUSH mod to break
-	  selection routines.
-
-	o Changed sortapp to show ls listing instead of 'cat README'
-
-	o Implemented Glenn Ramsey's recommendation to set ret = 1
-	  on receipt of FL_PUSH.
-
-	o Modified singleinput.cxx to call take_focus() to ensure
-	  it works correctly when parented by e.g. Fl_Tabs.
-
-	o Added -lXft to Makefile.LINUX to support antialiased fonts
-	  under Redhat 9.0
-
-2.13(alpha) -- 04/29/03 erco
-
-	o Marcin Jedlinski reports 'c<newrows;' bug in widgettable.c; fixed.
-
-2.12 -- 04/20/03 erco
-
-	o Added CONTEXT_ENDPAGE, changed CONTEXT_NEWPAGE -> CONTEXT_STARTPAGE
-
-	o Added Mister Satan's singleinput.cxx example to release
-
-	o Applied Mister Satan's fixes for scrollbars appearing 1 pixel
-	  too early. ('hideh/hidev < 0' changed to '.. <= 0')
-
-	o CONTEXT_NEWPAGE sends table dimensions via x/y/w/h, instead of zeroes.
-          Docs changed to reflect this.
-
-	o Added Makefile.MINGW32, and modified uname to truncate at the underbar
-
-	o Fixed 'sortapp' so that it would work with blank lines in the example.
-
-2.11 -- 04/09/03 erco
-
-        o Removed some unused scrollbar event handling
-	o Added CONTEXT_TABLE events when clicked in dead zones
-	o Fixed problem with two Fl_Table or more Fl_Table's (MR SATAN)
-	o Allow setting row_height and col_width w/out any row/cols defined
-	o testtablerow now shows two tables, to test for event problems.
-
-2.10a -- 04/06/03 erco
-
-        o Makefile mods for Microsoft
-	o atoi() #include for Microsoft missing
-	o Removed unused variables causing warnings on SGI
-
-2.10  -- 04/06/03 erco
-
-	o Got widgets away from STL as per Matthais request (only sortapp.cxx has it)
-	o Added table_box() to set the kind of box around the inner table
-	o Added row/col_min_resize()
-	o Cleaned up management of box borders (concept: inside vs. outside)
-	o Fixed some missing line breaks in the docs
-	o Implemented separate Fl_Scroll so Fl_Table can contain fltk widgets
-	o Fixed new row headers so they don't callback() during a resize
-	o Fixed wild select when dragged off table
-	o Select-drag off table now auto-scrolls
-
-2.00  -- 04/02/03 erco
-
-        o Added row headers
-	o Added ability to make it easy to add fltk widgets to the table
-	o You can now set row/col header colors and heights/widths
-	o Fixed drawing problems with table deadzones
-
-1.30  -- 03/30/03 erco
-
-        o Added widgettable.cxx
-	o Mods to Fl_Table to facilitate embeding fltk widget
-
-1.20  -- 03/18/03 erco
-
-	o Modified sortapp.cxx: sort direction indicated by 
-	  up/down arrow in header
-
-        o Makefiles for complile/run on Linux, OSX, Windows, IRIX.
-	  Tested under Linux, OSX, Windows, but not IRIX (didn't have
-	  vector library under 6.2)
-
-	o Verified compiles and runs ok with fltk 1.1.1 and 1.1.3
-
-1.10  -- 01/09/03 erco
-
-	o Mods for bcc (thanks to Marek Paliwoda)
-	o Removed MyTable.cxx, an old file
-	o Added 'make tar' target
-	o Added CHANGES log
-
-1.00  -- 12/16/02 erco
-
-	o Initial implementation/release
diff --git a/Utilities/FLTK/Fl_Table/CMakeLists.txt b/Utilities/FLTK/Fl_Table/CMakeLists.txt
deleted file mode 100644
index a02f89a..0000000
--- a/Utilities/FLTK/Fl_Table/CMakeLists.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-INCLUDE_DIRECTORIES(${SNAP_SOURCE_DIR}/Utilities/FLTK/Fl_Table/FL)
-INCLUDE_DIRECTORIES(${SNAP_SOURCE_DIR}/Utilities/FLTK/Fl_Table)
-ADD_LIBRARY(fltk_table Fl_Table.cxx Fl_Table_Row.cxx)
diff --git a/Utilities/FLTK/Fl_Table/COPYING b/Utilities/FLTK/Fl_Table/COPYING
deleted file mode 100644
index 8979dc8..0000000
--- a/Utilities/FLTK/Fl_Table/COPYING
+++ /dev/null
@@ -1,528 +0,0 @@
-                           Fl_Table License
-                           December 16, 2002
-
-The Fl_Table library and included programs are provided under the terms
-of the GNU Library General Public License (LGPL) with the following
-exceptions:
-
-    1. Modifications to the Fl_Table configure script, config
-       header file, and makefiles by themselves to support
-       a specific platform do not constitute a modified or
-       derivative work.
-
-       The authors do request that such modifications be
-       contributed to the Fl_Table project - send all
-       contributions to "erco at seriss dot com".
-
-    2. Widgets that are subclassed from Fl_Table widgets do not
-       constitute a derivative work.
-
-    3. Static linking of applications and widgets to the
-       Fl_Table library does not constitute a derivative work
-       and does not require the author to provide source
-       code for the application or widget, use the shared
-       Fl_Table libraries, or link their applications or
-       widgets against a user-supplied version of Fl_Table.
-
-       If you link the application or widget to a modified
-       version of Fl_Table, then the changes to Fl_Table must be
-       provided under the terms of the LGPL in sections
-       1, 2, and 4.
-
-    4. You do not have to provide a copy of the Fl_Table license
-       with programs that are linked to the Fl_Table library, nor
-       do you have to identify the Fl_Table license in your
-       program or documentation as required by section 6
-       of the LGPL.
-
-       However, programs must still identify their use of Fl_Table.
-       The following example statement can be included in user
-       documentation to satisfy this requirement:
-
-           [program/widget] is based in part on the work of
-           the Fl_Table project http://seriss.com/people/erco/fltk/Fl_Table/
-
------------------------------------------------------------------------
-
-		  GNU LIBRARY GENERAL PUBLIC LICENSE
-			 Version 2, June 1991
-
-	  Copyright (C) 1991 Free Software Foundation, Inc.
-       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-     Everyone is permitted to copy and distribute verbatim copies
-      of this license document, but changing it is not allowed.
-
-    [This is the first released version of the library GPL.  It is
-   numbered 2 because it goes with version 2 of the ordinary GPL.]
-
-			       Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
-  This license, the Library General Public License, applies to some
-specially designated Free Software Foundation software, and to any
-other libraries whose authors decide to use it.  You can use it for
-your libraries, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if
-you distribute copies of the library, or if you modify it.
-
-  For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you.  You must make sure that they, too, receive or can get the source
-code.  If you link a program with the library, you must provide
-complete object files to the recipients so that they can relink them
-with the library, after making changes to the library and recompiling
-it.  And you must show them these terms so they know their rights.
-
-  Our method of protecting your rights has two steps: (1) copyright
-the library, and (2) offer you this license which gives you legal
-permission to copy, distribute and/or modify the library.
-
-  Also, for each distributor's protection, we want to make certain
-that everyone understands that there is no warranty for this free
-library.  If the library is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original
-version, so that any problems introduced by others will not reflect on
-the original authors' reputations.
-

-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that companies distributing free
-software will individually obtain patent licenses, thus in effect
-transforming the program into proprietary software.  To prevent this,
-we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
-  Most GNU software, including some libraries, is covered by the ordinary
-GNU General Public License, which was designed for utility programs.  This
-license, the GNU Library General Public License, applies to certain
-designated libraries.  This license is quite different from the ordinary
-one; be sure to read it in full, and don't assume that anything in it is
-the same as in the ordinary license.
-
-  The reason we have a separate public license for some libraries is that
-they blur the distinction we usually make between modifying or adding to a
-program and simply using it.  Linking a program with a library, without
-changing the library, is in some sense simply using the library, and is
-analogous to running a utility program or application program.  However, in
-a textual and legal sense, the linked executable is a combined work, a
-derivative of the original library, and the ordinary General Public License
-treats it as such.
-
-  Because of this blurred distinction, using the ordinary General
-Public License for libraries did not effectively promote software
-sharing, because most developers did not use the libraries.  We
-concluded that weaker conditions might promote sharing better.
-
-  However, unrestricted linking of non-free programs would deprive the
-users of those programs of all benefit from the free status of the
-libraries themselves.  This Library General Public License is intended to
-permit developers of non-free programs to use free libraries, while
-preserving your freedom as a user of such programs to change the free
-libraries that are incorporated in them.  (We have not seen how to achieve
-this as regards changes in header files, but we have achieved it as regards
-changes in the actual functions of the Library.)  The hope is that this
-will lead to faster development of free libraries.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.  Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library".  The
-former contains code derived from the library, while the latter only
-works together with the library.
-
-  Note that it is possible for a library to be covered by the ordinary
-General Public License rather than by this special one.
-

-		  GNU LIBRARY GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License Agreement applies to any software library which
-contains a notice placed by the copyright holder or other authorized
-party saying it may be distributed under the terms of this Library
-General Public License (also called "this License").  Each licensee is
-addressed as "you".
-
-  A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
-  The "Library", below, refers to any such software library or work
-which has been distributed under these terms.  A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language.  (Hereinafter, translation is
-included without limitation in the term "modification".)
-
-  "Source code" for a work means the preferred form of the work for
-making modifications to it.  For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
-  Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it).  Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
-  1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
-  You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-

-  2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) The modified work must itself be a software library.
-
-    b) You must cause the files modified to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    c) You must cause the whole of the work to be licensed at no
-    charge to all third parties under the terms of this License.
-
-    d) If a facility in the modified Library refers to a function or a
-    table of data to be supplied by an application program that uses
-    the facility, other than as an argument passed when the facility
-    is invoked, then you must make a good faith effort to ensure that,
-    in the event an application does not supply such function or
-    table, the facility still operates, and performs whatever part of
-    its purpose remains meaningful.
-
-    (For example, a function in a library to compute square roots has
-    a purpose that is entirely well-defined independent of the
-    application.  Therefore, Subsection 2d requires that any
-    application-supplied function or table used by this function must
-    be optional: if the application does not supply it, the square
-    root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library.  To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License.  (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.)  Do not make any other change in
-these notices.
-

-  Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
-  This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
-  4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
-  If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library".  Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
-  However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library".  The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
-  When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library.  The
-threshold for this to be true is not precisely defined by law.
-
-  If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work.  (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
-  Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-

-  6. As an exception to the Sections above, you may also compile or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
-  You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License.  You must supply a copy of this License.  If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License.  Also, you must do one
-of these things:
-
-    a) Accompany the work with the complete corresponding
-    machine-readable source code for the Library including whatever
-    changes were used in the work (which must be distributed under
-    Sections 1 and 2 above); and, if the work is an executable linked
-    with the Library, with the complete machine-readable "work that
-    uses the Library", as object code and/or source code, so that the
-    user can modify the Library and then relink to produce a modified
-    executable containing the modified Library.  (It is understood
-    that the user who changes the contents of definitions files in the
-    Library will not necessarily be able to recompile the application
-    to use the modified definitions.)
-
-    b) Accompany the work with a written offer, valid for at
-    least three years, to give the same user the materials
-    specified in Subsection 6a, above, for a charge no more
-    than the cost of performing this distribution.
-
-    c) If distribution of the work is made by offering access to copy
-    from a designated place, offer equivalent access to copy the above
-    specified materials from the same place.
-
-    d) Verify that the user has already received a copy of these
-    materials or that you have already sent this user a copy.
-
-  For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it.  However, as a special exception,
-the source code distributed need not include anything that is normally
-distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
-  It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system.  Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-

-  7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
-    a) Accompany the combined library with a copy of the same work
-    based on the Library, uncombined with any other library
-    facilities.  This must be distributed under the terms of the
-    Sections above.
-
-    b) Give prominent notice with the combined library of the fact
-    that part of it is a work based on the Library, and explaining
-    where to find the accompanying uncombined form of the same work.
-
-  8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License.  Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License.  However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-  9. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Library or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
-  10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-

-  11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded.  In such case, this License incorporates the limitation as if
-written in the body of this License.
-
-  13. The Free Software Foundation may publish revised and/or new
-versions of the Library General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation.  If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-

-  14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission.  For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this.  Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
-			    NO WARRANTY
-
-  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-

-     Appendix: How to Apply These Terms to Your New Libraries
-
-  If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change.  You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
-  To apply these terms, attach the following notices to the library.  It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the library's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
-
-    This library 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
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the
-  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
-  <signature of Ty Coon>, 1 April 1990
-  Ty Coon, President of Vice
-
-That's all there is to it!
diff --git a/Utilities/FLTK/Fl_Table/CREDITS b/Utilities/FLTK/Fl_Table/CREDITS
deleted file mode 100644
index f780a55..0000000
--- a/Utilities/FLTK/Fl_Table/CREDITS
+++ /dev/null
@@ -1,27 +0,0 @@
-CREDITS - Fl_Table
-------------------
-    This file lists the people responsible for the toolkit you
-    are now using.  If you've looking for your name in lights
-    but we've forgotten you here, please send an email to
-    "fltk-bugs at fltk.org" and we'll update this file accordingly.
-
-CORE DEVELOPERS
-
-    Greg Ercolano     12/16/2002 - initial implementation 12/16/02.
-    				   Fl_Table, Fl_Table_Row, docs.
-
-    Jean-Marc Lienher 02/22/2004 - added keyboard nav + mouse selection, 
-    				   and ported Fl_Table into fltk-utf8-1.1.4
-
-OTHER CONTRIBUTORS
-
-    Inspired by the Feb 2000 version of FLVW's Flvw_Table widget.
-    Mucho thanks to those folks.
-
-    Mister Satan   04/07/2003 - MinGW porting mods, and singleinput.cxx; a cool 
-    		                Fl_Input oriented spreadsheet example
-
-    Marek Paliwoda 01/08/2003 - Porting mods for Borland
-
-    Ori Berger 03/16/2006 - Optimizations for >500k rows/cols
-
diff --git a/Utilities/FLTK/Fl_Table/FL/Fl_Table.H b/Utilities/FLTK/Fl_Table/FL/Fl_Table.H
deleted file mode 100644
index 3dfc184..0000000
--- a/Utilities/FLTK/Fl_Table/FL/Fl_Table.H
+++ /dev/null
@@ -1,451 +0,0 @@
-//
-// Fl_Table -- A table widget
-//
-// Copyright 2002 by Greg Ercolano.
-// Copyright (c) 2004 O'ksi'D
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-// Please report all bugs and problems to "erco at seriss dot com".
-//
-// TODO:
-//    o Auto scroll during dragged selection
-//    o Keyboard navigation (up/down/left/right arrow)
-//
-
-#ifndef _FL_TABLE_H
-#define _FL_TABLE_H
-
-#include <sys/types.h>
-#include <string.h>		// memcpy
-#ifdef _WIN32
-#include <malloc.h>		// WINDOWS: malloc/realloc
-#else /*_WIN32*/
-#include <stdlib.h>		// UNIX: malloc/realloc
-#endif /*_WIN32*/
-
-#include <FL/Fl.H>
-#include <FL/Fl_Group.H>
-#include <FL/Fl_Scroll.H>
-#include <FL/Fl_Box.H>
-#include <FL/Fl_Scrollbar.H>
-
-class Fl_Table : public Fl_Group {
-public:
-  enum TableContext {
-    CONTEXT_NONE       = 0,
-    CONTEXT_STARTPAGE  = 0x01,	// before a page is redrawn
-    CONTEXT_ENDPAGE    = 0x02,	// after a page is redrawn
-    CONTEXT_ROW_HEADER = 0x04,	// in the row header
-    CONTEXT_COL_HEADER = 0x08,	// in the col header
-    CONTEXT_CELL       = 0x10,	// in one of the cells
-    CONTEXT_TABLE      = 0x20,	// in the table
-    CONTEXT_RC_RESIZE  = 0x40 	// column or row being resized
-  };
-
-private:
-  int _rows, _cols;	// total rows/cols
-  int _row_header_w;	// width of row header
-  int _col_header_h;	// height of column header
-  int _row_position;	// last row_position set (not necessarily == toprow!)
-  int _col_position;	// last col_position set (not necessarily == leftcol!)
-
-  char _row_header;	// row header enabled?
-  char _col_header;	// col header enabled?
-  char _row_resize;	// row resizing enabled?
-  char _col_resize;	// col resizing enabled?
-  int _row_resize_min;	// row minimum resizing height (default=1)
-  int _col_resize_min;	// col minimum resizing width (default=1)
-
-  // OPTIMIZATION: partial row/column redraw variables
-  int _redraw_toprow;
-  int _redraw_botrow;
-  int _redraw_leftcol;
-  int _redraw_rightcol;
-  Fl_Color _row_header_color;
-  Fl_Color _col_header_color;
-
-  int _auto_drag;
-  int _selecting;
-
-  // An STL-ish vector without templates
-  class IntVector {
-    int *arr;
-    unsigned int _size;
-    void init() {
-      arr = NULL;
-      _size = 0;
-    }
-    void copy(int *newarr, unsigned int newsize) {
-      size(newsize);
-      memcpy(arr, newarr, newsize * sizeof(int));
-    }
-  public:
-    IntVector() { init(); }					// CTOR
-    ~IntVector() { if ( arr ) free(arr); arr = NULL; }		// DTOR
-    IntVector(IntVector&o) { init(); copy(o.arr, o._size); }	// COPY CTOR
-    IntVector& operator=(IntVector&o) {				// ASSIGN
-      init();
-      copy(o.arr, o._size);
-      return(*this);
-    }
-    int operator[](int x) const { return(arr[x]); }
-    int& operator[](int x) { return(arr[x]); }
-    unsigned int size() { return(_size); }
-    void size(unsigned int count) {
-      if ( count != _size ) {
-        arr = (int*)realloc(arr, count * sizeof(int));
-	_size = count;
-      }
-    }
-    int pop_back() { int tmp = arr[_size-1]; _size--; return(tmp); }
-    void push_back(int val) { unsigned int x = _size; size(_size+1); arr[x] = val; }
-    int back() { return(arr[_size-1]); }
-  };
-
-  IntVector _colwidths;			// column widths in pixels
-  IntVector _rowheights;		// row heights in pixels
-
-  Fl_Cursor _last_cursor;		// last mouse cursor before changed to 'resize' cursor
-
-  // EVENT CALLBACK DATA
-  TableContext _callback_context;	// event context
-  int _callback_row, _callback_col;	// event row/col
-
-  // handle() state variables.
-  //    Put here instead of local statics in handle(), so more
-  //    than one Fl_Table can exist without crosstalk between them.
-  //
-  int _resizing_col;			// column being dragged
-  int _resizing_row;			// row being dragged
-  int _dragging_x;			// starting x position for horiz drag
-  int _dragging_y;			// starting y position for vert drag
-  int _last_row;			// last row we FL_PUSH'ed
-
-  // Redraw single cell
-  void _redraw_cell(TableContext context, int R, int C);
-
-  void _start_auto_drag();
-  void _stop_auto_drag();
-  void _auto_drag_cb();
-  static void _auto_drag_cb2(void *d);
-
-protected:
-  enum ResizeFlag {
-    RESIZE_NONE      = 0,
-    RESIZE_COL_LEFT  = 1,
-    RESIZE_COL_RIGHT = 2,
-    RESIZE_ROW_ABOVE = 3,
-    RESIZE_ROW_BELOW = 4
-  };
-
-  int table_w, table_h;				// table's virtual size (in pixels)
-  int toprow, botrow, leftcol, rightcol;	// four corners of viewable table
-
-  // selection
-  int current_row, current_col;
-  int select_row, select_col;
-
-  // OPTIMIZATION: Precomputed scroll positions for the toprow/leftcol
-  int toprow_scrollpos;
-  int leftcol_scrollpos;
-
-  // Dimensions
-  int tix, tiy, tiw, tih;			// data table inner dimension xywh
-  int tox, toy, tow, toh;			// data table outer dimension xywh
-  int wix, wiy, wiw, wih;			// widget inner dimension xywh
-
-  Fl_Scroll *table;				// container for child fltk widgets (if any)
-  Fl_Scrollbar *vscrollbar; 			// vertical scrollbar
-  Fl_Scrollbar *hscrollbar;			// horizontal scrollbar
-
-  // Fltk
-  int handle(int e);				// fltk handle() override
-
-  // Class maintenance
-  void recalc_dimensions();
-  void table_resized();				// table resized; recalc
-  void table_scrolled();			// table scrolled; recalc
-  void get_bounds(TableContext context,		// return x/y/w/h bounds for context
-		  int &X, int &Y, int &W, int &H);
-  void change_cursor(Fl_Cursor newcursor);	// change mouse cursor to some other shape
-  TableContext cursor2rowcol(int &R, int &C, ResizeFlag &resizeflag);
-					        // find r/c given current x/y event
-  int find_cell(TableContext context,		// find cell's x/y/w/h given r/c
-	       int R, int C, int &X, int &Y, int &W, int &H);
-  int row_col_clamp(TableContext context, int &R, int &C);
-					        // clamp r/c to known universe
-
-  // Called to draw cells
-  virtual void draw_cell(TableContext context, int R=0, int C=0, 
-			 int X=0, int Y=0, int W=0, int H=0)
-      { }					// overridden by deriving class
-
-  long row_scroll_position(int row);		// find scroll position of row (in pixels)
-  long col_scroll_position(int col);		// find scroll position of col (in pixels)
-
-  int is_fltk_container() { 			// does table contain fltk widgets?
-    return( Fl_Group::children() > 3 );		// (ie. more than box and 2 scrollbars?)
-  }
-
-  static void scroll_cb(Fl_Widget*,void*);	// h/v scrollbar callback
-
-  void damage_zone(int r1, int c1, int r2, int c2, int r3 = 0, int c3 = 0);
-
-  void redraw_range(int toprow, int botrow, int leftcol, int rightcol) {
-    if ( _redraw_toprow == -1 ) {
-      // Initialize redraw range
-      _redraw_toprow = toprow;
-      _redraw_botrow = botrow;
-      _redraw_leftcol = leftcol;
-      _redraw_rightcol = rightcol;
-    } else {
-      // Extend redraw range
-      if ( toprow < _redraw_toprow ) _redraw_toprow = toprow;
-      if ( botrow > _redraw_botrow ) _redraw_botrow = botrow;
-      if ( leftcol < _redraw_leftcol ) _redraw_leftcol = leftcol;
-      if ( rightcol > _redraw_rightcol ) _redraw_rightcol = rightcol;
-    }
-
-    // Indicate partial redraw needed of some cells
-    damage(FL_DAMAGE_CHILD);
-  }
-
-public:
-  Fl_Table(int X, int Y, int W, int H, const char *l=0);
-  ~Fl_Table();
-
-  virtual void clear() { rows(0); cols(0); }
-
-  // topline()
-  // middleline()
-  // bottomline()
-
-  inline void table_box(Fl_Boxtype val) {
-    table->box(val);
-    table_resized();
-  }
-  inline Fl_Boxtype table_box( void ) {
-    return(table->box());
-  }
-  virtual void rows(int val);			// set/get number of rows
-  inline int rows() {
-    return(_rows);
-  }
-  virtual void cols(int val);			// set/get number of columns
-  inline int cols() {
-    return(_cols);
-  }
-  inline void visible_cells(int& r1, int& r2, int& c1, int& c2) {
-    r1 = toprow;
-    r2 = botrow;
-    c1 = leftcol;
-    c2 = rightcol;
-  } 
-  // Interactive resizing happening?
-  int is_interactive_resize() {
-    return(_resizing_row != -1 || _resizing_col != -1);
-  } 
-  inline int row_resize() {
-    return(_row_resize);
-  }
-  void row_resize(int flag) {			// enable row resizing
-    _row_resize = flag;
-  }
-  inline int col_resize() {
-    return(_col_resize);
-  }
-  void col_resize(int flag) {			// enable col resizing
-    _col_resize = flag;
-  }
-  inline int col_resize_min() {			// column minimum resizing width
-    return(_col_resize_min);
-  }
-  void col_resize_min(int val) {
-    _col_resize_min = ( val < 1 ) ? 1 : val;
-  } 
-  inline int row_resize_min() {			// column minimum resizing width
-    return(_row_resize_min);
-  }
-  void row_resize_min(int val) {
-    _row_resize_min = ( val < 1 ) ? 1 : val;
-  }
-  inline int row_header() {			// set/get row header enable flag
-    return(_row_header);
-  }
-  void row_header(int flag) {
-    _row_header = flag;
-    table_resized();
-    redraw();
-  }
-  inline int col_header() {			// set/get col header enable flag
-    return(_col_header);
-  }
-  void col_header(int flag) {
-    _col_header = flag;
-    table_resized();
-    redraw();
-  }
-  inline void col_header_height(int height) {	// set/get col header height
-    _col_header_h = height;
-    table_resized();
-    redraw();
-  }
-  inline int col_header_height() {
-    return(_col_header_h);
-  }
-  inline void row_header_width(int width) {	// set/get row header width
-    _row_header_w = width;
-    table_resized();
-    redraw();
-  }
-  inline int row_header_width() {
-    return(_row_header_w);
-  }
-  inline void row_header_color(Fl_Color val) {	// set/get row header color
-    _row_header_color = val;
-    redraw();
-  }
-  inline Fl_Color row_header_color() {
-    return(_row_header_color);
-  } 
-  inline void col_header_color(Fl_Color val) {	// set/get col header color
-    _col_header_color = val;
-    redraw();
-  }
-  inline Fl_Color col_header_color() {
-    return(_col_header_color);
-  }
-  void row_height(int row, int height);		// set/get row height
-  inline int row_height(int row) {
-    return((row<0 || row>=(int)_rowheights.size()) ? 0 : _rowheights[row]);
-  }
-  void col_width(int col, int width);		// set/get a column's width
-  inline int col_width(int col) {
-    return((col<0 || col>=(int)_colwidths.size()) ? 0 : _colwidths[col]);
-  }
-  void row_height_all(int height) {		// set all row/col heights
-    for ( int r=0; r<rows(); r++ ) {
-      row_height(r, height);
-    }
-  }
-  void col_width_all(int width) {
-    for ( int c=0; c<cols(); c++ ) {
-      col_width(c, width);
-    }
-  }
-  void row_position(int row);			// set/get table's current scroll position
-  void col_position(int col);
-  int row_position() {				// current row position
-    return(_row_position);
-  }
-  int col_position() {				// current col position
-    return(_col_position);
-  }
-  inline void top_row(int row) {		// set/get top row (deprecated)
-    row_position(row);
-  }
-  inline int top_row() {
-    return(row_position());
-  }
-  int is_selected(int r, int c);		// selected cell
-  void get_selection(int& s_top, int& s_left, int& s_bottom, int& s_right);
-  void set_selection(int s_top, int s_left, int s_bottom, int s_right);
-  int move_cursor(int R, int C);
-
-  void resize(int X, int Y, int W, int H);	// fltk resize() override
-  void draw(void);				// fltk draw() override
-
-// This crashes sortapp() during init.
-//  void box(Fl_Boxtype val) {
-//    Fl_Group::box(val);
-//    if ( table ) {
-//      resize(x(), y(), w(), h());
-//    }
-//  }
-//  Fl_Boxtype box(void) const {
-//    return(Fl_Group::box());
-//  }
-
-  // Child group
-  void init_sizes() {
-    table->init_sizes();
-    table->redraw();
-  }
-  void add(Fl_Widget& w) {
-    table->add(w);
-  }
-  void add(Fl_Widget* w) {
-    table->add(w);
-  }
-  void insert(Fl_Widget& w, int n) {
-    table->insert(w,n);
-  }
-  void insert(Fl_Widget& w, Fl_Widget* w2) {
-    table->insert(w,w2);
-  }
-  void remove(Fl_Widget& w) {
-    table->remove(w);
-  }
-  void begin() {
-    table->begin();
-  }
-  void end() {
-    table->end();
-    // HACK: Avoid showing Fl_Scroll; seems to erase screen
-    //       causing unnecessary flicker, even if its box() is FL_NO_BOX.
-    //
-    if ( table->children() > 2 ) {
-      table->show();
-    } else {
-      table->hide();
-    } 
-    Fl_Group::current((Fl_Group*)(Fl_Group::parent()));
-  }
-  Fl_Widget * const *array() {
-    return(table->array());
-  }
-  Fl_Widget *child(int n) const {
-    return(table->child(n));
-  }
-  int children() const {
-    return(table->children()-2);    // -2: skip Fl_Scroll's h/v scrollbar widgets
-  }
-  int find(const Fl_Widget *w) const {
-    return(table->find(w));
-  }
-  int find(const Fl_Widget &w) const {
-    return(table->find(w));
-  } 
-  // CALLBACKS
-  int callback_row() {
-    return(_callback_row);
-  }
-  int callback_col() {
-    return(_callback_col);
-  }
-  TableContext callback_context() {
-    return(_callback_context);
-  }
-  void do_callback(TableContext context, int row, int col) {
-    _callback_context = context;
-    _callback_row = row;
-    _callback_col = col;
-    Fl_Widget::do_callback();
-  }
-};
-
-#endif /*_FL_TABLE_H*/
diff --git a/Utilities/FLTK/Fl_Table/FL/Fl_Table_Row.H b/Utilities/FLTK/Fl_Table/FL/Fl_Table_Row.H
deleted file mode 100644
index e7b38a4..0000000
--- a/Utilities/FLTK/Fl_Table/FL/Fl_Table_Row.H
+++ /dev/null
@@ -1,150 +0,0 @@
-#ifndef _FL_TABLE_ROW_H
-#define _FL_TABLE_ROW_H
-
-//
-// Fl_Table_Row -- A row oriented table widget
-//
-//    A class specializing in a table of rows.
-//    Handles row-specific selection behavior.
-//
-// Copyright 2002 by Greg Ercolano.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-// Please report all bugs and problems to "erco at seriss dot com".
-//
-//
-
-#include "Fl_Table.H"
-
-class Fl_Table_Row : public Fl_Table {
-public:
-  enum TableRowSelectMode {
-    SELECT_NONE,		// no selection allowed
-    SELECT_SINGLE,		// single row selection
-    SELECT_MULTI		// multiple row selection (default)
-  }; 
-private:
-  // An STL-ish vector without templates
-  class CharVector {
-    char *arr;
-    int _size;
-    void init() {
-      arr = NULL;
-      _size = 0;
-    }
-    void copy(char *newarr, int newsize) {
-      size(newsize);
-      memcpy(arr, newarr, newsize * sizeof(char));
-    }
-  public:
-    CharVector() {				// CTOR
-      init();
-    }
-    ~CharVector() {				// DTOR
-      if ( arr ) free(arr);
-      arr = NULL;
-    }
-    CharVector(CharVector&o) {			// COPY CTOR
-      init();
-      copy(o.arr, o._size);
-    }
-    CharVector& operator=(CharVector&o) {	// ASSIGN
-      init();
-      copy(o.arr, o._size);
-      return(*this);
-    }
-    char operator[](int x) const {
-      return(arr[x]);
-    }
-    char& operator[](int x) {
-      return(arr[x]);
-    }
-    int size() {
-      return(_size);
-    }
-    void size(int count) {
-      if ( count != _size ) {
-        arr = (char*)realloc(arr, count * sizeof(char));
-	_size = count;
-      }
-    }
-    char pop_back() {
-      char tmp = arr[_size-1];
-      _size--;
-      return(tmp);
-    }
-    void push_back(char val) {
-      int x = _size;
-      size(_size+1);
-      arr[x] = val;
-    }
-    char back() {
-      return(arr[_size-1]);
-    }
-  };
-  CharVector _rowselect;		// selection flag for each row
-
-  // handle() state variables.
-  //    Put here instead of local statics in handle(), so more
-  //    than one instance can exist without crosstalk between.
-  //
-  int _dragging_select;		// dragging out a selection?
-  int _last_row;
-  int _last_y;			// last event's Y position
-  int _last_push_x;		// last PUSH event's X position
-  int _last_push_y;		// last PUSH event's Y position
-
-  TableRowSelectMode _selectmode;
-
-protected:
-  int handle(int event);
-  int find_cell(TableContext context,		// find cell's x/y/w/h given r/c
-	       int R, int C, int &X, int &Y, int &W, int &H) {
-    return(Fl_Table::find_cell(context, R, C, X, Y, W, H));
-  }
-
-public:
-  Fl_Table_Row(int X, int Y, int W, int H, const char *l=0) : Fl_Table(X,Y,W,H,l) {
-    _dragging_select = 0;
-    _last_row        = -1;
-    _last_y          = -1;
-    _last_push_x     = -1;
-    _last_push_y     = -1;
-    _selectmode      = SELECT_MULTI;
-  }
-  ~Fl_Table_Row() { }
-  
-  void rows(int val);			// set number of rows
-  int rows() {				// get number of rows
-    return(Fl_Table::rows());
-  }
-  void type(TableRowSelectMode val);	// set selection mode
-  TableRowSelectMode type() const {	// get selection mode
-    return(_selectmode);
-  }
-  int row_selected(int row);		// is row selected? (0=no, 1=yes, -1=range err)
-  int select_row(int row, int flag=1);	// select state for row: flag:0=off, 1=on, 2=toggle
-				        // returns: 0=no change, 1=changed, -1=range err
-  void select_all_rows(int flag=1);	// all rows to a known state
-  void clear() {
-    rows(0);		// implies clearing selection
-    cols(0);
-    Fl_Table::clear();	// clear the table
-  }
-};
-
-#endif /*_FL_TABLE_ROW_H*/
diff --git a/Utilities/FLTK/Fl_Table/Fl_Table.cxx b/Utilities/FLTK/Fl_Table/Fl_Table.cxx
deleted file mode 100644
index 32d35cf..0000000
--- a/Utilities/FLTK/Fl_Table/Fl_Table.cxx
+++ /dev/null
@@ -1,1218 +0,0 @@
-//
-// Fl_Table -- A table widget
-//
-// Copyright 2002 by Greg Ercolano.
-// Copyright (c) 2004 O'ksi'D
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-
-#include <stdio.h>		// fprintf
-#include <FL/fl_draw.H>
-#include <FL/Fl_Table.H>
-
-#if defined(USE_UTF8) && ( defined(MICROSOFT) || defined(LINUX) )
-#include <FL/fl_utf8.H>	// currently only Windows and Linux
-#endif
-
-#define SCROLLBAR_SIZE	16
-
-// Scroll display so 'row' is at top
-void Fl_Table::row_position(int row) {
-  if ( _row_position == row ) return;		// OPTIMIZATION: no change? avoid redraw
-  if ( row < 0 ) row = 0;
-  else if ( row >= rows() ) row = rows() - 1;
-  if ( table_h <= tih ) return;			// don't scroll if table smaller than window
-  double newtop = row_scroll_position(row);
-  if ( newtop > vscrollbar->maximum() ) {
-    newtop = vscrollbar->maximum();
-  }
-  vscrollbar->Fl_Slider::value(newtop);
-  table_scrolled();
-  redraw();
-  _row_position = row;	// HACK: override what table_scrolled() came up with
-}
-
-// Scroll display so 'col' is at left
-void Fl_Table::col_position(int col) {
-  if ( _col_position == col ) return;	// OPTIMIZATION: no change? avoid redraw
-  if ( col < 0 ) col = 0;
-  else if ( col >= cols() ) col = cols() - 1;
-  if ( table_w <= tiw ) return;		// don't scroll if table smaller than window
-  double newleft = col_scroll_position(col);
-  if ( newleft > hscrollbar->maximum() ) {
-    newleft = hscrollbar->maximum();
-  }
-  hscrollbar->Fl_Slider::value(newleft);
-  table_scrolled();
-  redraw();
-  _col_position = col;	// HACK: override what table_scrolled() came up with
-}
-
-// Find scroll position of a row (in pixels)
-long Fl_Table::row_scroll_position(int row) {
-    int startrow = 0;
-    long scroll = 0; 
-    // OPTIMIZATION: 
-    //     Attempt to use precomputed row scroll position
-    //
-    if ( toprow_scrollpos != -1 && row >= toprow ) {
-      scroll = toprow_scrollpos;
-      startrow = toprow;
-    }
-    for ( int t=startrow; t<row; t++ ) {
-      scroll += row_height(t);
-    }
-    return(scroll);
-}
-
-// Find scroll position of a column (in pixels)
-long Fl_Table::col_scroll_position(int col) {
-  int startcol = 0;
-  long scroll = 0;
-  // OPTIMIZATION: 
-  //     Attempt to use precomputed row scroll position
-  //
-  if ( leftcol_scrollpos != -1 && col >= leftcol ) {
-    scroll = leftcol_scrollpos;
-    startcol = leftcol;
-  }
-  for ( int t=startcol; t<col; t++ ) {
-    scroll += col_width(t);
-  }
-  return(scroll);
-}
-
-// Ctor
-Fl_Table::Fl_Table(int X, int Y, int W, int H, const char *l) : Fl_Group(X,Y,W,H,l) {
-  _rows             = 0;
-  _cols             = 0;
-  _row_header_w     = 40;
-  _col_header_h     = 18;
-  _row_header       = 0;
-  _col_header       = 0;
-  _row_header_color = color();
-  _col_header_color = color();
-  _row_resize       = 0;
-  _col_resize       = 0;
-  _row_resize_min   = 1;
-  _col_resize_min   = 1;
-  _redraw_toprow    = -1;
-  _redraw_botrow    = -1;
-  _redraw_leftcol   = -1;
-  _redraw_rightcol  = -1;
-  table_w           = 0;
-  table_h           = 0;
-  toprow            = 0;
-  botrow            = 0;
-  leftcol           = 0;
-  rightcol          = 0;
-  toprow_scrollpos  = -1;
-  leftcol_scrollpos = -1;
-  _last_cursor      = FL_CURSOR_DEFAULT;
-  _resizing_col     = -1;
-  _resizing_row     = -1;
-  _dragging_x       = -1;
-  _dragging_y       = -1;
-  _last_row         = -1;
-  _auto_drag        = 0;
-  current_col	      = -1;
-  current_row       = -1;
-  select_row        = -1;
-  select_col        = -1;
-
-  box(FL_THIN_DOWN_FRAME);
-
-  vscrollbar = new Fl_Scrollbar(x()+w()-SCROLLBAR_SIZE, y(),
-				SCROLLBAR_SIZE, h()-SCROLLBAR_SIZE);
-  vscrollbar->type(FL_VERTICAL);
-  vscrollbar->callback(scroll_cb, (void*)this);
-
-  hscrollbar = new Fl_Scrollbar(x(), y()+h()-SCROLLBAR_SIZE,
-				w(), SCROLLBAR_SIZE);
-  hscrollbar->type(FL_HORIZONTAL);
-  hscrollbar->callback(scroll_cb, (void*)this);
-
-  table = new Fl_Scroll(x(), y(), w(), h());
-  table->box(FL_NO_BOX);
-  table->type(0);		// don't show Fl_Scroll's scrollbars -- use our own
-  table->hide();		// hide unless children are present
-  table->end();
-
-  table_resized();
-  redraw();
-
-  Fl_Group::end();		// end the group's begin()
-
-  table->begin();		// leave with fltk children getting added to the scroll
-}
-
-// Dtor
-Fl_Table::~Fl_Table() {
-    // The parent Fl_Group takes care of destroying scrollbars
-}
-
-// Set height of a row
-void Fl_Table::row_height(int row, int height) {
-  if ( row < 0 ) return;
-  if ( row < (int)_rowheights.size() && _rowheights[row] == height ) {
-    return;		// OPTIMIZATION: no change? avoid redraw
-  }
-  // Add row heights, even if none yet
-  int now_size = (int)_rowheights.size();
-  if ( row >= now_size ) {
-    _rowheights.size(row);
-    while (now_size < row)
-      _rowheights[now_size++] = height;
-  }
-  _rowheights[row] = height;
-  table_resized();
-  if ( row <= botrow ) {	// OPTIMIZATION: only redraw if onscreen or above screen
-    redraw();
-  }
-  // ROW RESIZE CALLBACK
-  if ( Fl_Widget::callback() && when() & FL_WHEN_CHANGED ) {
-    do_callback(CONTEXT_RC_RESIZE, row, 0);
-  }
-}
-
-// Set width of a column
-void Fl_Table::col_width(int col, int width)
-{
-  if ( col < 0 ) return;
-  if ( col < (int)_colwidths.size() && _colwidths[col] == width ) {
-    return;			// OPTIMIZATION: no change? avoid redraw
-  }
-  // Add column widths, even if none yet
-  int now_size = (int)_colwidths.size();
-  if ( col >= now_size ) {
-    _colwidths.size(col);
-    while (now_size < col) {
-      _colwidths[now_size++] = width;
-    }
-  }
-  _colwidths[col] = width;
-  table_resized();
-  if ( col <= rightcol ) {	// OPTIMIZATION: only redraw if onscreen or to the left
-    redraw();
-  }
-  // COLUMN RESIZE CALLBACK
-  if ( Fl_Widget::callback() && when() & FL_WHEN_CHANGED ) {
-    do_callback(CONTEXT_RC_RESIZE, 0, col);
-  }
-}
-
-// Return row/col clamped to reality
-int Fl_Table::row_col_clamp(TableContext context, int &R, int &C) {
-  int clamped = 0;
-  if ( R < 0 ) { R = 0; clamped = 1; }
-  if ( C < 0 ) { C = 0; clamped = 1; }
-  switch ( context ) {
-    case CONTEXT_COL_HEADER:
-      // Allow col headers to draw even if no rows
-      if ( R >= _rows && R != 0 ) { R = _rows - 1; clamped = 1; }
-      break;
-
-    case CONTEXT_ROW_HEADER:
-      // Allow row headers to draw even if no columns
-      if ( C >= _cols && C != 0 ) { C = _cols - 1; clamped = 1; }
-      break;
-
-    case CONTEXT_CELL:
-    default:
-      // CLAMP R/C TO _rows/_cols
-      if ( R >= _rows ) { R = _rows - 1; clamped = 1; }
-      if ( C >= _cols ) { C = _cols - 1; clamped = 1; }
-      break;
-  }
-  return(clamped);
-}
-
-// Return bounding region for given context
-void Fl_Table::get_bounds(TableContext context, int &X, int &Y, int &W, int &H) {
-  switch ( context ) {
-    case CONTEXT_COL_HEADER:
-      // Column header clipping.
-      X = tox;
-      Y = wiy;
-      W = tow;
-      H = col_header_height();
-      return;
-
-    case CONTEXT_ROW_HEADER:
-      // Row header clipping.
-      X = wix;
-      Y = toy;
-      W = row_header_width();
-      H = toh;
-      return;
-
-    case CONTEXT_TABLE:
-      // Table inner dimensions
-      X = tix; Y = tiy; W = tiw; H = tih;
-      return;
-
-    // TODO: Add other contexts..
-    default:
-      fprintf(stderr, "Fl_Table::get_bounds(): context %d unimplemented\n", (int)context);
-      return;
-  }
-  //NOTREACHED
-}
-
-// Find row/col beneath cursor
-//
-//    Returns R/C and context.
-//    Also returns resizeflag, if mouse is hovered over a resize boundary.
-//
-Fl_Table::TableContext Fl_Table::cursor2rowcol(int &R, int &C, ResizeFlag &resizeflag) {
-  // return values
-  R = C = 0;
-  resizeflag = RESIZE_NONE;
-  // Row header?
-  int X, Y, W, H;
-  if ( row_header() ) {
-    // Inside a row heading?
-    get_bounds(CONTEXT_ROW_HEADER, X, Y, W, H);
-    if ( Fl::event_inside(X, Y, W, H) ) {
-      // Scan visible rows until found
-      for ( R = toprow; R <= botrow; R++ ) {
-	find_cell(CONTEXT_ROW_HEADER, R, 0, X, Y, W, H);
-	if ( Fl::event_y() >= Y && Fl::event_y() < (Y+H) ) {
-	  // Found row?
-	  //     If cursor over resize boundary, and resize enabled,
-	  //     enable the appropriate resize flag.
-	  //
-	  if ( row_resize() ) {
-	      if ( Fl::event_y() <= (Y+3-0) ) { resizeflag = RESIZE_ROW_ABOVE; }
-	      if ( Fl::event_y() >= (Y+H-3) ) { resizeflag = RESIZE_ROW_BELOW; }
-	  }
-	  return(CONTEXT_ROW_HEADER);
-	}
-      }
-      // Must be in row header dead zone
-      return(CONTEXT_NONE);
-    }
-  }
-  // Column header?
-  if ( col_header() ) {
-    // Inside a column heading?
-    get_bounds(CONTEXT_COL_HEADER, X, Y, W, H);
-    if ( Fl::event_inside(X, Y, W, H) ) {
-      // Scan visible columns until found
-      for ( C = leftcol; C <= rightcol; C++ ) {
-	find_cell(CONTEXT_COL_HEADER, 0, C, X, Y, W, H);
-	if ( Fl::event_x() >= X && Fl::event_x() < (X+W) ) {
-	  // Found column?
-	  //     If cursor over resize boundary, and resize enabled,
-	  //     enable the appropriate resize flag.
-	  //
-	  if ( col_resize() ) {
-	    if ( Fl::event_x() <= (X+3-0) ) { resizeflag = RESIZE_COL_LEFT; }
-	    if ( Fl::event_x() >= (X+W-3) ) { resizeflag = RESIZE_COL_RIGHT; }
-	  }
-	  return(CONTEXT_COL_HEADER);
-	}
-      }
-      // Must be in column header dead zone
-      return(CONTEXT_NONE);
-    }
-  }
-  // Mouse somewhere in table?
-  //     Scan visible r/c's until we find it.
-  //
-  if ( Fl::event_inside(tox, toy, tow, toh) ) {
-    for ( R = toprow; R <= botrow; R++ ) {
-      find_cell(CONTEXT_CELL, R, C, X, Y, W, H);
-      if ( Fl::event_y() < Y ) break;		// OPT: thanks lars
-      if ( Fl::event_y() >= (Y+H) ) continue;	// OPT: " "
-      for ( C = leftcol; C <= rightcol; C++ ) {
-	find_cell(CONTEXT_CELL, R, C, X, Y, W, H);
-	if ( Fl::event_inside(X, Y, W, H) ) {
-	  return(CONTEXT_CELL);			// found it
-	}
-      }
-    }
-    // Must be in a dead zone of the table
-    R = C = 0;
-    return(CONTEXT_TABLE);
-  }
-  // Somewhere else
-  return(CONTEXT_NONE);
-}
-
-// Find X/Y/W/H for cell at R/C
-//     If R or C are out of range, returns -1 
-//     with X/Y/W/H set to zero.
-//
-int Fl_Table::find_cell(TableContext context, int R, int C, int &X, int &Y, int &W, int &H) {
-  if ( row_col_clamp(context, R, C) ) {		// row or col out of range? error
-    X=Y=W=H=0;
-    return(-1);
-  }
-  X = col_scroll_position(C) - hscrollbar->value() + tix;
-  Y = row_scroll_position(R) - vscrollbar->value() + tiy;
-  W = col_width(C);
-  H = row_height(R);
-
-  switch ( context ) {
-    case CONTEXT_COL_HEADER:
-      Y = wiy;
-      H = col_header_height();
-      return(0);
-
-    case CONTEXT_ROW_HEADER:
-      X = wix;
-      W = row_header_width();
-      return(0);
-
-    case CONTEXT_CELL:
-      return(0);
-
-    case CONTEXT_TABLE:
-      return(0);
-
-    // TODO -- HANDLE OTHER CONTEXTS
-    default:
-      fprintf(stderr, "Fl_Table::find_cell: unknown context %d\n", (int)context);
-      return(-1);
-  }
-  //NOTREACHED
-}
-
-// Enable automatic scroll-selection
-void Fl_Table::_start_auto_drag() {
-  if (_auto_drag) return;
-  _auto_drag = 1;
-  Fl::add_timeout(0.3, _auto_drag_cb2, this);
-}
-
-// Disable automatic scroll-selection
-void Fl_Table::_stop_auto_drag() {
-  if (!_auto_drag) return;
-  Fl::remove_timeout(_auto_drag_cb2, this);
-  _auto_drag = 0;
-}
-
-void Fl_Table::_auto_drag_cb2(void *d) {
-  ((Fl_Table*)d)->_auto_drag_cb();
-}
-
-// Handle automatic scroll-selection if mouse selection dragged off table edge
-void Fl_Table::_auto_drag_cb() {
-  int lx = Fl::e_x;
-  int ly = Fl::e_y;
-  if (_selecting == CONTEXT_COL_HEADER)
-    { ly = y() + col_header_height(); }
-  else if (_selecting == CONTEXT_ROW_HEADER)
-    { lx = x() + row_header_width(); }
-  if (lx > x() + w() - 20) {
-    Fl::e_x = x() + w() - 20;
-    if (hscrollbar->visible())
-	((Fl_Slider*)hscrollbar)->value(
-	    hscrollbar->clamp(hscrollbar->value() + 30));
-    hscrollbar->do_callback();
-    _dragging_x = Fl::e_x - 30;
-  }
-  else if (lx < (x() + row_header_width())) {
-    Fl::e_x = x() + row_header_width() + 1;
-    if (hscrollbar->visible())  {
-      ((Fl_Slider*)hscrollbar)->value(hscrollbar->clamp(hscrollbar->value() - 30));
-    }
-    hscrollbar->do_callback();
-    _dragging_x = Fl::e_x + 30;
-  }
-  if (ly > y() + h() - 20) {
-    Fl::e_y = y() + h() - 20;
-    if (vscrollbar->visible()) {
-      ((Fl_Slider*)vscrollbar)->value(vscrollbar->clamp(vscrollbar->value() + 30));
-    }
-    vscrollbar->do_callback();
-    _dragging_y = Fl::e_y - 30;
-  }
-  else if (ly < (y() + col_header_height())) {
-    Fl::e_y = y() + col_header_height() + 1;
-    if (vscrollbar->visible()) {
-      ((Fl_Slider*)vscrollbar)->value(vscrollbar->clamp(vscrollbar->value() - 30));
-    }
-    vscrollbar->do_callback();
-    _dragging_y = Fl::e_y + 30;
-  }
-  _auto_drag = 2;
-  handle(FL_DRAG);
-  _auto_drag = 1;
-  Fl::e_x = lx;
-  Fl::e_y = ly;
-  Fl::check();
-  Fl::flush();
-  if (Fl::event_buttons() && _auto_drag) {
-    Fl::add_timeout(0.05, _auto_drag_cb2, this);
-  }
-}
-
-// Recalculate the window dimensions
-void Fl_Table::recalc_dimensions() {
-  // Recalc to* (Table Outer), ti* (Table Inner), wi* ( Widget Inner)
-  wix = ( x() + Fl::box_dx(box())); tox = wix; tix = tox + Fl::box_dx(table->box());
-  wiy = ( y() + Fl::box_dy(box())); toy = wiy; tiy = toy + Fl::box_dy(table->box());
-  wiw = ( w() - Fl::box_dw(box())); tow = wiw; tiw = tow - Fl::box_dw(table->box());
-  wih = ( h() - Fl::box_dh(box())); toh = wih; tih = toh - Fl::box_dh(table->box());
-  // Trim window if headers enabled
-  if ( col_header() ) {
-    tiy += col_header_height(); toy += col_header_height();
-    tih -= col_header_height(); toh -= col_header_height();
-  }
-  if ( row_header() ) {
-    tix += row_header_width(); tox += row_header_width();
-    tiw -= row_header_width(); tow -= row_header_width();
-  } 
-  // Make scroll bars disappear if window large enough
-  {
-    // First pass: can hide via window size?
-    int hidev = (table_h <= tih);
-    int hideh = (table_w <= tiw); 
-    // Second pass: Check for interference
-    if ( !hideh & hidev ) { hidev = (( table_h - tih + SCROLLBAR_SIZE ) <= 0 ); } 
-    if ( !hidev & hideh ) { hideh = (( table_w - tiw + SCROLLBAR_SIZE ) <= 0 ); } 
-    // Determine scrollbar visibility, trim ti[xywh]/to[xywh]
-    if ( hidev ) { vscrollbar->hide(); } 
-    else { vscrollbar->show(); tiw -= SCROLLBAR_SIZE; tow -= SCROLLBAR_SIZE; }
-    if ( hideh ) { hscrollbar->hide(); } 
-    else { hscrollbar->show(); tih -= SCROLLBAR_SIZE; toh -= SCROLLBAR_SIZE; }
-  } 
-  // Resize the child table
-  table->resize(tox, toy, tow, toh);
-  table->init_sizes();
-}
-
-// Recalculate internals after a scroll.
-//
-//    Call this if table has been scrolled or resized.
-//    Does not handle redraw().
-//    TODO: Assumes ti[xywh] has already been recalculated.
-//
-void Fl_Table::table_scrolled() {
-  // Find top row
-  int y, row, voff = vscrollbar->value();
-  for ( row=y=0; row < _rows; row++ ) {
-    y += row_height(row);
-    if ( y > voff ) { y -= row_height(row); break; }
-  }
-  _row_position = toprow = ( row >= _rows ) ? (row - 1) : row;
-  toprow_scrollpos = y;	// OPTIMIZATION: save for later use 
-  // Find bottom row
-  voff = vscrollbar->value() + tih;
-  for ( ; row < _rows; row++ ) {
-    y += row_height(row);
-    if ( y >= voff ) { break; }
-  }
-  botrow = ( row >= _rows ) ? (row - 1) : row; 
-  // Left column
-  int x, col, hoff = hscrollbar->value();
-  for ( col=x=0; col < _cols; col++ ) {
-    x += col_width(col);
-    if ( x > hoff ) { x -= col_width(col); break; }
-  }
-  _col_position = leftcol = ( col >= _cols ) ? (col - 1) : col;
-  leftcol_scrollpos = x;	// OPTIMIZATION: save for later use 
-  // Right column
-  //    Work with data left over from leftcol calculation
-  //
-  hoff = hscrollbar->value() + tiw;
-  for ( ; col < _cols; col++ ) {
-    x += col_width(col);
-    if ( x >= hoff ) { break; }
-  }
-  rightcol = ( col >= _cols ) ? (col - 1) : col; 
-  // First tell children to scroll
-  draw_cell(CONTEXT_RC_RESIZE, 0,0,0,0,0,0);
-}
-
-// Table resized: recalc internal data
-//    Call this whenever the window is resized.
-//    Recalculates the scrollbar sizes.
-//    Makes no assumptions about any pre-initialized data.
-//
-void Fl_Table::table_resized() {
-  table_h = row_scroll_position(rows());
-  table_w = col_scroll_position(cols()); 
-  recalc_dimensions(); 
-  // Recalc scrollbar sizes
-  //    Clamp scrollbar value() after a resize.
-  //    Resize scrollbars to enforce a constant trough width after a window resize.
-  //
-  {
-    // Vertical scrollbar
-    float vscrolltab = ( table_h == 0 || tih > table_h ) ? 1 : (float)tih / table_h;
-    float hscrolltab = ( table_w == 0 || tiw > table_w ) ? 1 : (float)tiw / table_w;
-    vscrollbar->bounds(0, table_h-tih);
-    vscrollbar->precision(10);
-    vscrollbar->slider_size(vscrolltab);
-    vscrollbar->resize(wix+wiw-SCROLLBAR_SIZE, wiy,
-		       SCROLLBAR_SIZE, 
-		       wih - ((hscrollbar->visible())?SCROLLBAR_SIZE:0));
-    vscrollbar->Fl_Valuator::value(vscrollbar->clamp(vscrollbar->value()));	
-    // Horizontal scrollbar
-    hscrollbar->bounds(0, table_w-tiw);
-    hscrollbar->precision(10);
-    hscrollbar->slider_size(hscrolltab);
-    hscrollbar->resize(wix, wiy+wih-SCROLLBAR_SIZE,
-		       wiw - ((vscrollbar->visible())?SCROLLBAR_SIZE:0), 
-		       SCROLLBAR_SIZE);
-    hscrollbar->Fl_Valuator::value(hscrollbar->clamp(hscrollbar->value()));
-  }
-
-  // Tell FLTK child widgets were resized
-  Fl_Group::init_sizes();
-
-  // Recalc top/bot/left/right
-  table_scrolled();
-
-  // DO *NOT* REDRAW -- LEAVE THIS UP TO THE CALLER
-  // redraw();
-}
-
-// Someone moved a scrollbar
-void Fl_Table::scroll_cb(Fl_Widget*w, void *data) {
-  Fl_Table *o = (Fl_Table*)data;
-  o->recalc_dimensions();	// recalc tix, tiy, etc.
-  o->table_scrolled();
-  o->redraw();
-}
-
-// Set number of rows
-void Fl_Table::rows(int val) {
-  int oldrows = _rows;
-  _rows = val;
-  {
-    int default_h = ( _rowheights.size() > 0 ) ? _rowheights.back() : 25;
-    int now_size = _rowheights.size();
-    _rowheights.size(val);			// enlarge or shrink as needed
-    while ( now_size < val ) {
-      _rowheights[now_size++] = default_h;	// fill new
-    }
-  }
-  table_resized();
-
-  // OPTIMIZATION: redraw only if change is visible.
-  if ( val >= oldrows && oldrows > botrow ) {
-    // NO REDRAW
-  } else {
-    redraw();
-  }
-}
-
-// Set number of cols
-void Fl_Table::cols(int val) {
-  _cols = val;
-  {
-    int default_w = ( _colwidths.size() > 0 ) ? _colwidths[_colwidths.size()-1] : 80;
-    int now_size = _colwidths.size();
-    _colwidths.size(val);			// enlarge or shrink as needed
-    while ( now_size < val ) {
-      _colwidths[now_size++] = default_w;	// fill new
-    }
-  }
-  table_resized();
-  redraw();
-}
-
-// Change mouse cursor to different type
-void Fl_Table::change_cursor(Fl_Cursor newcursor) {
-  if ( newcursor != _last_cursor ) {
-    fl_cursor(newcursor, FL_BLACK, FL_WHITE);
-    _last_cursor = newcursor;
-  }
-}
-
-void Fl_Table::damage_zone(int r1, int c1, int r2, int c2, int r3, int c3) {
-  int R1 = r1, C1 = c1;
-  int R2 = r2, C2 = c2;
-  if (r1 > R2) R2 = r1;
-  if (r2 < R1) R1 = r2;
-  if (r3 > R2) R2 = r3;
-  if (r3 < R1) R1 = r3;
-  if (c1 > C2) C2 = c1;
-  if (c2 < C1) C1 = c2;
-  if (c3 > C2) C2 = c3;
-  if (c3 < C1) C1 = c3;
-  if (R1 < 0) {
-    if (R2 < 0) return;
-    R1 = 0;
-  }
-  if (C1 < 0) {
-    if (C2 < 0) return;
-    C1 = 0;
-  }
-  if (R1 < toprow) R1 = toprow;
-  if (R2 > botrow) R2 = botrow;
-  if (C1 < leftcol) C1 = leftcol;
-  if (C2 > rightcol) C2 = rightcol;
-  redraw_range(R1, R2, C1, C2);
-}
-
-int Fl_Table::move_cursor(int R, int C) {
-  if (select_row == -1) R++;
-  if (select_col == -1) C++;
-  R += select_row;
-  C += select_col;
-  if (R < 0) R = 0;
-  if (R >= rows()) R = rows() - 1;
-  if (C < 0) C = 0;
-  if (C >= cols()) C = cols() - 1;
-  if (R == select_row && C == select_col) return 0;
-  damage_zone(current_row, current_col, select_row, select_col, R, C);
-  select_row = R;
-  select_col = C;
-  if (!Fl::event_state(FL_SHIFT)) {
-    current_row = R;
-    current_col = C;
-  }
-  if (R < toprow + 1 || R > botrow - 1) row_position(R);
-  if (C < leftcol + 1 || C > rightcol - 1) col_position(C);
-  return 1;
-}
-
-// #define DEBUG 1
-#ifdef DEBUG
-#include "eventnames.h"
-#define PRINTEVENT \
-    fprintf(stderr,"Table %s: ** Event: %s --\n", (label()?label():"none"), eventnames[event]);
-#else
-#define PRINTEVENT
-#endif
-
-// Handle FLTK events
-int Fl_Table::handle(int event) {
-  PRINTEVENT;
-  int ret = Fl_Group::handle(event);	// let FLTK group handle events first
-  if (ret) {
-    if (Fl::event_inside(hscrollbar) || Fl::event_inside(vscrollbar)) return 1;
-    if (Fl::focus() != this && contains(Fl::focus())) return 1;
-  }
-  // Which row/column are we over?
-  int R, C;  				// row/column being worked on
-  ResizeFlag resizeflag;		// which resizing area are we over? (0=none)
-  TableContext context = cursor2rowcol(R, C, resizeflag);
-  switch ( event ) {
-    case FL_PUSH:
-      if (Fl::event_button() == 1 && !Fl::event_clicks()) {
-	if (Fl::focus() != this) {
-	  take_focus();
-	  do_callback(CONTEXT_TABLE, -1, -1);
-	  ret = 1;
-	}
-	damage_zone(current_row, current_col, select_row, select_col, R, C);
-	if (context == CONTEXT_CELL) {
-	  current_row = select_row = R;
-	  current_col = select_col = C;
-	  _selecting = CONTEXT_CELL;
-	} else {
-	  current_row = select_row = -1;
-	  current_col = select_col = -1;
-	}
-      }
-      // Need this for eg. right click to pop up a menu
-      if ( Fl_Widget::callback() &&		// callback defined?
-	   resizeflag == RESIZE_NONE ) {	// not resizing?
-	do_callback(context, R, C);		// do callback
-      }
-      switch ( context ) {
-	case CONTEXT_CELL:
-	  // FL_PUSH on a cell?
-	  ret = 1; 			// express interest in FL_RELEASE
-	  break;
-
-	case CONTEXT_NONE:
-	  // FL_PUSH on table corner?
-	  if ( Fl::event_button() == 1 && 
-	       Fl::event_x() < x() + row_header_width()) {
-	      current_col = 0;
-	      select_col = cols() - 1;
-	      current_row = 0;
-	      select_row = rows() - 1;				
-	      damage_zone(current_row, current_col, select_row, select_col);
-	      ret = 1;
-	  }
-	  break;
-
-	case CONTEXT_COL_HEADER:
-	  // FL_PUSH on a column header?
-	  if ( Fl::event_button() == 1) {
-	    // Resizing? Handle it
-	    if ( resizeflag ) {
-	      // Start resize if left click on column border.
-	      //    "ret=1" ensures we get drag events from now on.
-	      //    (C-1) is used if mouse is over the left hand side 
-	      //    of cell, so we resize the next column on the left.
-	      //
-	      _resizing_col = ( resizeflag & RESIZE_COL_LEFT ) ? C-1 : C; 
-	      _resizing_row = -1;
-	      _dragging_x = Fl::event_x(); 
-	      ret = 1;
-	    } else {
-	      // Not resizing? Select the column
-	      current_col = select_col = C;
-	      current_row = 0;
-	      select_row = rows() - 1;
-	      _selecting = CONTEXT_COL_HEADER;
-	      damage_zone(current_row, current_col, select_row, select_col);
-	      ret = 1;
-	    }
-	  }
-	  break;
-
-	case CONTEXT_ROW_HEADER:
-	  // FL_PUSH on a row header?
-	  if ( Fl::event_button() == 1 ) {
-	    // Resizing? Handle it
-	    if ( resizeflag ) {
-	      // Start resize if left mouse clicked on row border.
-	      //    "ret = 1" ensures we get drag events from now on.
-	      //    (R-1) is used if mouse is over the top of the cell,
-	      //    so that we resize the row above.
-	      //
-	      _resizing_row = ( resizeflag & RESIZE_ROW_ABOVE ) ? R-1 : R; 
-	      _resizing_col = -1;
-	      _dragging_y = Fl::event_y(); 
-	      ret = 1;
-	    } else {
-	      // Not resizing? Select the row
-	      current_row = select_row = R;
-	      current_col = 0;
-	      select_col = cols() - 1;
-	      _selecting = CONTEXT_ROW_HEADER;
-	      damage_zone(current_row, current_col, select_row, select_col);
-	      ret = 1;
-	    }
-	  }
-	  break;
-
-	default:
-	  ret = 0;		// express disinterest
-	  break;
-      }
-      _last_row = R;
-      break;
-
-    case FL_DRAG:
-      if (_auto_drag == 1) {
-	ret = 1;
-	break;
-      } 
-      if ( _resizing_col > -1 ) {
-	// Dragging column?
-	//
-	//    Let user drag even /outside/ the row/col widget.
-	//    Don't allow column width smaller than 1.
-	//    Continue to show FL_CURSOR_WE at all times during drag.
-	//
-	int offset = _dragging_x - Fl::event_x();
-	int new_w = col_width(_resizing_col) - offset;
-	if ( new_w < _col_resize_min ) new_w = _col_resize_min;
-	col_width(_resizing_col, new_w);
-	_dragging_x = Fl::event_x();
-	table_resized();
-	redraw();
-	change_cursor(FL_CURSOR_WE);
-	ret = 1;
-	if ( Fl_Widget::callback() && when() & FL_WHEN_CHANGED ) {
-	  do_callback(CONTEXT_RC_RESIZE, R, C);
-	}
-      }
-      else if ( _resizing_row > -1 ) {
-	// Dragging row?
-	//
-	//    Let user drag even /outside/ the row/col widget.
-	//    Don't allow row width smaller than 1.
-	//    Continue to show FL_CURSOR_NS at all times during drag.
-	//
-	int offset = _dragging_y - Fl::event_y();
-	int new_h = row_height(_resizing_row) - offset;
-	if ( new_h < _row_resize_min ) new_h = _row_resize_min;
-	row_height(_resizing_row, new_h);
-	_dragging_y = Fl::event_y();
-	table_resized();
-	redraw();
-	change_cursor(FL_CURSOR_NS);
-	ret = 1;
-	if ( Fl_Widget::callback() && when() & FL_WHEN_CHANGED ) {
-	  do_callback(CONTEXT_RC_RESIZE, R, C);
-	}
-      } else {
-	if (Fl::event_button() == 1 && 
-	    _selecting == CONTEXT_CELL &&
-	    context == CONTEXT_CELL) {
-	  if (select_row != R || select_col != C) {
-	    damage_zone(current_row, current_col, select_row, select_col, R, C);
-	  }
-	  select_row = R;
-	  select_col = C;
-	  ret = 1;
-	}
-	else if (Fl::event_button() == 1 && 
-		 _selecting == CONTEXT_ROW_HEADER && 
-		 context & (CONTEXT_ROW_HEADER|CONTEXT_COL_HEADER|CONTEXT_CELL)) {
-	  if (select_row != R) {
-	     damage_zone(current_row, current_col, select_row, select_col, R, C);
-	  }
-	  select_row = R;
-	  ret = 1;
-	}
-	else if (Fl::event_button() == 1 && 
-		 _selecting == CONTEXT_COL_HEADER 
-		 && context & (CONTEXT_ROW_HEADER|CONTEXT_COL_HEADER|CONTEXT_CELL)) {
-	  if (select_col != C) {
-	    damage_zone(current_row, current_col, select_row, select_col, R, C);
-	  }
-	  select_col = C;
-	  ret = 1;
-	}
-      }
-      // Enable autodrag if not resizing, and mouse has moved off table edge
-      if ( _resizing_row < 0 && _resizing_col < 0 && _auto_drag == 0 && 
-	  ( Fl::event_x() > x() + w() - 20 ||
-	    Fl::event_x() < x() + row_header_width() || 
-	    Fl::event_y() > y() + h() - 20 ||
-	    Fl::event_y() < y() + col_header_height()
-	  ) ) {
-	_start_auto_drag();
-      }
-      break;
-
-    case FL_RELEASE:
-      _stop_auto_drag();
-      switch ( context ) {
-	case CONTEXT_ROW_HEADER:		// release on row header
-	case CONTEXT_COL_HEADER:		// release on col header
-	case CONTEXT_CELL:			// release on a cell
-	case CONTEXT_TABLE:			// release on dead zone
-	  if ( _resizing_col == -1 &&		// not resizing a column
-	       _resizing_row == -1 &&		// not resizing a row
-	       Fl_Widget::callback() && 	// callback defined
-	       when() & FL_WHEN_RELEASE && 	// on button release
-	       _last_row == R ) {		// release on same row PUSHed?
-	    // Need this for eg. left clicking on a cell to select it
-	    do_callback(context, R, C);
-	  }
-	  break;
-
-	default:
-	  break;
-      }
-      if ( Fl::event_button() == 1 ) {
-	change_cursor(FL_CURSOR_DEFAULT);
-	_resizing_col = -1;
-	_resizing_row = -1;
-	ret = 1;
-      }
-      break;
-
-    case FL_MOVE:
-      if ( context == CONTEXT_COL_HEADER && 		// in column header?
-	   resizeflag ) {				// resize + near boundary?
-	change_cursor(FL_CURSOR_WE);			// show resize cursor
-      }
-      else if ( context == CONTEXT_ROW_HEADER && 	// in row header?
-	        resizeflag ) {				// resize + near boundary?
-	change_cursor(FL_CURSOR_NS);			// show resize cursor
-      } else {
-        change_cursor(FL_CURSOR_DEFAULT);		// normal cursor
-      }
-      ret = 1;
-      break;
-
-    case FL_ENTER:		// See FLTK event docs on the FL_ENTER widget
-      if (!ret) take_focus();
-      ret = 1;
-      //FALLTHROUGH
-
-    case FL_LEAVE:		// We want to track the mouse if resizing is allowed.
-      if ( resizeflag ) {
-        ret = 1;
-      }
-      if ( event == FL_LEAVE ) {
-	_stop_auto_drag();
-	change_cursor(FL_CURSOR_DEFAULT);
-      }
-      break;
-
-    case FL_FOCUS:
-      Fl::focus(this);
-      //FALLTHROUGH
-
-    case FL_UNFOCUS:
-      _stop_auto_drag();
-      ret = 1;
-      break;
-
-    case FL_KEYBOARD: {
-      ret = 0;
-      int is_row = select_row;
-      int is_col = select_col;
-      switch(Fl::event_key()) {
-	case FL_Home:
-	  ret = move_cursor(0, -1000000);
-	  break;
-	case FL_End:
-	  ret = move_cursor(0, 1000000);
-	  break;
-	case FL_Page_Up:
-	  ret = move_cursor(-(botrow - toprow - 1), 0);
-	  break;
-	case FL_Page_Down:
-	  ret = move_cursor(botrow - toprow - 1 , 0);
-	  break;
-	case FL_Left:
-	  ret = move_cursor(0, -1);
-	  break;
-	case FL_Right:
-	  ret = move_cursor(0, 1);
-	  break;
-	case FL_Up:
-	  ret = move_cursor(-1, 0);
-	  break;
-	case FL_Down:
-	  ret = move_cursor(1, 0);
-	  break;
-      }
-      if (ret && Fl::focus() != this) {
-	do_callback(CONTEXT_TABLE, -1, -1);
-	take_focus();
-      }
-      //if (!ret && Fl_Widget::callback() && when() & FL_WHEN_NOT_CHANGED  )
-      if ( Fl_Widget::callback() && 
-	   (
-	     ( !ret && when() & FL_WHEN_NOT_CHANGED ) || 
-	     ( is_row!= select_row || is_col!= select_col ) 
-	   )
-	 ) {
-	do_callback(CONTEXT_CELL, select_row, select_col); 
-	//damage_zone(current_row, current_col, select_row, select_col);
-	ret = 1;
-      }
-      break;
-    }
-
-    default:
-      change_cursor(FL_CURSOR_DEFAULT);
-      break;
-  }
-  return(ret);
-}
-
-// Resize FLTK override
-//     Handle resize events if user resizes parent window.
-//
-void Fl_Table::resize(int X, int Y, int W, int H) {
-    // Tell group to resize, and recalc our own widget as well
-    Fl_Group::resize(X, Y, W, H);
-    table_resized();
-    redraw();
-}
-
-// Draw a cell
-void Fl_Table::_redraw_cell(TableContext context, int r, int c) {
-    if ( r < 0 || c < 0 ) return;
-    int X,Y,W,H;
-    find_cell(context, r, c, X, Y, W, H);	// find positions of cell
-    draw_cell(context, r, c, X, Y, W, H);	// call users' function to draw it
-}
-
-int Fl_Table::is_selected(int r, int c) {
-  int s_left, s_right, s_top, s_bottom;
-
-  if (select_col > current_col) {
-    s_left = current_col;
-    s_right = select_col;
-  } else {
-    s_right = current_col;
-    s_left = select_col;
-  }
-  if (select_row > current_row) {
-    s_top = current_row;
-    s_bottom = select_row;
-  } else {
-    s_bottom = current_row;
-    s_top = select_row;
-  }
-  if (r >= s_top && r <= s_bottom && c >= s_left && c <= s_right) {
-    return 1;
-  }
-  return 0;
-}
-
-void Fl_Table::get_selection(int& s_top, int& s_left, int& s_bottom, int& s_right) {
-  if (select_col > current_col) {
-    s_left = current_col;
-    s_right = select_col;
-  } else {
-    s_right = current_col;
-    s_left = select_col;
-  }
-  if (select_row > current_row) {
-    s_top = current_row;
-    s_bottom = select_row;
-  } else {
-    s_bottom = current_row;
-    s_top = select_row;
-  }
-}
-
-void Fl_Table::set_selection(int s_top, int s_left, int s_bottom, int s_right) {
-  damage_zone(current_row, current_col, select_row, select_col);
-  current_col = s_left;
-  current_row = s_top;
-  select_col = s_right;
-  select_row = s_bottom;
-  damage_zone(current_row, current_col, select_row, select_col);
-}
-
-// Draw the entire Fl_Table
-//    Override the draw() routine to draw the table.
-//    Then tell the group to draw over us.
-//
-void Fl_Table::draw() {   
-  draw_cell(CONTEXT_STARTPAGE, 0, 0,	 	// let user's drawing routine
-	    tix, tiy, tiw, tih);		// prep new page
-
-  // Let fltk widgets draw themselves first. Do this after
-  // draw_cell(CONTEXT_STARTPAGE) in case user moves widgets around.
-  // Use window 'inner' clip to prevent drawing into table border.
-  // (unfortunately this clips FLTK's border, so we must draw it explicity below)
-  //
-  fl_push_clip(wix, wiy, wiw, wih);
-  {
-    Fl_Group::draw();
-  }
-  fl_pop_clip();
-
-  // Explicitly draw border around widget, if any
-  draw_box(box(), x(), y(), w(), h(), color());
-
-  // If Fl_Scroll 'table' is hidden, draw its box
-  //    Do this after Fl_Group::draw() so we draw over scrollbars
-  //    that leak around the border.
-  //
-  if ( ! table->visible() ) {
-    if ( damage() & FL_DAMAGE_ALL || damage() & FL_DAMAGE_CHILD ) {
-      draw_box(table->box(), tox, toy, tow, toh, table->color());
-    }
-  } 
-  // Clip all further drawing to the inner widget dimensions
-  fl_push_clip(wix, wiy, wiw, wih);
-  {
-    // Only redraw a few cells?
-    if ( ! ( damage() & FL_DAMAGE_ALL ) && _redraw_leftcol != -1 ) {
-      fl_push_clip(tix, tiy, tiw, tih);
-      for ( int c = _redraw_leftcol; c <= _redraw_rightcol; c++ ) {
-	for ( int r = _redraw_toprow; r <= _redraw_botrow; r++ ) { 
-	    _redraw_cell(CONTEXT_CELL, r, c);
-	}
-      }
-      fl_pop_clip();
-    }
-    if ( damage() & FL_DAMAGE_ALL ) {
-      int X,Y,W,H;
-      // Draw row headers, if any
-      if ( row_header() ) {
-	get_bounds(CONTEXT_ROW_HEADER, X, Y, W, H);
-	fl_push_clip(X,Y,W,H);
-	for ( int r = toprow; r <= botrow; r++ ) {
-	    _redraw_cell(CONTEXT_ROW_HEADER, r, 0);
-	}
-	fl_pop_clip();
-      }
-      // Draw column headers, if any
-      if ( col_header() ) {
-	get_bounds(CONTEXT_COL_HEADER, X, Y, W, H);
-	fl_push_clip(X,Y,W,H);
-	for ( int c = leftcol; c <= rightcol; c++ ) {
-	    _redraw_cell(CONTEXT_COL_HEADER, 0, c);
-	}
-	fl_pop_clip();
-      } 
-      // Draw all cells.
-      //    This includes cells partially obscured off edges of table.
-      //    No longer do this last; you might think it would be nice
-      //    to draw over dead zones, but on redraws it flickers. Avoid
-      //    drawing over deadzones; prevent deadzones by sizing columns.
-      //
-      fl_push_clip(tix, tiy, tiw, tih); {
-	for ( int r = toprow; r <= botrow; r++ ) {
-	  for ( int c = leftcol; c <= rightcol; c++ ) {
-	      _redraw_cell(CONTEXT_CELL, r, c); 
-	  }
-	}
-      }
-      fl_pop_clip(); 
-      // Draw little rectangle in corner of headers
-      if ( row_header() && col_header() ) {
-        fl_rectf(wix, wiy, row_header_width(), col_header_height(), color());
-      }
-
-      // Table has a boxtype? Close those few dead pixels
-      if ( table->box() ) {
-	if ( col_header() ) {
-	  fl_rectf(tox, wiy, Fl::box_dx(table->box()), col_header_height(), color());
-	}
-	if ( row_header() ) {
-	  fl_rectf(wix, toy, row_header_width(), Fl::box_dx(table->box()), color());
-	}
-      }
-
-      // Table width smaller than window? Fill remainder with rectangle
-      if ( table_w < tiw ) {
-	fl_rectf(tix + table_w, tiy, tiw - table_w, tih, color()); 
-	// Col header? fill that too
-	if ( col_header() ) {
-	  fl_rectf(tix + table_w, 
-		   wiy, 
-		   // get that corner just right..
-		   (tiw - table_w + Fl::box_dw(table->box()) - 
-				    Fl::box_dx(table->box())),
-		   col_header_height(),
-		   color());
-	}
-      } 
-      // Table height smaller than window? Fill remainder with rectangle
-      if ( table_h < tih ) {
-	fl_rectf(tix, tiy + table_h, tiw, tih - table_h, color()); 
-	if ( row_header() ) {
-	  // NOTE:
-	  //     Careful with that lower corner; don't use tih; when eg. 
-	  //     table->box(FL_THIN_UPFRAME) and hscrollbar hidden, 
-	  //     leaves a row of dead pixels.
-	  //
-	  fl_rectf(wix, tiy + table_h, row_header_width(), 
-		   (wiy+wih) - (tiy+table_h) - 
-		   ( hscrollbar->visible() ? SCROLLBAR_SIZE : 0),
-		   color());
-	}
-      }
-    } 
-    // Both scrollbars? Draw little box in lower right
-    if ( vscrollbar->visible() && hscrollbar->visible() ) {
-      fl_rectf(vscrollbar->x(), hscrollbar->y(), 
-	       vscrollbar->w(), hscrollbar->h(), color());
-    } 
-    draw_cell(CONTEXT_ENDPAGE, 0, 0,		// let user's drawing
-	      tix, tiy, tiw, tih);		// routines cleanup
-
-    _redraw_leftcol = _redraw_rightcol = _redraw_toprow = _redraw_botrow = -1;
-  }
-  fl_pop_clip();
-}
diff --git a/Utilities/FLTK/Fl_Table/Fl_Table_Row.cxx b/Utilities/FLTK/Fl_Table/Fl_Table_Row.cxx
deleted file mode 100644
index 85fa5aa..0000000
--- a/Utilities/FLTK/Fl_Table/Fl_Table_Row.cxx
+++ /dev/null
@@ -1,317 +0,0 @@
-//
-// Fl_Table_Row -- A row oriented table widget
-//
-//    A class specializing in a table of rows.
-//    Handles row-specific selection behavior.
-//
-// Copyright 2002 by Greg Ercolano.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
-// Please report all bugs and problems to "erco at seriss dot com".
-//
-//
-// TODO:
-//    o Row headings (only column headings supported currently)
-//
-
-#include <stdio.h>		// for debugging
-#include <FL/Fl.H>
-#include <FL/fl_draw.H>
-#include <FL/Fl_Table_Row.H>
-
-// Is row selected?
-int Fl_Table_Row::row_selected(int row) {
-  if ( row < 0 || row >= rows() ) return(-1);
-  return(_rowselect[row]);
-}
-
-// Change row selection type
-void Fl_Table_Row::type(TableRowSelectMode val) {
-  _selectmode = val;
-  switch ( _selectmode ) {
-    case SELECT_NONE:
-    {
-      for ( int row=0; row<rows(); row++ ) {
-	_rowselect[row] = 0;
-      }
-      redraw();
-      break;
-    }
-    case SELECT_SINGLE:
-    {
-      int count = 0;
-      for ( int row=0; row<rows(); row++ ) {
-	if ( _rowselect[row] ) {
-	  if ( ++count > 1 ) {	// only one allowed
-	    _rowselect[row] = 0;
-	  }
-	}
-      }
-      redraw();
-      break;
-    }
-    case SELECT_MULTI:
-      break;
-  }
-}
-
-// Change selection state for row
-//
-//     flag:
-//        0 - clear selection
-//        1 - set selection
-//        2 - toggle selection
-//
-//     Returns:
-//        0 - selection state did not change
-//        1 - selection state changed
-//       -1 - row out of range or incorrect selection mode
-//
-int Fl_Table_Row::select_row(int row, int flag) {
-  int ret = 0;
-  if ( row < 0 || row >= rows() ) { return(-1); }
-  switch ( _selectmode ) {
-    case SELECT_NONE:
-      return(-1);
-
-    case SELECT_SINGLE:
-    {
-      int oldval;
-      for ( int t=0; t<rows(); t++ ) {
-	if ( t == row ) {
-	  oldval = _rowselect[row];
-	  if ( flag == 2 ) { _rowselect[row] ^= 1; }
-	  else             { _rowselect[row] = flag; }
-	  if ( oldval != _rowselect[row] ) {
-	    redraw_range(row, row, leftcol, rightcol);
-	    ret = 1;
-	  }
-	}
-	else if ( _rowselect[t] ) {
-	  _rowselect[t] = 0;
-	  redraw_range(t, t, leftcol, rightcol);
-	}
-      }
-      break;
-    }
-
-    case SELECT_MULTI:
-    {
-      int oldval = _rowselect[row];
-      if ( flag == 2 ) { _rowselect[row] ^= 1; }
-      else             { _rowselect[row] = flag; }
-      if ( _rowselect[row] != oldval ) {		// select state changed?
-	if ( row >= toprow && row <= botrow ) {		// row visible?
-	  // Extend partial redraw range
-	  redraw_range(row, row, leftcol, rightcol);
-	}
-	ret = 1;
-      }
-    }
-  }
-  return(ret);
-}
-
-// Select all rows to a known state
-void Fl_Table_Row::select_all_rows(int flag) {
-  switch ( _selectmode ) {
-    case SELECT_NONE:
-      return;
-
-    case SELECT_SINGLE:
-      if ( flag != 0 ) return;
-      //FALLTHROUGH
-
-    case SELECT_MULTI:
-    {
-      char changed = 0;
-      if ( flag == 2 ) {
-	for ( int row=0; row<(int)_rowselect.size(); row++ ) {
-	  _rowselect[row] ^= 1;
-	}
-	changed = 1;
-      } else {
-	for ( int row=0; row<(int)_rowselect.size(); row++ ) {
-	  changed |= (_rowselect[row] != flag)?1:0;
-	  _rowselect[row] = flag; 
-	}
-      }
-      if ( changed ) {
-        redraw();
-      }
-    }
-  }
-}
-
-// Set number of rows
-void Fl_Table_Row::rows(int val) {
-  Fl_Table::rows(val);
-  while ( val > (int)_rowselect.size() ) { _rowselect.push_back(0); }	// enlarge
-  while ( val < (int)_rowselect.size() ) { _rowselect.pop_back(); }	// shrink
-}
-
-// #include "eventnames.h"		// debugging
-// #include <stdio.h>
-
-// Handle events
-int Fl_Table_Row::handle(int event) {
-
-  //  fprintf(stderr, "** EVENT: %s: EVENT XY=%d,%d\n", 
-  //      eventnames[event], Fl::event_x(), Fl::event_y());	// debugging
-
-  // Let base class handle event
-  int ret = Fl_Table::handle(event);
-
-  // The following code disables cell selection.. why was it added? -erco 05/18/03
-  // if ( ret ) { _last_y = Fl::event_y(); return(1); }	// base class 'handled' it (eg. column resize)
-
-  int shiftstate = (Fl::event_state() & FL_CTRL) ? FL_CTRL :
-		   (Fl::event_state() & FL_SHIFT) ? FL_SHIFT : 0;
-
-  // Which row/column are we over?
-  int R, C;  				// row/column being worked on
-  ResizeFlag resizeflag;		// which resizing area are we over? (0=none)
-  TableContext context = cursor2rowcol(R, C, resizeflag);
-  switch ( event ) {
-    case FL_PUSH:
-      if ( Fl::event_button() == 1 ) {
-	_last_push_x = Fl::event_x();	// save regardless of context
-	_last_push_y = Fl::event_y();	// " "
-
-	// Handle selection in table.
-	//     Select cell under cursor, and enable drag selection mode.
-	//
-	if ( context == CONTEXT_CELL ) {
-	  // Ctrl key? Toggle selection state
-	  switch ( shiftstate ) {
-	    case FL_CTRL:
-	      select_row(R, 2);		// toggle
-	      break;
-
-	    case FL_SHIFT:
-	    {
-	      select_row(R, 1);
-	      if ( _last_row > -1 ) {
-		int srow = R, erow = _last_row;
-		if ( srow > erow ) {
-		  srow = _last_row;
-		  erow = R;
-		}
-		for ( int row = srow; row <= erow; row++ ) {
-		  select_row(row, 1);
-		}
-	      }
-	      break;
-	   }
-
-	   default:
-	     select_all_rows(0);	// clear all previous selections
-	     select_row(R, 1);
-	     break;
-	  }
-
-	  _last_row = R;
-	  _dragging_select = 1;
-	  ret = 1;      // FL_PUSH handled (ensures FL_DRAG will be sent)
-	  // redraw();  // redraw() handled by select_row()
-	}
-      } 
-      break;
-
-    case FL_DRAG:
-    {
-      if ( _dragging_select ) {
-	// Dragged off table edges? Handle scrolling
-	int offtop = toy - _last_y;			// >0 if off top of table
-	int offbot = _last_y - (toy + toh);		// >0 if off bottom of table
-
-	if ( offtop > 0 && row_position() > 0 ) {
-	  // Only scroll in upward direction
-	  int diff = _last_y - Fl::event_y();
-	  if ( diff < 1 ) {
-	    ret = 1;
-	    break;
-	  }
-	  row_position(row_position() - diff);
-	  context = CONTEXT_CELL; C = 0; R = row_position();  // HACK: fake it
-	  if ( R < 0 || R > rows() ) { ret = 1; break; }      // HACK: ugly
-	}
-	else if ( offbot > 0 && botrow < rows() ) {
-	  // Only scroll in downward direction
-	  int diff = Fl::event_y() - _last_y;
-	  if ( diff < 1 ) {
-	    ret = 1;
-	    break;
-	  }
-	  row_position(row_position() + diff);
-	  context = CONTEXT_CELL; C = 0; R = botrow;		// HACK: fake it
-	  if ( R < 0 || R > rows() ) { ret = 1; break; }	// HACK: ugly
-	}
-	if ( context == CONTEXT_CELL ) {
-	  switch ( shiftstate ) {
-	    case FL_CTRL:
-	      if ( R != _last_row ) {		// toggle if dragged to new row
-		  select_row(R, 2);		// 2=toggle
-	      }
-	      break;
-
-	    case FL_SHIFT:
-	    default:
-	      select_row(R, 1);
-	      if ( _last_row > -1 ) {
-		int srow = R, erow = _last_row;
-		if ( srow > erow ) {
-		  srow = _last_row;
-		  erow = R;
-		}
-		for ( int row = srow; row <= erow; row++ ) {
-		  select_row(row, 1);
-		}
-	      }
-	      break;
-	  }
-	  ret = 1;				// drag handled
-	  _last_row = R;
-	}
-      }
-      break;
-    }
-
-    case FL_RELEASE:
-      if ( Fl::event_button() == 1 ) {
-	_dragging_select = 0;
-	ret = 1;			// release handled
-	// Clicked off edges of data table? 
-	//    A way for user to clear the current selection.
-	//
-	int databot = tiy + table_h,
-	    dataright = tix + table_w;
-	if ( 
-	    ( _last_push_x > dataright && Fl::event_x() > dataright ) ||
-	    ( _last_push_y > databot && Fl::event_y() > databot )
-	   ) {
-	  select_all_rows(0);			// clear previous selections
-	}
-      }
-      break;
-
-    default:
-	break;
-  }
-  _last_y = Fl::event_y();
-  return(ret);
-}
diff --git a/Utilities/FLTK/Fl_Table/README b/Utilities/FLTK/Fl_Table/README
deleted file mode 100644
index 503c5ff..0000000
--- a/Utilities/FLTK/Fl_Table/README
+++ /dev/null
@@ -1,106 +0,0 @@
-Fl_Table -- FLTK Table Widget
------------------------------
-
-WHAT IS Fl_Table?
-
-    Fl_Table is a low level widget intended to help people
-    design higher level widgets, and is aimed at becoming
-    part of FLTK's core.
-
-    Fl_Table is a low level widget that helps widget designers
-    (or self motivated app designers) derive their own higher
-    level widgets to do what they need.
-
-    Fl_Table can be used to implement many table-like widgets; 
-    a 'spreadsheet', a two dimensional table browser, an
-    invoice generator.
-
-    Anything where resizable rows and columns with optional
-    row/column headers are desireable.
-
-LICENSING
-
-    Fl_Table comes with complete free source code. 
-    Fl_Table is available under the terms of the GNU Library 
-    General Public License. See COPYING for more info.
-
-    Contrary to popular belief, it can be used in commercial
-    software!
-
-BUILD INSTRUCTIONS
-
-    Tested under Linux, Mac OSX and Windows with fltk 1.3.x.
-
-    To build the test programs and related Fl_Table object files:
-
-	make
-
-   These test programs are created:
-
-       	testtablerow     -- Simple row/column test. 
-			    Scroll around, resize the columns.
-
-	exercisetablerow -- Exercises widget options to check for bugs.
-
-	sortapp          -- Sample app that loads output of an 'ls' listing, and
-			    lets you toggle-sort the columns by clicking on the 
-			    column headings.
-
-	widgettable      -- Exercises ability to embed fltk widgets in table
-
-	singleinput      -- Shows Mr. Satan's trick to use Fl_Input effectively
-			    in Fl_Table, with only a single instance of the widget.
-
-UTF8 SUPPORT
-
-    FLTK officially started supporting UTF8 in 1.3.0, and the default
-    Makefile should work with that OK.
-
-    For some years before 1.3.x, there was an FLTK utf8 'patch' that
-    was used quite a bit.. to make that work you may need to manually
-    add the -lXutf8 link option, as there was a separate Xutf8 lib.
-
-
-WHERE'S THE DOCUMENTATION?
-
-    See documentation/index.html.
-
-FEATURES
-
-    Currently the lib supports:
-
-	    o A full on X/Y table
-	    o Column headers (that can be resized, and disabled)
-	    o An Fl_Table_Row widget that specializes in row selection behavior
-	    o Complete custom drawing behavior in cells
-	    o Ctrl-selection and Shift-selection, and drag selection
-	    o Callback mechanism for when mouse events occur in table
-	      (sortapp uses this to do sorting when column header clicked)
-	    o No limit on table size (or well, there 'shouldn't' be one)
-	    o Can act as a container for fltk widgets or custom widgets
-
-RELEASE NOTES/VERSION INFORMATION
-    
-    See ./CHANGES.
-
-LIMITATIONS
-
-    Known bugs:
-
-	    o 'sortapp' is not sorting the selection states.
-	      Probably move this into the 'Row' class somehow?
-	      Problem in demo only, not the core lib.
-
-    Currently *lacks* the following, but will be in there RSN:
-
-	    o User control of scrollbar visibility and selection behavior
-
-    Not sure when I'll get to these:
-
-	    o No concept of a 'current cell' or 'cell cursor'
-	    o Keyboard navigation of cell selection
-	    o Footers (row or column)
-
-BUGS?
-    
-    Send them to erco at seriss dot com
diff --git a/Utilities/FLTK/Fl_Table/TODO b/Utilities/FLTK/Fl_Table/TODO
deleted file mode 100644
index 1ab0164..0000000
--- a/Utilities/FLTK/Fl_Table/TODO
+++ /dev/null
@@ -1,120 +0,0 @@
-> DOXYGEN the documentation
-
-> BUG: in testtablerow, mouse wheel does not scroll lower window
-  if mouse is inside it, but PGUP/DOWN work ok. ???
-
-> Bring over changes from RUSH:
-	o (DONE) is_interactive_resize()
-	o something else I think???
-
-> exercisetablerow: Lots of messages on startup.. WHY??
-    'Demo' callback: Row=497 Col=0 Context=7 Event=0
-    'Demo' callback: Row=498 Col=0 Context=7 Event=0
-    'Demo' callback: Row=499 Col=0 Context=7 Event=0
-    'Demo' callback: Row=0 Col=0 Context=0 Event=1
-    'Demo' callback: Row=0 Col=0 Context=0 Event=1
-
-> exercisetable(): add a prompt for changing 'when()' via a pulldown.
-
-> Add a Right click popup menu, and see
-  how that would be implemented using new callback() system.
-
-> Add an any_selected() method to Fl_Table_Row(), so one
-  can easily determine if any rows are selected.
-
-> TODO: (see 3.10 Jean Marc additions)
-  Need to make mouse region selection controllable via 'or'able flags:
-
-	> Single cell					(SELECT_CELL)
-	> Row of cells (eg. Fl_Browser, Fl_Table_Row)	(SELECT_ROW)
-	> Column of cells		      		(SELECT_COL)
-	> Freeform row/col (current behavior) 		(SELECT_MULTI)
-
-> Autoscrolling is a hack.
-  Need finer control of auto-scrolling, based on proximity
-  to the table edge, like normal tty scrolling.
-
-> Don't show resize cursor when over header for left edge 
-  of cell#0, or top edge of header for row#0.
-
-> Fl_Table_Row: A way to pick different select modes;
-
-	none
-	1 of n (file browser)
-	multi
-
-  See Fl_Browser_
-
-> Keyboard navigation of a 'current cell' or 'current row'
-  using Tab and Shift Tab, Arrows, Spacebar, etc. Again,
-  see Fl_Browser.  Needs a focus box.
-
-> fltk-config
-
-    Greg Ercolano wrote:
-
-    > Does fltk-config somehow deal with the issue of having
-    > multiple FLTK dirs installed on a machine?
-
-    Yes, through the configured directories...
-
-    > I just started playing with fltk-config this morning,
-    > and noticed that it reports paths like /usr/local/lib
-    > even though I didn't run 'make install'.
-
-    Easy fix: provide your source directories when configuring,
-    e.g.:
-
-	./configure --prefix=/usr/local/src/fltk-M.m.p \
-	    --includedir=/usr/local/src/fltk-M.m.p
-
-> In FLTK 2.0, there's some way to avoid having the parent
-  draw the rectangle over the table.
-
-> Implement a way the derived class can disable/draw their own
-  dead zones. Do this for ALL dead zones.
-
-	CONTEXT_DEADZONE_TABLE
-	CONTEXT_DEADZONE_HEADER
-	CONTEXT_DEADZONE_SCROLLBAR
-
-> Need to override /all/ Fl_Group methods, eg:
-
-	add()
-	add_resizable()
-	find()
-	insert()
-	remove()
-
-> optimize for fixed rowh/colw
-
-> If has_fltk_children(), don't call the draw_cell() stuff?
-
-> Add row_margin/col_margin() to change overall spacing between cells.
-  Esp for use with fltk container. Also, gets rid of need for
-  user to handle those little edge lines in custom widgets
-
-----------------------------------------------------------------
-
-> (3.0) Document all Fl_Table_Row functions.
-
-> (3.0) Fl_Table_Row:
-  If you make a selection, but drag off the end of the last row,
-  you loose the selection.
-
-> (3.0) When resized very small, horiz scroll bar clips OUTSIDE
-  the border instead of INSIDE. Make sure when scroll bars drawn,
-  they are clipped to the INNER boarder.
-
-> (3.0) Implement callback() stuff.
-  Try to follow Fl_Browser as closely as possible.
-  For keyboard navigation, and probably right-click stiuff
-  too to bring up menus.
-
-> (3.0) Don't scroll if resizing.
-
-> (3.1) HEY!! When you click to resize a column, it ALSO sends
-  a NON-resize event to the callback(). MASK THEM!
-
-> (3.1) col_width() or row_height() should probably invoke
-  user callback() with a CONTEXT_RC_RESIZE.
diff --git a/Utilities/MacOS/BundleResources/Info.plist b/Utilities/MacOS/BundleResources/Info.plist
index e3159a6..12c30f7 100644
--- a/Utilities/MacOS/BundleResources/Info.plist
+++ b/Utilities/MacOS/BundleResources/Info.plist
@@ -3,7 +3,7 @@
 <plist version="1.0">
 <dict>
 	<key>CFBundleExecutable</key>
-	<string>InsightSNAP</string>
+        <string>ITK-SNAP</string>
 	<key>CFBundleIconFile</key>
 	<string>itksnap</string>
 	<key>CFBundleIdentifier</key>
@@ -20,9 +20,25 @@
 	<string>@SNAP_VERSION_FULL@</string>
 	<key>CFBundleSignature</key>
 	<string>itksnap</string>
+        <key>NSPrincipalClass</key>
+        <string>NSApplication</string>
+        <key>NSHighResolutionCapable</key>
+        <string>True</string>
 	<key>CFBundleDocumentTypes</key>
 	<array>
-		<dict>
+                <dict>
+                        <key>CFBundleTypeName</key>
+                        <string>ITK-SNAP Workspace File</string>
+                        <key>CFBundleTypeRole</key>
+                        <string>Viewer</string>
+                        <key>CFBundleTypeExtensions</key>
+                        <array>
+                                <string>itksnap</string>
+                        </array>
+                        <key>CFBundleTypeIconFile</key>
+                        <string>itksnap.icns</string>
+                </dict>
+                <dict>
 			<key>CFBundleTypeName</key>
 			<string>NIfTI File</string>
 			<key>CFBundleTypeRole</key>
@@ -30,7 +46,8 @@
 			<key>CFBundleTypeExtensions</key>
 			<array>
 				<string>nii</string>
-			</array>
+                                <string>nii-gz</string>
+                        </array>
 		</dict>
 		<dict>
 			<key>CFBundleTypeName</key>
diff --git a/Utilities/MacOS/BundleResources/README.txt b/Utilities/MacOS/BundleResources/README.txt
new file mode 100644
index 0000000..c8e9d66
--- /dev/null
+++ b/Utilities/MacOS/BundleResources/README.txt
@@ -0,0 +1,19 @@
+To install ITK-SNAP on your Mac, follow these simple steps:
+
+1. Drag the icon ITK-SNAP.app onto the Applications directory.
+
+2. If you would like to call ITK-SNAP from the command line, copy the 
+   included launcher script "itksnap" into a folder in your PATH, such as
+
+     /usr/local/bin/ 
+
+   (You can do this simply by dragging the "itksnap" icon onto the
+   "usr-local-bin" icon)
+
+3. You can launch ITK-SNAP in many ways:
+
+     a. Using the Finder by clicking the ITK-SNAP.app icon
+
+     b. Using the Finder by double-clicking 3D image files (.nii, .mha, etc.)
+
+     c. From Terminal, by typing "itksnap"
diff --git a/Utilities/MacOS/BundleResources/background.png b/Utilities/MacOS/BundleResources/background.png
new file mode 100644
index 0000000..ea1d98a
Binary files /dev/null and b/Utilities/MacOS/BundleResources/background.png differ
diff --git a/Utilities/MacOS/BundleResources/dsstore.bin b/Utilities/MacOS/BundleResources/dsstore.bin
new file mode 100644
index 0000000..851861d
Binary files /dev/null and b/Utilities/MacOS/BundleResources/dsstore.bin differ
diff --git a/Utilities/MacOS/BundleResources/itksnap b/Utilities/MacOS/BundleResources/itksnap
new file mode 100755
index 0000000..d30ea82
--- /dev/null
+++ b/Utilities/MacOS/BundleResources/itksnap
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# This script calls the ITK-SNAP inside of its bundle in the Applications directory. 
+# It was modeled after the mvim script that comes with MacVim
+#
+# The script looks for the ITK-SNAP binary in a list of directories. If you want to
+# tell the script where to look, set the environment variable ITKSNAP_APP_DIR, e.g.:
+#
+# ITKSNAP_APP_DIR=/Applications
+#
+
+# Try to find the ITK-SNAP application somewhere
+if [ -z "$ITKSNAP_APP_DIR" ]
+then
+ 	myDir="`dirname "$0"`"
+	myAppDir="$myDir/../Applications"
+	for i in ~/Applications $myDir $myAppDir /Applications; do
+    if [ -x "$i/ITK-SNAP.app" ]; then
+			ITKSNAP_APP_DIR="$i"
+			break
+		fi
+  done
+fi
+
+# Try to find the ITK-SNAP application somewhere
+if [ -z "$ITKSNAP_APP_DIR" ]
+then
+	echo "Cannot find ITK-SNAP.app. Try setting the ITKSNAP_APP_DIR environment variable to the directory containing ITK-SNAP.app"
+	exit 1
+fi
+
+# Try to find the binary to launch
+binary="$ITKSNAP_APP_DIR/ITK-SNAP.app/Contents/MacOS/ITK-SNAP"
+
+# Call the binary
+exec $binary --console ${1:+"$@"}
+
+
+
+
+
+
+
diff --git a/Utilities/Win32/itksnap.rc b/Utilities/Win32/itksnap.rc
new file mode 100644
index 0000000..844c350
--- /dev/null
+++ b/Utilities/Win32/itksnap.rc
@@ -0,0 +1 @@
+IDI_ICON1               ICON    DISCARDABLE     "snaplogo.ico"
\ No newline at end of file
diff --git a/Utilities/Win32/snaplogo.ico b/Utilities/Win32/snaplogo.ico
new file mode 100644
index 0000000..6b13cb0
Binary files /dev/null and b/Utilities/Win32/snaplogo.ico differ
diff --git a/Utilities/licensetemplate.txt b/Utilities/licensetemplate.txt
new file mode 100644
index 0000000..62da968
--- /dev/null
+++ b/Utilities/licensetemplate.txt
@@ -0,0 +1,25 @@
+/*=========================================================================
+
+  Program:   ITK-SNAP
+  Module:    $RCSfile: Filename.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/10/18 11:25:44 $
+  Version:   $Revision: 1.12 $
+  Copyright (c) 2011 Paul A. Yushkevich
+
+  This file is part of ITK-SNAP
+
+  ITK-SNAP 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 3 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, see <http://www.gnu.org/licenses/>.
+
+=========================================================================*/

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/itksnap.git



More information about the debian-med-commit mailing list