r589: Added threaded rasterizer
[ctsim.git] / src / views.cpp
index ba400e708a4cf336038b2d2bc07dcdbe3276b3fd..fdfbc9f6dde82fd16e1d9576f4f5d87894a77454 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: views.cpp,v 1.94 2001/01/31 01:01:22 kevin Exp $
+**  $Id: views.cpp,v 1.121 2001/02/27 03:59:30 kevin Exp $
 **
 **  This program is free software; you can redistribute it and/or modify
 **  it under the terms of the GNU General Public License (version 2) as
 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 ******************************************************************************/
 
-// For compilers that support precompilation, includes "wx/wx.h".
 #include "wx/wxprec.h"
-
-#ifdef __BORLANDC__
-#pragma hdrstop
-#endif
-
 #ifndef WX_PRECOMP
 #include "wx/wx.h"
 #endif
@@ -53,6 +47,9 @@
 #include "backprojectors.h"
 #include "reconstruct.h"
 #include "timer.h"
+#include "threadproj.h"
+#include "threadrecon.h"
+#include "threadraster.h"
 
 #if defined(MSVC) || HAVE_SSTREAM
 #include <sstream>
@@ -119,6 +116,7 @@ ImageFileCanvas::OnMouseEvent(wxMouseEvent& event)
   if (! m_pView)
     return;
   
+  
   wxClientDC dc(this);
   PrepareDC(dc);
   
@@ -268,7 +266,7 @@ ImageFileView::OnProperties (wxCommandEvent& event)
   if (rIF.nx() == 0 || rIF.ny() == 0)
     *theApp->getLog() << "Properties: empty imagefile\n";
   else {
-    const std::string& rFilename = rIF.getFilename();
+    const std::string rFilename = m_pFrame->GetTitle().c_str();
     std::ostringstream os;
     double min, max, mean, mode, median, stddev;
     rIF.statistics (rIF.getArray(), min, max, mean, mode, median, stddev);
@@ -388,7 +386,7 @@ ImageFileView::OnCompare (wxCommandEvent& event)
           return;
         }
         pDifferenceDoc->setImageFile (pDifferenceImage);
-
+        
         wxString s = GetFrame()->GetTitle() + ": ";
         pDifferenceImage->labelsCopy (rIF, s.c_str());
         s = pCompareDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";
@@ -398,7 +396,8 @@ ImageFileView::OnCompare (wxCommandEvent& event)
           << " and " << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str() << ": "
           << os.str().c_str();
         pDifferenceImage->labelAdd (os.str().c_str());
-        pDifferenceDoc->Modify (true);
+        if (theApp->getAskDeleteNewDocs())
+          pDifferenceDoc->Modify (true);
         pDifferenceDoc->UpdateAllViews (this);
         pDifferenceDoc->getView()->OnUpdate (this, NULL);
         pDifferenceDoc->getView()->getFrame()->Show(true);
@@ -414,7 +413,8 @@ ImageFileView::OnInvertValues (wxCommandEvent& event)
   ImageFile& rIF = GetDocument()->getImageFile();
   rIF.invertPixelValues (rIF);
   rIF.labelAdd ("Invert Pixel Values");
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -424,7 +424,8 @@ ImageFileView::OnSquare (wxCommandEvent& event)
   ImageFile& rIF = GetDocument()->getImageFile();
   rIF.square (rIF);
   rIF.labelAdd ("Square Pixel Values");
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -434,7 +435,8 @@ ImageFileView::OnSquareRoot (wxCommandEvent& event)
   ImageFile& rIF = GetDocument()->getImageFile();
   rIF.sqrt (rIF);
   rIF.labelAdd ("Square-root Pixel Values");
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -444,7 +446,8 @@ ImageFileView::OnLog (wxCommandEvent& event)
   ImageFile& rIF = GetDocument()->getImageFile();
   rIF.log (rIF);
   rIF.labelAdd ("Logrithm base-e Pixel Values");
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -454,7 +457,8 @@ ImageFileView::OnExp (wxCommandEvent& event)
   ImageFile& rIF = GetDocument()->getImageFile();
   rIF.exp (rIF);
   rIF.labelAdd ("Exponent base-e Pixel Values");
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -490,7 +494,8 @@ ImageFileView::OnAdd (wxCommandEvent& event)
       newImage.labelsCopy (rRHSIF, s.c_str());
       newImage.labelAdd (os.str().c_str());
       *theApp->getLog() << os.str().c_str() << "\n";
-      pNewDoc->Modify (true);
+      if (theApp->getAskDeleteNewDocs())
+        pNewDoc->Modify (true);
       pNewDoc->UpdateAllViews (this);
       pNewDoc->getView()->OnUpdate (this, NULL);
       pNewDoc->getView()->getFrame()->Show(true);
@@ -530,7 +535,8 @@ ImageFileView::OnSubtract (wxCommandEvent& event)
       newImage.labelsCopy (rRHSIF, s.c_str());
       newImage.labelAdd (os.str().c_str());
       *theApp->getLog() << os.str().c_str() << "\n";
-      pNewDoc->Modify (true);
+      if (theApp->getAskDeleteNewDocs())
+        pNewDoc->Modify (true);
       pNewDoc->UpdateAllViews (this);
       pNewDoc->getView()->OnUpdate (this, NULL);
       pNewDoc->getView()->getFrame()->Show(true);
@@ -570,7 +576,8 @@ ImageFileView::OnMultiply (wxCommandEvent& event)
       newImage.labelsCopy (rRHSIF, s.c_str());
       newImage.labelAdd (os.str().c_str());
       *theApp->getLog() << os.str().c_str() << "\n";
-      pNewDoc->Modify (true);
+      if (theApp->getAskDeleteNewDocs())
+        pNewDoc->Modify (true);
       pNewDoc->UpdateAllViews (this);
       pNewDoc->getView()->OnUpdate (this, NULL);
       pNewDoc->getView()->getFrame()->Show(true);
@@ -610,7 +617,8 @@ ImageFileView::OnDivide (wxCommandEvent& event)
       newImage.labelsCopy (rRHSIF, s.c_str());
       newImage.labelAdd (os.str().c_str());
       *theApp->getLog() << os.str().c_str() << "\n";
-      pNewDoc->Modify (true);
+      if (theApp->getAskDeleteNewDocs())
+        pNewDoc->Modify (true);
       pNewDoc->UpdateAllViews (this);
       pNewDoc->getView()->OnUpdate (this, NULL);
       pNewDoc->getView()->getFrame()->Show(true);
@@ -628,7 +636,8 @@ ImageFileView::OnFFT (wxCommandEvent& event)
   rIF.labelAdd ("FFT Image");
   m_bMinSpecified = false;
   m_bMaxSpecified = false;
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -640,7 +649,8 @@ ImageFileView::OnIFFT (wxCommandEvent& event)
   rIF.labelAdd ("IFFT Image");
   m_bMinSpecified = false;
   m_bMaxSpecified = false;
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -652,7 +662,8 @@ ImageFileView::OnFFTRows (wxCommandEvent& event)
   rIF.labelAdd ("FFT Rows");
   m_bMinSpecified = false;
   m_bMaxSpecified = false;
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -664,7 +675,8 @@ ImageFileView::OnIFFTRows (wxCommandEvent& event)
   rIF.labelAdd ("IFFT Rows");
   m_bMinSpecified = false;
   m_bMaxSpecified = false;
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -676,7 +688,8 @@ ImageFileView::OnFFTCols (wxCommandEvent& event)
   rIF.labelAdd ("FFT Columns");
   m_bMinSpecified = false;
   m_bMaxSpecified = false;
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -688,7 +701,8 @@ ImageFileView::OnIFFTCols (wxCommandEvent& event)
   rIF.labelAdd ("IFFT Columns");
   m_bMinSpecified = false;
   m_bMaxSpecified = false;
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 #endif
@@ -702,7 +716,8 @@ ImageFileView::OnFourier (wxCommandEvent& event)
   rIF.labelAdd ("Fourier Image");
   m_bMinSpecified = false;
   m_bMaxSpecified = false;
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -715,7 +730,8 @@ ImageFileView::OnInverseFourier (wxCommandEvent& event)
   rIF.labelAdd ("Inverse Fourier Image");
   m_bMinSpecified = false;
   m_bMaxSpecified = false;
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -727,7 +743,8 @@ ImageFileView::OnShuffleNaturalToFourierOrder (wxCommandEvent& event)
   rIF.labelAdd ("Shuffle Natural To Fourier Order");
   m_bMinSpecified = false;
   m_bMaxSpecified = false;
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -739,7 +756,8 @@ ImageFileView::OnShuffleFourierToNaturalOrder (wxCommandEvent& event)
   rIF.labelAdd ("Shuffle Fourier To Natural Order");
   m_bMinSpecified = false;
   m_bMaxSpecified = false;
-  GetDocument()->Modify (true);
+  if (theApp->getAskDeleteNewDocs())
+    GetDocument()->Modify (true);
   GetDocument()->UpdateAllViews (this);
 }
 
@@ -752,7 +770,8 @@ ImageFileView::OnMagnitude (wxCommandEvent& event)
     rIF.labelAdd ("Magnitude of complex-image");
     m_bMinSpecified = false;
     m_bMaxSpecified = false;
-    GetDocument()->Modify (true);
+    if (theApp->getAskDeleteNewDocs())
+      GetDocument()->Modify (true);
     GetDocument()->UpdateAllViews (this);
   }
 }
@@ -766,7 +785,8 @@ ImageFileView::OnPhase (wxCommandEvent& event)
     rIF.labelAdd ("Phase of complex-image");
     m_bMinSpecified = false;
     m_bMaxSpecified = false;
-    GetDocument()->Modify (true);
+    if (theApp->getAskDeleteNewDocs())
+      GetDocument()->Modify (true);
     GetDocument()->UpdateAllViews (this);
   }
 }
@@ -813,7 +833,7 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   m_pFileMenu->Append(wxID_REVERT, "Re&vert");
   
   m_pFileMenu->AppendSeparator();
-  m_pFileMenu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
+  m_pFileMenu->Append(IFMENU_FILE_PROPERTIES, "P&roperties\tCtrl-I");
   m_pFileMenu->Append(IFMENU_FILE_EXPORT, "&Export...");
   
   m_pFileMenu->AppendSeparator();
@@ -822,6 +842,7 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   m_pFileMenu->Append(wxID_PREVIEW, "Print Preview");
 #ifdef CTSIM_MDI
   m_pFileMenu->AppendSeparator();
+  m_pFileMenu->Append (MAINMENU_FILE_PREFERENCES, "Prefere&nces...");
   m_pFileMenu->Append(MAINMENU_FILE_EXIT, "E&xit");
 #endif
   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
@@ -840,14 +861,14 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   filter_menu->Append (IFMENU_FILTER_EXP, "&Exp");
   filter_menu->AppendSeparator();
 #ifdef HAVE_FFT
-  filter_menu->Append (IFMENU_FILTER_FFT, "2D &FFT");
-  filter_menu->Append (IFMENU_FILTER_IFFT, "2D &IFFT");
+  filter_menu->Append (IFMENU_FILTER_FFT, "2-D &FFT");
+  filter_menu->Append (IFMENU_FILTER_IFFT, "2-D &IFFT");
   filter_menu->Append (IFMENU_FILTER_FFT_ROWS, "FFT Rows");
   filter_menu->Append (IFMENU_FILTER_IFFT_ROWS, "IFFT Rows");
   filter_menu->Append (IFMENU_FILTER_FFT_COLS, "FFT Columns");
   filter_menu->Append (IFMENU_FILTER_IFFT_COLS, "IFFT Columns");
-  filter_menu->Append (IFMENU_FILTER_FOURIER, "F&ourier");
-  filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "Inverse Fo&urier");
+  filter_menu->Append (IFMENU_FILTER_FOURIER, "2-D F&ourier");
+  filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "2-D Inverse Fo&urier");
 #else
   filter_menu->Append (IFMENU_FILTER_FOURIER, "&Fourier");
   filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "&Inverse Fourier");
@@ -873,12 +894,12 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   m_pMenuAnalyze->Append (IFMENU_PLOT_COL, "Plot &Column");
   m_pMenuAnalyze->Append (IFMENU_PLOT_HISTOGRAM, "Plot &Histogram");
   m_pMenuAnalyze->AppendSeparator();
-  m_pMenuAnalyze->Append (IFMENU_PLOT_FFT_ROW, "Plot FFT Row");
-  m_pMenuAnalyze->Append (IFMENU_PLOT_FFT_COL, "Plot FFT Column");
+  m_pMenuAnalyze->Append (IFMENU_PLOT_FFT_ROW, "P&lot FFT Row");
+  m_pMenuAnalyze->Append (IFMENU_PLOT_FFT_COL, "Plo&t FFT Column");
   m_pMenuAnalyze->AppendSeparator();
   m_pMenuAnalyze->Append (IFMENU_COMPARE_IMAGES, "Compare &Images...");
-  m_pMenuAnalyze->Append (IFMENU_COMPARE_ROW, "Compare &Row");
-  m_pMenuAnalyze->Append (IFMENU_COMPARE_COL, "Compare &Column");
+  m_pMenuAnalyze->Append (IFMENU_COMPARE_ROW, "Compare Ro&w");
+  m_pMenuAnalyze->Append (IFMENU_COMPARE_COL, "Compare Colu&mn");
   m_pMenuAnalyze->Enable (IFMENU_PLOT_ROW, false);
   m_pMenuAnalyze->Enable (IFMENU_PLOT_COL, false);
   m_pMenuAnalyze->Enable (IFMENU_COMPARE_ROW, false);
@@ -888,7 +909,8 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   
   wxMenu *help_menu = new wxMenu;
   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
-  help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics\tCtrl-H");
+  help_menu->Append (MAINMENU_HELP_TIPS, "&Tips");
+  help_menu->Append (IDH_QUICKSTART, "&Quick Start");
   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
   
   wxMenuBar *menu_bar = new wxMenuBar;
@@ -904,24 +926,18 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   
   subframe->Centre(wxBOTH);
   
-  wxAcceleratorEntry accelEntries[11];
-  accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('O'), wxID_OPEN);
-  accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('S'), wxID_SAVE);
-  accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('W'), wxID_CLOSE);
-  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('H'), MAINMENU_HELP_TOPICS);
-  accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('P'), MAINMENU_FILE_CREATE_PHANTOM);
-  accelEntries[5].Set (wxACCEL_CTRL, static_cast<int>('F'), MAINMENU_FILE_CREATE_FILTER);
-  accelEntries[6].Set (wxACCEL_NORMAL, WXK_F1, MAINMENU_HELP_CONTENTS);
-  accelEntries[7].Set (wxACCEL_CTRL, static_cast<int>('A'), IFMENU_VIEW_SCALE_AUTO);
-  accelEntries[8].Set (wxACCEL_CTRL, static_cast<int>('U'), IFMENU_VIEW_SCALE_FULL);
-  accelEntries[9].Set (wxACCEL_CTRL, static_cast<int>('E'), IFMENU_VIEW_SCALE_MINMAX);
+  wxAcceleratorEntry accelEntries[5];
+  accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('A'), IFMENU_VIEW_SCALE_AUTO);
+  accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('U'), IFMENU_VIEW_SCALE_FULL);
+  accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('E'), IFMENU_VIEW_SCALE_MINMAX);
+  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('I'), IFMENU_FILE_PROPERTIES);
 #if wxUSE_GLCANVAS
-  accelEntries[10].Set (wxACCEL_CTRL, static_cast<int>('3'), IFMENU_IMAGE_CONVERT3D);
-  wxAcceleratorTable accelTable (11, accelEntries);
+  accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('3'), IFMENU_IMAGE_CONVERT3D);
+  wxAcceleratorTable accelTable (5, accelEntries);
 #else
-  wxAcceleratorTable accelTable (10, accelEntries);
+  wxAcceleratorTable accelTable (4, accelEntries);
 #endif
-
+  
   subframe->SetAcceleratorTable (accelTable);
   
   return subframe;
@@ -932,7 +948,6 @@ bool
 ImageFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
 {
   m_pFrame = CreateChildFrame(doc, this);
-  (m_pFrame);
   
   m_bMinSpecified = false;
   m_bMaxSpecified = false;
@@ -989,6 +1004,10 @@ ImageFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
     double scaleWidth = m_dMaxPixel - m_dMinPixel;
     
     unsigned char* imageData = new unsigned char [nx * ny * 3];
+    if (! imageData) {
+      sys_error (ERR_SEVERE, "Unable to allocate memory for Image display");
+      return;
+    }
     for (int ix = 0; ix < nx; ix++) {
       for (int iy = 0; iy < ny; iy++) {
         double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
@@ -1019,7 +1038,7 @@ ImageFileView::OnClose (bool deleteWindow)
   //GetDocumentManager()->ActivateView (this, false, true);
   if (! GetDocument() || ! GetDocument()->Close())
     return false;
-
+  
   Activate (false);
   if (m_pCanvas) {
     m_pCanvas->setView(NULL);
@@ -1032,7 +1051,7 @@ ImageFileView::OnClose (bool deleteWindow)
   SetFrame(NULL);
   
   if (deleteWindow) {
-    m_pFrame->Destroy();
+    delete m_pFrame;
     m_pFrame = NULL;
     if (GetDocument() && GetDocument()->getBadFileOpen())
       ::wxYield();  // wxWindows bug workaround
@@ -1110,7 +1129,8 @@ ImageFileView::OnScaleSize (wxCommandEvent& event)
     rScaledIF.labelAdd (os.str().c_str());
     rIF.scaleImage (rScaledIF);
     *theApp->getLog() << os.str().c_str() << "\n";
-    pScaledDoc->Modify (true);
+    if (theApp->getAskDeleteNewDocs())
+      pScaledDoc->Modify (true);
     pScaledDoc->UpdateAllViews (this);
     pScaledDoc->getView()->OnUpdate (this, NULL);
     pScaledDoc->getView()->getFrame()->Show(true);
@@ -1125,8 +1145,13 @@ ImageFileView::OnConvert3d (wxCommandEvent& event)
   Graph3dFileDocument* pGraph3d = theApp->newGraph3dDoc();
   pGraph3d->setBadFileOpen();
   pGraph3d->createFromImageFile (rIF);
-  pGraph3d->getView()->getFrame()->SetClientSize (200, 200);
+  pGraph3d->getView()->OnUpdate (this, NULL);
+  pGraph3d->UpdateAllViews();
+  pGraph3d->getView()->getFrame()->SetClientSize (400, 400);
   pGraph3d->getView()->getFrame()->Show (true);
+  GetDocumentManager()->ActivateView (pGraph3d->getView(), true, false);
+  ::wxYield();
+  pGraph3d->getView()->getCanvas()->SetFocus();
 }
 #endif
 
@@ -1208,7 +1233,8 @@ ImageFileView::OnPlotRow (wxCommandEvent& event)
       delete pYImag;
       delete pYMag;
     }
-    pPlotDoc->Modify (true);
+    if (theApp->getAskDeleteNewDocs())
+      pPlotDoc->Modify (true);
     pPlotDoc->UpdateAllViews ();
     pPlotDoc->getView()->OnUpdate (this, NULL);
     pPlotDoc->getView()->getFrame()->Show(true);
@@ -1293,7 +1319,8 @@ ImageFileView::OnPlotCol (wxCommandEvent& event)
       delete pYImag;
       delete pYMag;
     }
-    pPlotDoc->Modify (true);
+    if (theApp->getAskDeleteNewDocs())
+      pPlotDoc->Modify (true);
     pPlotDoc->UpdateAllViews ();
     pPlotDoc->getView()->OnUpdate (this, NULL);
     pPlotDoc->getView()->getFrame()->Show(true);
@@ -1387,7 +1414,8 @@ ImageFileView::OnPlotFFTRow (wxCommandEvent& event)
     delete pYMag;
     delete [] pcIn;
     
-    pPlotDoc->Modify (true);
+    if (theApp->getAskDeleteNewDocs())
+      pPlotDoc->Modify (true);
     pPlotDoc->UpdateAllViews ();
     pPlotDoc->getView()->OnUpdate (this, NULL);
     pPlotDoc->getView()->getFrame()->Show(true);
@@ -1487,7 +1515,8 @@ ImageFileView::OnPlotFFTCol (wxCommandEvent& event)
     delete pdTemp;
     delete [] pcIn;
     
-    pPlotDoc->Modify (true);
+    if (theApp->getAskDeleteNewDocs())
+      pPlotDoc->Modify (true);
     pPlotDoc->UpdateAllViews ();
     pPlotDoc->getView()->OnUpdate (this, NULL);
     pPlotDoc->getView()->getFrame()->Show(true);
@@ -1577,7 +1606,8 @@ ImageFileView::OnCompareCol (wxCommandEvent& event)
       delete pX;
       delete pY1;
       delete pY2;
-      pPlotDoc->Modify (true);
+      if (theApp->getAskDeleteNewDocs())
+        pPlotDoc->Modify (true);
       pPlotDoc->UpdateAllViews ();
       pPlotDoc->getView()->OnUpdate (this, NULL);
       pPlotDoc->getView()->getFrame()->Show(true);
@@ -1668,7 +1698,8 @@ ImageFileView::OnCompareRow (wxCommandEvent& event)
       delete pX;
       delete pY1;
       delete pY2;
-      pPlotDoc->Modify (true);
+      if (theApp->getAskDeleteNewDocs())
+        pPlotDoc->Modify (true);
       pPlotDoc->UpdateAllViews ();
       pPlotDoc->getView()->OnUpdate (this, NULL);
       pPlotDoc->getView()->getFrame()->Show(true);
@@ -1734,7 +1765,8 @@ ImageFileView::OnPlotHistogram (wxCommandEvent& event)
       rPlotFile.addDescription (os.str().c_str());
       delete pX;
       delete pY;
-      pPlotDoc->Modify (true);
+      if (theApp->getAskDeleteNewDocs())
+        pPlotDoc->Modify (true);
       pPlotDoc->UpdateAllViews ();
       pPlotDoc->getView()->OnUpdate (this, NULL);
       pPlotDoc->getView()->getFrame()->Show(true);
@@ -1762,6 +1794,20 @@ PhantomCanvas::OnDraw (wxDC& dc)
     m_pView->OnDraw(& dc);
 }
 
+wxSize
+PhantomCanvas::GetBestSize() const
+{
+  if (! m_pView)
+    return wxSize(0,0);
+  
+  int xSize, ySize;
+  theApp->getMainFrame()->GetClientSize (&xSize, &ySize);
+  xSize = maxValue<int> (xSize, ySize);
+  ySize = xSize = (xSize / 4);
+  return wxSize (xSize, ySize);
+}
+
+
 
 // PhantomFileView
 
@@ -1783,10 +1829,11 @@ PhantomFileView::PhantomFileView()
   m_iDefaultNDet = 367;
   m_iDefaultNView = 320;
 #endif
-  m_iDefaultNSample = 1;
+  m_iDefaultNSample = 2;
   m_dDefaultRotation = 1;
   m_dDefaultFocalLength = 2;
-  m_dDefaultFieldOfView = 1;
+  m_dDefaultViewRatio = 1;
+  m_dDefaultScanRatio = 1;
   m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL;
   m_iDefaultTrace = Trace::TRACE_NONE;
   
@@ -1799,6 +1846,7 @@ PhantomFileView::PhantomFileView()
   m_iDefaultRasterNY = 256;
   m_iDefaultRasterNSamples = 2;
 #endif
+  m_dDefaultRasterViewRatio = 1;
 }
 
 PhantomFileView::~PhantomFileView()
@@ -1827,139 +1875,187 @@ PhantomFileView::OnProperties (wxCommandEvent& event)
 void
 PhantomFileView::OnProjections (wxCommandEvent& event)
 {
-  DialogGetProjectionParameters dialogProjection (getFrameForChild(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView, m_iDefaultGeometry, m_iDefaultTrace);
+  DialogGetProjectionParameters dialogProjection (getFrameForChild(), 
+    m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, 
+    m_dDefaultFocalLength, m_dDefaultViewRatio, m_dDefaultScanRatio, m_iDefaultGeometry, 
+    m_iDefaultTrace);
   int retVal = dialogProjection.ShowModal();
-  if (retVal == wxID_OK) {
-    m_iDefaultNDet = dialogProjection.getNDet();
-    m_iDefaultNView = dialogProjection.getNView();
-    m_iDefaultNSample = dialogProjection.getNSamples();
-    m_iDefaultTrace = dialogProjection.getTrace();
-    m_dDefaultRotation = dialogProjection.getRotAngle();
-    m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
-    m_dDefaultFieldOfView = dialogProjection.getFieldOfViewRatio();
-    wxString sGeometry = dialogProjection.getGeometry();
-    m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
+  if (retVal != wxID_OK) 
+    return;
+  
+  m_iDefaultNDet = dialogProjection.getNDet();
+  m_iDefaultNView = dialogProjection.getNView();
+  m_iDefaultNSample = dialogProjection.getNSamples();
+  m_iDefaultTrace = dialogProjection.getTrace();
+  m_dDefaultRotation = dialogProjection.getRotAngle();
+  m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
+  m_dDefaultViewRatio = dialogProjection.getViewRatio();
+  m_dDefaultScanRatio = dialogProjection.getScanRatio();
+  wxString sGeometry = dialogProjection.getGeometry();
+  m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
+  double dRotationRadians = m_dDefaultRotation;
+  m_dDefaultRotation /= TWOPI;  // convert back to fraction of a circle
+  
+  if (m_iDefaultNDet <= 0 || m_iDefaultNView <= 0 || sGeometry == "")
+    return;
+  
+  const Phantom& rPhantom = GetDocument()->getPhantom();
+  Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, 
+    dRotationRadians, m_dDefaultFocalLength, m_dDefaultViewRatio, m_dDefaultScanRatio);
+  if (theScanner.fail()) {
+    wxString msg = "Failed making scanner\n";
+    msg += theScanner.failMessage().c_str();
+    *theApp->getLog() << msg << "\n";
+    wxMessageBox (msg, "Error");
+    return;
+  }
+  
+  std::ostringstream os;
+  os << "Projections for " << rPhantom.name() << ": nDet=" << m_iDefaultNDet 
+    << ", nView=" << m_iDefaultNView << ", nSamples=" << m_iDefaultNSample 
+    << ", RotAngle=" << m_dDefaultRotation << ", FocalLengthRatio=" << m_dDefaultFocalLength 
+    << ", ViewRatio=" << m_dDefaultViewRatio << ", ScanRatio=" << m_dDefaultScanRatio 
+    << ", Geometry=" << sGeometry.c_str() << ", FanBeamAngle=" << 
+    convertRadiansToDegrees (theScanner.fanBeamAngle());
+  
+  Timer timer;
+  Projections* pProj = NULL;
+  if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
+    pProj = new Projections;
+    pProj->initFromScanner (theScanner);
     
-    if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
-      const Phantom& rPhantom = GetDocument()->getPhantom();
-      Projections* pProj = new Projections;
-      Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, 
-                          m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView);
-      if (theScanner.fail()) {
-        *theApp->getLog() << "Failed making scanner: " << theScanner.failMessage().c_str() << "\n";
+    ProjectionsDialog dialogProjections (theScanner, *pProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(getFrameForChild()));
+    for (int iView = 0; iView < pProj->nView(); iView++) {
+      ::wxYield();
+      if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
+        delete pProj;
         return;
       }
-      pProj->initFromScanner (theScanner);
-      m_dDefaultRotation /= PI;  // convert back to PI units
-      
-      Timer timer;
-      if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
-        ProjectionsDialog dialogProjections (theScanner, *pProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(getFrameForChild()));
-        for (int iView = 0; iView < pProj->nView(); iView++) {
-          ::wxYield();
-          if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
-            delete pProj;
-            return;
-          }
-          ::wxYield();
-          while (dialogProjections.isPaused()) {
-            ::wxYield();
-            ::wxUsleep(50);
-          }
-        }
-      } else {
-        wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), pProj->nView() + 1, getFrameForChild(), wxPD_CAN_ABORT);
-        for (int i = 0; i < pProj->nView(); i++) {
-          theScanner.collectProjections (*pProj, rPhantom, i, 1, true, m_iDefaultTrace);
-          if (! dlgProgress.Update (i+1)) {
-            delete pProj;
-            return;
-          }
-        }
-      }
-      
-      std::ostringstream os;
-      os << "Projections for " << rPhantom.name() << ": nDet=" << m_iDefaultNDet << ", nView=" << m_iDefaultNView << ", nSamples=" << m_iDefaultNSample << ", RotAngle=" << m_dDefaultRotation << ", FocalLengthRatio=" << m_dDefaultFocalLength << ", FieldOfViewRatio=" << m_dDefaultFieldOfView << ", Geometry=" << sGeometry.c_str();
-      pProj->setCalcTime (timer.timerEnd());
-      pProj->setRemark (os.str());
-      *theApp->getLog() << os.str().c_str() << "\n";
-      
       ::wxYield();
-      ProjectionFileDocument* pProjectionDoc = theApp->newProjectionDoc();
-      if (! pProjectionDoc) {
-        sys_error (ERR_SEVERE, "Unable to create projection document");
+      while (dialogProjections.isPaused()) {
+        ::wxYield();
+        ::wxUsleep(50);
+      }
+    }
+  } else {
+    if (theApp->getUseBackgroundTasks() || theApp->getNumberCPU() > 1) {
+      ProjectorSupervisorThread* pProjector = new ProjectorSupervisorThread (this, m_iDefaultNDet,
+        m_iDefaultNView, sGeometry.c_str(), m_iDefaultNSample, dRotationRadians,
+        m_dDefaultFocalLength, m_dDefaultViewRatio, m_dDefaultScanRatio, os.str().c_str());
+      if (pProjector->Create() != wxTHREAD_NO_ERROR) {
+        sys_error (ERR_SEVERE, "Error creating projector thread");
+        delete pProjector;
         return;
       }
-      pProjectionDoc->setProjections (pProj);
-      ProjectionFileView* projView = pProjectionDoc->getView();
-      if (projView) {
-        projView->OnUpdate (projView, NULL);
-        if (projView->getCanvas())
-             projView->getCanvas()->SetClientSize (m_iDefaultNDet, m_iDefaultNView);
-        if (wxFrame* pFrame = projView->getFrame()) {
-          pFrame->Show(true);
-          pFrame->SetFocus();
-          pFrame->Raise();
+      pProjector->SetPriority(60);
+      pProjector->Run();
+      return;
+    } else {
+      pProj = new Projections;
+      pProj->initFromScanner (theScanner);
+      wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), pProj->nView() + 1, getFrameForChild(), wxPD_CAN_ABORT );
+      for (int i = 0; i < pProj->nView(); i++) {
+        theScanner.collectProjections (*pProj, rPhantom, i, 1, true, m_iDefaultTrace);
+        if (! dlgProgress.Update (i+1)) {
+          delete pProj;
+          return;
         }
-        GetDocumentManager()->ActivateView (projView, true, false);
       }
-      ::wxYield();
-      pProjectionDoc-> Modify(true);
-      pProjectionDoc->UpdateAllViews (this);
     }
   }
+  
+  *theApp->getLog() << os.str().c_str() << "\n";
+  pProj->setRemark (os.str());
+  pProj->setCalcTime (timer.timerEnd());
+  
+  ProjectionFileDocument* pProjectionDoc = theApp->newProjectionDoc();
+  if (! pProjectionDoc) {
+    sys_error (ERR_SEVERE, "Unable to create projection document");
+    return;
+  }
+  pProjectionDoc->setProjections (pProj);
+  ProjectionFileView* projView = pProjectionDoc->getView();
+  if (projView) {
+    projView->OnUpdate (projView, NULL);
+    if (projView->getCanvas())
+      projView->getCanvas()->SetClientSize (m_iDefaultNDet, m_iDefaultNView);
+    if (wxFrame* pFrame = projView->getFrame()) {
+      pFrame->Show(true);
+      pFrame->SetFocus();
+      pFrame->Raise();
+    }
+    GetDocumentManager()->ActivateView (projView, true, false);
+  }
+  if (theApp->getAskDeleteNewDocs())
+    pProjectionDoc-> Modify(true);
+  pProjectionDoc->UpdateAllViews (this);
 }
 
 
 void
 PhantomFileView::OnRasterize (wxCommandEvent& event)
 {
-  DialogGetRasterParameters dialogRaster (getFrameForChild(), m_iDefaultRasterNX, m_iDefaultRasterNY, m_iDefaultRasterNSamples);
+  DialogGetRasterParameters dialogRaster (getFrameForChild(), m_iDefaultRasterNX, m_iDefaultRasterNY, 
+    m_iDefaultRasterNSamples, m_dDefaultRasterViewRatio);
   int retVal = dialogRaster.ShowModal();
-  if (retVal == wxID_OK) {
-    m_iDefaultRasterNX = dialogRaster.getXSize();
-    m_iDefaultRasterNY  = dialogRaster.getYSize();
-    m_iDefaultRasterNSamples = dialogRaster.getNSamples();
-    if (m_iDefaultRasterNSamples < 1)
-      m_iDefaultRasterNSamples = 1;
-    if (m_iDefaultRasterNX > 0 && m_iDefaultRasterNY > 0) {
-      const Phantom& rPhantom = GetDocument()->getPhantom();
-
-      ImageFile* pImageFile = new ImageFile;
-      
-      pImageFile->setArraySize (m_iDefaultRasterNX, m_iDefaultRasterNY);
-      wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), 
-                                    pImageFile->nx() + 1, getFrameForChild(), wxPD_CAN_ABORT);
-      Timer timer;
-      for (unsigned int i = 0; i < pImageFile->nx(); i++) {
-        rPhantom.convertToImagefile (*pImageFile, m_iDefaultRasterNSamples, Trace::TRACE_NONE, i, 1, true);
-        if (! dlgProgress.Update (i+1)) {
-          delete pImageFile;
-          return;
-        }
-      }
-
-      ImageFileDocument* pRasterDoc = theApp->newImageDoc();
-      if (! pRasterDoc) {
-        sys_error (ERR_SEVERE, "Unable to create image file");
+  if (retVal != wxID_OK)
+    return;
+  
+  m_iDefaultRasterNX = dialogRaster.getXSize();
+  m_iDefaultRasterNY  = dialogRaster.getYSize();
+  m_iDefaultRasterNSamples = dialogRaster.getNSamples();
+  m_dDefaultRasterViewRatio = dialogRaster.getViewRatio();
+  if (m_iDefaultRasterNSamples < 1)
+    m_iDefaultRasterNSamples = 1;
+  if (m_dDefaultRasterViewRatio < 0)
+    m_dDefaultRasterViewRatio = 0;
+  if (m_iDefaultRasterNX <= 0 || m_iDefaultRasterNY <= 0) 
+    return;
+  
+  const Phantom& rPhantom = GetDocument()->getPhantom();
+  std::ostringstream os;
+  os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << m_iDefaultRasterNX << ", YSize=" 
+    << m_iDefaultRasterNY << ", ViewRatio=" << m_dDefaultRasterViewRatio << ", nSamples=" 
+    << m_iDefaultRasterNSamples;;
+
+  if (theApp->getUseBackgroundTasks() || theApp->getNumberCPU() > 1) {
+    RasterizerSupervisorThread* pThread = new RasterizerSupervisorThread (this, m_iDefaultRasterNX, m_iDefaultRasterNY,
+      m_dDefaultRasterViewRatio, m_iDefaultRasterNSamples, os.str().c_str());
+    if (pThread->Create() != wxTHREAD_NO_ERROR) {
+      *theApp->getLog() << "Error creating rasterizer thread\n";
+      return;
+    }
+    pThread->SetPriority (60);
+    pThread->Run();
+  } else {
+    ImageFile* pImageFile = new ImageFile (m_iDefaultRasterNX, m_iDefaultRasterNY);
+    wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), 
+      pImageFile->nx() + 1, getFrameForChild(), wxPD_CAN_ABORT );
+    Timer timer;
+    for (unsigned int i = 0; i < pImageFile->nx(); i++) {
+      rPhantom.convertToImagefile (*pImageFile, m_dDefaultRasterViewRatio, m_iDefaultRasterNSamples, Trace::TRACE_NONE, i, 1, true);
+      if (! dlgProgress.Update (i+1)) {
+        delete pImageFile;
         return;
       }
-      pRasterDoc->setImageFile (pImageFile);
-
+    }
+  
+    ImageFileDocument* pRasterDoc = theApp->newImageDoc();
+    if (! pRasterDoc) {
+      sys_error (ERR_SEVERE, "Unable to create image file");
+      return;
+    }
+    pRasterDoc->setImageFile (pImageFile);
+    if (theApp->getAskDeleteNewDocs())
       pRasterDoc->Modify (true);
-      pRasterDoc->UpdateAllViews (this);
-      pRasterDoc->getView()->getFrame()->Show(true);
-      std::ostringstream os;
-      os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << m_iDefaultRasterNX << ", YSize=" 
-        << m_iDefaultRasterNY << ", nSamples=" << m_iDefaultRasterNSamples;
-      *theApp->getLog() << os.str().c_str() << "\n";
-      pImageFile->labelAdd (os.str().c_str(), timer.timerEnd());
-      ImageFileView* rasterView = pRasterDoc->getView();
-      if (rasterView) {
-        rasterView->getFrame()->SetFocus();
-        rasterView->OnUpdate (rasterView, NULL);
-      }
-      
+    pRasterDoc->UpdateAllViews (this);
+    pRasterDoc->getView()->getFrame()->Show(true);
+    *theApp->getLog() << os.str().c_str() << "\n";
+    pImageFile->labelAdd (os.str().c_str(), timer.timerEnd());
+    ImageFileView* rasterView = pRasterDoc->getView();
+    if (rasterView) {
+      rasterView->getFrame()->SetFocus();
+      rasterView->OnUpdate (rasterView, NULL);
     }
   }
 }
@@ -1969,11 +2065,8 @@ PhantomCanvas*
 PhantomFileView::CreateCanvas (wxFrame *parent)
 {
   PhantomCanvas* pCanvas;
-  int width, height;
-  parent->GetClientSize(&width, &height);
-  
-  pCanvas = new PhantomCanvas (this, parent, wxPoint(0, 0), wxSize(width, height), 0);
   
+  pCanvas = new PhantomCanvas (this, parent, wxPoint(0, 0), wxSize(0,0), 0);
   pCanvas->SetBackgroundColour(*wxWHITE);
   pCanvas->Clear();
   
@@ -1988,9 +2081,9 @@ wxDocChildFrame*
 PhantomFileView::CreateChildFrame(wxDocument *doc, wxView *view)
 {
 #if CTSIM_MDI
-  wxDocMDIChildFrame *subframe = new wxDocMDIChildFrame (doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
+  wxDocMDIChildFrame *subframe = new wxDocMDIChildFrame (doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
 #else
-  wxDocChildFrame *subframe = new wxDocChildFrame (doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
+  wxDocChildFrame *subframe = new wxDocChildFrame (doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
 #endif
   theApp->setIconForFrame (subframe);
   
@@ -2003,7 +2096,7 @@ PhantomFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   m_pFileMenu->Append(wxID_CLOSE, "&Close");
   
   m_pFileMenu->AppendSeparator();
-  m_pFileMenu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
+  m_pFileMenu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties\tCtrl-I");
   
   m_pFileMenu->AppendSeparator();
   m_pFileMenu->Append(wxID_PRINT, "&Print...");
@@ -2011,6 +2104,7 @@ PhantomFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   m_pFileMenu->Append(wxID_PREVIEW, "Print Pre&view");
 #ifdef CTSIM_MDI
   m_pFileMenu->AppendSeparator();
+  m_pFileMenu->Append (MAINMENU_FILE_PREFERENCES, "Prefere&nces...");
   m_pFileMenu->Append(MAINMENU_FILE_EXIT, "E&xit");
 #endif
   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
@@ -2022,7 +2116,8 @@ PhantomFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   
   wxMenu *help_menu = new wxMenu;
   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
-  help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics\tCtrl-H");
+  help_menu->Append (MAINMENU_HELP_TIPS, "&Tips");
+  help_menu->Append (IDH_QUICKSTART, "&Quick Start");
   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
   
   wxMenuBar *menu_bar = new wxMenuBar;
@@ -2034,16 +2129,11 @@ PhantomFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   subframe->SetMenuBar(menu_bar);
   subframe->Centre(wxBOTH);
   
-  wxAcceleratorEntry accelEntries[8];
-  accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('O'), wxID_OPEN);
-  accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('S'), wxID_SAVE);
-  accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('H'), MAINMENU_HELP_TOPICS);
-  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('P'), MAINMENU_FILE_CREATE_PHANTOM);
-  accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('F'), MAINMENU_FILE_CREATE_FILTER);
-  accelEntries[5].Set (wxACCEL_NORMAL, WXK_F1, MAINMENU_HELP_CONTENTS);
-  accelEntries[6].Set (wxACCEL_CTRL, static_cast<int>('J'), PHMMENU_PROCESS_PROJECTIONS);
-  accelEntries[7].Set (wxACCEL_CTRL, static_cast<int>('R'), PHMMENU_PROCESS_RASTERIZE);
-  wxAcceleratorTable accelTable (8, accelEntries);
+  wxAcceleratorEntry accelEntries[3];
+  accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('J'), PHMMENU_PROCESS_PROJECTIONS);
+  accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('R'), PHMMENU_PROCESS_RASTERIZE);
+  accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('I'), PHMMENU_FILE_PROPERTIES);
+  wxAcceleratorTable accelTable (3, accelEntries);
   subframe->SetAcceleratorTable (accelTable);
   
   return subframe;
@@ -2055,11 +2145,11 @@ PhantomFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
 {
   m_pFrame = CreateChildFrame(doc, this);
   SetFrame(m_pFrame);
-  
-  int width, height;
-  m_pFrame->GetClientSize(&width, &height);
-  m_pFrame->SetTitle("PhantomFileView");
   m_pCanvas = CreateCanvas (m_pFrame);
+  m_pFrame->SetClientSize (m_pCanvas->GetBestSize());
+  m_pCanvas->SetClientSize (m_pCanvas->GetBestSize());
+  
+  m_pFrame->SetTitle ("PhantomFileView");
   
 #ifdef __X__
   int x, y;  // X requires a forced resize
@@ -2160,12 +2250,13 @@ IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
 EVT_MENU(PJMENU_RECONSTRUCT_FBP, ProjectionFileView::OnReconstructFBP)
+EVT_MENU(PJMENU_RECONSTRUCT_FOURIER, ProjectionFileView::OnReconstructFourier)
 EVT_MENU(PJMENU_CONVERT_POLAR, ProjectionFileView::OnConvertPolar)
 EVT_MENU(PJMENU_CONVERT_FFT_POLAR, ProjectionFileView::OnConvertFFTPolar)
 END_EVENT_TABLE()
 
 ProjectionFileView::ProjectionFileView() 
-: wxView(), m_pCanvas(NULL), m_pFrame(NULL), m_pFileMenu(0)
+: wxView(), m_pFrame(0), m_pCanvas(0), m_pFileMenu(0)
 {
 #ifdef DEBUG
   m_iDefaultNX = 115;
@@ -2185,7 +2276,7 @@ ProjectionFileView::ProjectionFileView()
   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_DIRECT;
 #endif
   m_iDefaultZeropad = 1;
-  m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF3;
+  m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF;
   m_iDefaultInterpolation = Backprojector::INTERP_LINEAR;
   m_iDefaultInterpParam = 1;
   m_iDefaultTrace = Trace::TRACE_NONE;
@@ -2225,22 +2316,28 @@ ProjectionFileView::OnConvertPolar (wxCommandEvent& event)
     m_iDefaultPolarNX = dialogPolar.getXSize();
     m_iDefaultPolarNY = dialogPolar.getYSize();
     ImageFileDocument* pPolarDoc = theApp->newImageDoc();
-    ImageFile& rIF = pPolarDoc->getImageFile();
+    ImageFile* pIF = new ImageFile (m_iDefaultPolarNX, m_iDefaultPolarNY);
+    m_iDefaultPolarInterpolation = Projections::convertInterpNameToID (strInterpolation.c_str());
+    if (! rProj.convertPolar (*pIF, m_iDefaultPolarInterpolation)) {
+      delete pIF;
+      *theApp->getLog() << "Error converting to Polar\n";
+      return;
+    }
+    pPolarDoc = theApp->newImageDoc ();
     if (! pPolarDoc) {
       sys_error (ERR_SEVERE, "Unable to create image file");
       return;
     }
-    rIF.setArraySize (m_iDefaultPolarNX, m_iDefaultPolarNY);
-    m_iDefaultPolarInterpolation = Projections::convertInterpNameToID (strInterpolation.c_str());
-    rProj.convertPolar (rIF, m_iDefaultPolarInterpolation);
-    rIF.labelAdd (rProj.getLabel().getLabelString().c_str(), rProj.calcTime());
+    pPolarDoc->setImageFile (pIF);
+    pIF->labelAdd (rProj.getLabel().getLabelString().c_str(), rProj.calcTime());
     std::ostringstream os;
     os << "Convert projection file " << GetFrame()->GetTitle().c_str() << " to polar image: xSize=" 
       << m_iDefaultPolarNX << ", ySize=" << m_iDefaultPolarNY << ", interpolation=" 
       << strInterpolation.c_str();
     *theApp->getLog() << os.str().c_str() << "\n";
-    rIF.labelAdd (os.str().c_str());
-    pPolarDoc->Modify (true);
+    pIF->labelAdd (os.str().c_str());
+    if (theApp->getAskDeleteNewDocs())
+      pPolarDoc->Modify (true);
     pPolarDoc->UpdateAllViews ();
     pPolarDoc->getView()->OnUpdate (this, NULL);
     pPolarDoc->getView()->getFrame()->Show(true);
@@ -2258,23 +2355,29 @@ ProjectionFileView::OnConvertFFTPolar (wxCommandEvent& event)
     m_iDefaultPolarNX = dialogPolar.getXSize();
     m_iDefaultPolarNY = dialogPolar.getYSize();
     m_iDefaultPolarZeropad = dialogPolar.getZeropad();
+    ImageFile* pIF = new ImageFile (m_iDefaultPolarNX, m_iDefaultPolarNY);
+    
+    m_iDefaultPolarInterpolation = Projections::convertInterpNameToID (strInterpolation.c_str());
+    if (! rProj.convertFFTPolar (*pIF, m_iDefaultPolarInterpolation, m_iDefaultPolarZeropad)) {
+      delete pIF;
+      *theApp->getLog() << "Error converting to polar\n";
+      return;
+    }
     ImageFileDocument* pPolarDoc = theApp->newImageDoc();
-    ImageFile& rIF = pPolarDoc->getImageFile();
     if (! pPolarDoc) {
       sys_error (ERR_SEVERE, "Unable to create image file");
       return;
     }
-    rIF.setArraySize (m_iDefaultPolarNX, m_iDefaultPolarNY);
-    m_iDefaultPolarInterpolation = Projections::convertInterpNameToID (strInterpolation.c_str());
-    rProj.convertFFTPolar (rIF, m_iDefaultPolarInterpolation, m_iDefaultPolarZeropad);
-    rIF.labelAdd (rProj.getLabel().getLabelString().c_str(), rProj.calcTime());
+    pPolarDoc->setImageFile (pIF);
+    pIF->labelAdd (rProj.getLabel().getLabelString().c_str(), rProj.calcTime());
     std::ostringstream os;
     os << "Convert projection file " << GetFrame()->GetTitle().c_str() << " to FFT polar image: xSize=" 
       << m_iDefaultPolarNX << ", ySize=" << m_iDefaultPolarNY << ", interpolation=" 
       << strInterpolation.c_str() << ", zeropad=" << m_iDefaultPolarZeropad;
     *theApp->getLog() << os.str().c_str() << "\n";
-    rIF.labelAdd (os.str().c_str());
-    pPolarDoc->Modify (true);
+    pIF->labelAdd (os.str().c_str());
+    if (theApp->getAskDeleteNewDocs())
+      pPolarDoc->Modify (true);
     pPolarDoc->UpdateAllViews ();
     pPolarDoc->getView()->OnUpdate (this, NULL);
     pPolarDoc->getView()->getFrame()->Show(true);
@@ -2290,84 +2393,119 @@ ProjectionFileView::OnReconstructFourier (wxCommandEvent& event)
 void
 ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
 {
-  DialogGetReconstructionParameters dialogReconstruction (getFrameForChild(), m_iDefaultNX, m_iDefaultNY, m_iDefaultFilter, m_dDefaultFilterParam, m_iDefaultFilterMethod, m_iDefaultFilterGeneration, m_iDefaultZeropad, m_iDefaultInterpolation, m_iDefaultInterpParam, m_iDefaultBackprojector, m_iDefaultTrace);
+  DialogGetReconstructionParameters dialogReconstruction (getFrameForChild(), m_iDefaultNX, m_iDefaultNY, 
+    m_iDefaultFilter, m_dDefaultFilterParam, m_iDefaultFilterMethod, m_iDefaultFilterGeneration, 
+    m_iDefaultZeropad, m_iDefaultInterpolation, m_iDefaultInterpParam, m_iDefaultBackprojector, 
+    m_iDefaultTrace);
   
   int retVal = dialogReconstruction.ShowModal();
-  if (retVal == wxID_OK) {
-    m_iDefaultNX = dialogReconstruction.getXSize();
-    m_iDefaultNY = dialogReconstruction.getYSize();
-    wxString optFilterName = dialogReconstruction.getFilterName();
-    m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
-    m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
-    wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
-    m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
-    m_iDefaultZeropad = dialogReconstruction.getZeropad();
-    wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
-    m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
-    wxString optInterpName = dialogReconstruction.getInterpName();
-    m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
-    m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
-    wxString optBackprojectName = dialogReconstruction.getBackprojectName();
-    m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
-    m_iDefaultTrace = dialogReconstruction.getTrace();
-    if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
-      const Projections& rProj = GetDocument()->getProjections();
-
-      ImageFile* pImageFile = new ImageFile;
-      pImageFile->setArraySize (m_iDefaultNX, m_iDefaultNY);
-      
-      Reconstructor* pReconstructor = new Reconstructor (rProj, *pImageFile, optFilterName.c_str(), m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace);
-      
-      Timer timerRecon;
-      if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
-        ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstructor, rProj, *pImageFile, m_iDefaultTrace, getFrameForChild());
-        for (int iView = 0; iView < rProj.nView(); iView++) {
-          ::wxYield();
-          if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView)) {
-            delete pDlgReconstruct;
-            delete pReconstructor;
-            delete pImageFile;
-            return;
-          }
-          ::wxYield();
-          while (pDlgReconstruct->isPaused()) {
-            ::wxYield();
-            ::wxUsleep(50);
-          }
-        }
+  if (retVal != wxID_OK)
+    return;
+  
+  m_iDefaultNX = dialogReconstruction.getXSize();
+  m_iDefaultNY = dialogReconstruction.getYSize();
+  wxString optFilterName = dialogReconstruction.getFilterName();
+  m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
+  m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
+  wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
+  m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
+  m_iDefaultZeropad = dialogReconstruction.getZeropad();
+  wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
+  m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
+  wxString optInterpName = dialogReconstruction.getInterpName();
+  m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
+  m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
+  wxString optBackprojectName = dialogReconstruction.getBackprojectName();
+  m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
+  m_iDefaultTrace = dialogReconstruction.getTrace();
+  
+  if (m_iDefaultNX <= 0 && m_iDefaultNY <= 0) 
+    return;
+  
+  const Projections& rProj = GetDocument()->getProjections();
+  std::ostringstream os;
+  os << "Reconstruct " << rProj.getFilename() << ": xSize=" << m_iDefaultNX << ", ySize=" << m_iDefaultNY << ", Filter=" << optFilterName.c_str() << ", FilterParam=" << m_dDefaultFilterParam << ", FilterMethod=" << optFilterMethodName.c_str() << ", FilterGeneration=" << optFilterGenerationName.c_str() << ", Zeropad=" << m_iDefaultZeropad << ", Interpolation=" << optInterpName.c_str() << ", InterpolationParam=" << m_iDefaultInterpParam << ", Backprojection=" << optBackprojectName.c_str();
+  
+  Timer timerRecon;
+  ImageFile rImageFile;
+  if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
+    rImageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
+    Reconstructor* pReconstructor = new Reconstructor (rProj, rImageFile, optFilterName.c_str(), 
+      m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
+      optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace);
+    
+    ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstructor, rProj, rImageFile, m_iDefaultTrace, getFrameForChild());
+    for (int iView = 0; iView < rProj.nView(); iView++) {
+      ::wxYield();
+      if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView, true)) {
         delete pDlgReconstruct;
-      } else {
-        wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, getFrameForChild(), wxPD_CAN_ABORT);
-        for (int i = 0; i < rProj.nView(); i++) {
-          pReconstructor->reconstructView (i, 1);
-          if (! dlgProgress.Update (i + 1)) {
-            delete pReconstructor;
-            delete pImageFile;
-            return;
-          }
+        delete pReconstructor;
+        return;
+      }
+      ::wxYield();
+      ::wxYield();
+      while (pDlgReconstruct->isPaused()) {
+        ::wxYield();
+        ::wxUsleep(50);
+      }
+    }
+    pReconstructor->postProcessing();
+    delete pDlgReconstruct;
+    delete pReconstructor;
+  } else {
+    if (theApp->getUseBackgroundTasks() || theApp->getNumberCPU() > 1) {
+      ReconstructorSupervisorThread* pReconstructor = new ReconstructorSupervisorThread (this, 
+        m_iDefaultNX, m_iDefaultNY, optFilterName.c_str(), 
+        m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
+        optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), os.str().c_str());
+      if (pReconstructor->Create() != wxTHREAD_NO_ERROR) {
+        sys_error (ERR_SEVERE, "Error creating reconstructor thread");
+        delete pReconstructor;
+        return;
+      }
+      pReconstructor->SetPriority (60);
+      pReconstructor->Run();
+      return;
+    } else {
+      rImageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
+      Reconstructor* pReconstructor = new Reconstructor (rProj, rImageFile, optFilterName.c_str(), 
+        m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
+        optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace);
+      
+      wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, getFrameForChild(), wxPD_CAN_ABORT );
+      for (int iView = 0; iView < rProj.nView(); iView++) {
+        pReconstructor->reconstructView (iView, 1);
+        if (! dlgProgress.Update (iView + 1)) {
+          delete pReconstructor;
+          return; // don't make new window, thread will do this
         }
       }
+      pReconstructor->postProcessing();
       delete pReconstructor;
       ImageFileDocument* pReconDoc = theApp->newImageDoc();
       if (! pReconDoc) {
         sys_error (ERR_SEVERE, "Unable to create image file");
         return;
       }
-      pReconDoc->setImageFile (pImageFile);
-      pReconDoc->Modify (true);
-      pReconDoc->UpdateAllViews (this);
-      if (ImageFileView* rasterView = pReconDoc->getView()) {
-        rasterView->OnUpdate (rasterView, NULL);
-        rasterView->getFrame()->SetFocus();
-        rasterView->getFrame()->Show(true);
-      }
-      std::ostringstream os;
-      os << "Reconstruct " << rProj.getFilename() << ": xSize=" << m_iDefaultNX << ", ySize=" << m_iDefaultNY << ", Filter=" << optFilterName.c_str() << ", FilterParam=" << m_dDefaultFilterParam << ", FilterMethod=" << optFilterMethodName.c_str() << ", FilterGeneration=" << optFilterGenerationName.c_str() << ", Zeropad=" << m_iDefaultZeropad << ", Interpolation=" << optInterpName.c_str() << ", InterpolationParam=" << m_iDefaultInterpParam << ", Backprojection=" << optBackprojectName.c_str();
-      *theApp->getLog() << os.str().c_str() << "\n";
-      pImageFile->labelAdd (rProj.getLabel());
-      pImageFile->labelAdd (os.str().c_str(), timerRecon.timerEnd());
     }
   }
+  ImageFileDocument* pReconDoc = theApp->newImageDoc();
+  if (! pReconDoc) {
+    sys_error (ERR_SEVERE, "Unable to create image file");
+    return;
+  }
+  pReconDoc->setImageFile (&rImageFile);
+  if (theApp->getAskDeleteNewDocs())
+    pReconDoc->Modify (true);
+  pReconDoc->UpdateAllViews (this);
+  if (ImageFileView* rasterView = pReconDoc->getView()) {
+    rasterView->OnUpdate (rasterView, NULL);
+    rasterView->getFrame()->SetFocus();
+    rasterView->getFrame()->Show(true);
+  }
+  *theApp->getLog() << os.str().c_str() << "\n";
+  rImageFile.labelAdd (rProj.getLabel());
+  rImageFile.labelAdd (os.str().c_str(), timerRecon.timerEnd());    
 }
 
 
@@ -2411,7 +2549,7 @@ ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   m_pFileMenu->Append(wxID_CLOSE, "&Close\tCtrl-W");
   
   m_pFileMenu->AppendSeparator();
-  m_pFileMenu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
+  m_pFileMenu->Append(PJMENU_FILE_PROPERTIES, "P&roperties\tCtrl-I");
   
   m_pFileMenu->AppendSeparator();
   m_pFileMenu->Append(wxID_PRINT, "&Print...");
@@ -2419,6 +2557,7 @@ ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   m_pFileMenu->Append(wxID_PREVIEW, "Print Pre&view");
 #ifdef CTSIM_MDI
   m_pFileMenu->AppendSeparator();
+  m_pFileMenu->Append (MAINMENU_FILE_PREFERENCES, "Prefere&nces...");
   m_pFileMenu->Append(MAINMENU_FILE_EXIT, "E&xit");
 #endif
   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
@@ -2426,7 +2565,7 @@ ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   
   wxMenu *convert_menu = new wxMenu;
   convert_menu->Append (PJMENU_CONVERT_POLAR, "&Polar Image...\tCtrl-L");
-  convert_menu->Append (PJMENU_CONVERT_FFT_POLAR, "&FFT->Polar Image...\tCtrl-I");
+  convert_menu->Append (PJMENU_CONVERT_FFT_POLAR, "&FFT->Polar Image...\tCtrl-M");
   
   wxMenu *reconstruct_menu = new wxMenu;
   reconstruct_menu->Append (PJMENU_RECONSTRUCT_FBP, "&Filtered Backprojection...\tCtrl-R", "Reconstruct image using filtered backprojection");
@@ -2435,7 +2574,8 @@ ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   
   wxMenu *help_menu = new wxMenu;
   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
-  help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics\tCtrl-H");
+  help_menu->Append (MAINMENU_HELP_TIPS, "&Tips");
+  help_menu->Append (IDH_QUICKSTART, "&Quick Start");
   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
   
   wxMenuBar *menu_bar = new wxMenuBar;
@@ -2448,19 +2588,13 @@ ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   subframe->SetMenuBar(menu_bar);  
   subframe->Centre(wxBOTH);
   
-  wxAcceleratorEntry accelEntries[11];
-  accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('O'), wxID_OPEN);
-  accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('S'), wxID_SAVE);
-  accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('W'), wxID_CLOSE);
-  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('H'), MAINMENU_HELP_TOPICS);
-  accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('P'), MAINMENU_FILE_CREATE_PHANTOM);
-  accelEntries[5].Set (wxACCEL_CTRL, static_cast<int>('F'), MAINMENU_FILE_CREATE_FILTER);
-  accelEntries[6].Set (wxACCEL_NORMAL, WXK_F1, MAINMENU_HELP_CONTENTS);
-  accelEntries[7].Set (wxACCEL_CTRL, static_cast<int>('L'), PJMENU_CONVERT_POLAR);
-  accelEntries[8].Set (wxACCEL_CTRL, static_cast<int>('I'), PJMENU_CONVERT_FFT_POLAR);
-  accelEntries[9].Set (wxACCEL_CTRL, static_cast<int>('R'), PJMENU_RECONSTRUCT_FBP);
-  accelEntries[10].Set (wxACCEL_CTRL, static_cast<int>('E'), PJMENU_RECONSTRUCT_FOURIER);
-  wxAcceleratorTable accelTable (11, accelEntries);
+  wxAcceleratorEntry accelEntries[5];
+  accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('L'), PJMENU_CONVERT_POLAR);
+  accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('M'), PJMENU_CONVERT_FFT_POLAR);
+  accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('R'), PJMENU_RECONSTRUCT_FBP);
+  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('E'), PJMENU_RECONSTRUCT_FOURIER);
+  accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('I'), PJMENU_FILE_PROPERTIES);
+  wxAcceleratorTable accelTable (5, accelEntries);
   subframe->SetAcceleratorTable (accelTable);
   
   return subframe;
@@ -2527,6 +2661,10 @@ ProjectionFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint)
     }
     
     unsigned char* imageData = new unsigned char [nDet * nView * 3];
+    if (! imageData) {
+      sys_error (ERR_SEVERE, "Unable to allocate memory for image display");
+      return;
+    }
     double scale = (max - min) / 255;
     for (int iy2 = 0; iy2 < nView; iy2++) {
       const DetectorArray& detarray = rProj.getDetectorArray (iy2);
@@ -2577,7 +2715,7 @@ ProjectionFileView::OnClose (bool deleteWindow)
     if (GetDocument() && GetDocument()->getBadFileOpen())
       ::wxYield();  // wxWindows bug workaround
   }
-
+  
   return true;
 }
 
@@ -2608,7 +2746,7 @@ PlotFileCanvas::OnDraw(wxDC& dc)
 IMPLEMENT_DYNAMIC_CLASS(PlotFileView, wxView)
 
 BEGIN_EVENT_TABLE(PlotFileView, wxView)
-EVT_MENU(PJMENU_FILE_PROPERTIES, PlotFileView::OnProperties)
+EVT_MENU(PLOTMENU_FILE_PROPERTIES, PlotFileView::OnProperties)
 EVT_MENU(PLOTMENU_VIEW_SCALE_MINMAX, PlotFileView::OnScaleMinMax)
 EVT_MENU(PLOTMENU_VIEW_SCALE_AUTO, PlotFileView::OnScaleAuto)
 EVT_MENU(PLOTMENU_VIEW_SCALE_FULL, PlotFileView::OnScaleFull)
@@ -2741,7 +2879,7 @@ PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   m_pFileMenu->Append(wxID_CLOSE, "&Close\tCtrl-W");
   
   m_pFileMenu->AppendSeparator();
-  m_pFileMenu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
+  m_pFileMenu->Append(PLOTMENU_FILE_PROPERTIES, "P&roperties\tCtrl-I");
   
   m_pFileMenu->AppendSeparator();
   m_pFileMenu->Append(wxID_PRINT, "&Print...");
@@ -2749,6 +2887,7 @@ PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   m_pFileMenu->Append(wxID_PREVIEW, "Print Pre&view");
 #ifdef CTSIM_MDI
   m_pFileMenu->AppendSeparator();
+  m_pFileMenu->Append (MAINMENU_FILE_PREFERENCES, "Prefere&nces...");
   m_pFileMenu->Append(MAINMENU_FILE_EXIT, "E&xit");
 #endif
   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
@@ -2761,7 +2900,8 @@ PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   
   wxMenu *help_menu = new wxMenu;
   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
-  help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics\tCtrl-H");
+  help_menu->Append (MAINMENU_HELP_TIPS, "&Tips");
+  help_menu->Append (IDH_QUICKSTART, "&Quick Start");
   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
   
   wxMenuBar *menu_bar = new wxMenuBar;
@@ -2773,18 +2913,12 @@ PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   subframe->SetMenuBar(menu_bar);
   subframe->Centre(wxBOTH);
   
-  wxAcceleratorEntry accelEntries[10];
-  accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('O'), wxID_OPEN);
-  accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('S'), wxID_SAVE);
-  accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('W'), wxID_CLOSE);
-  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('H'), MAINMENU_HELP_TOPICS);
-  accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('P'), MAINMENU_FILE_CREATE_PHANTOM);
-  accelEntries[5].Set (wxACCEL_CTRL, static_cast<int>('F'), MAINMENU_FILE_CREATE_FILTER);
-  accelEntries[6].Set (wxACCEL_NORMAL, WXK_F1, MAINMENU_HELP_CONTENTS);
-  accelEntries[7].Set (wxACCEL_CTRL, static_cast<int>('E'), PLOTMENU_VIEW_SCALE_MINMAX);
-  accelEntries[8].Set (wxACCEL_CTRL, static_cast<int>('A'), PLOTMENU_VIEW_SCALE_AUTO);
-  accelEntries[9].Set (wxACCEL_CTRL, static_cast<int>('U'), PLOTMENU_VIEW_SCALE_FULL);
-  wxAcceleratorTable accelTable (10, accelEntries);
+  wxAcceleratorEntry accelEntries[4];
+  accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('E'), PLOTMENU_VIEW_SCALE_MINMAX);
+  accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('A'), PLOTMENU_VIEW_SCALE_AUTO);
+  accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('U'), PLOTMENU_VIEW_SCALE_FULL);
+  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('I'), PLOTMENU_FILE_PROPERTIES);
+  wxAcceleratorTable accelTable (4, accelEntries);
   subframe->SetAcceleratorTable (accelTable);
   
   return subframe;
@@ -2905,8 +3039,8 @@ PlotFileView::OnClose (bool deleteWindow)
     m_pFrame = NULL;
     if (GetDocument() && GetDocument()->getBadFileOpen())
       ::wxYield();  // wxWindows bug workaround
- }
-
 }
+  
   return true;
 }
 
@@ -2973,7 +3107,7 @@ TextFileView::OnClose (bool deleteWindow)
     if (GetDocument() && GetDocument()->getBadFileOpen())
       ::wxYield();  // wxWindows bug workaround
   }
-
+  
   return TRUE;
 }
 
@@ -2991,7 +3125,7 @@ TextFileView::CreateChildFrame (wxDocument *doc, wxView *view)
 #endif
   theApp->setIconForFrame (subframe);
   
- m_pFileMenu = new wxMenu;
 m_pFileMenu = new wxMenu;
   
   m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P");
   m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F");
@@ -3006,6 +3140,7 @@ TextFileView::CreateChildFrame (wxDocument *doc, wxView *view)
   m_pFileMenu->Append(wxID_PREVIEW, "Print Pre&view");
 #ifdef CTSIM_MDI
   m_pFileMenu->AppendSeparator();
+  m_pFileMenu->Append (MAINMENU_FILE_PREFERENCES, "Prefere&nces...");
   m_pFileMenu->Append(MAINMENU_FILE_EXIT, "E&xit");
 #endif
   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
@@ -3013,7 +3148,8 @@ TextFileView::CreateChildFrame (wxDocument *doc, wxView *view)
   
   wxMenu *help_menu = new wxMenu;
   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
-  help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics\tCtrl-H");
+  help_menu->Append (MAINMENU_HELP_TIPS, "&Tips");
+  help_menu->Append (IDH_QUICKSTART, "&Quick Start");
   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
   
   wxMenuBar *menu_bar = new wxMenuBar;
@@ -3024,15 +3160,6 @@ TextFileView::CreateChildFrame (wxDocument *doc, wxView *view)
   subframe->SetMenuBar(menu_bar);
   subframe->Centre(wxBOTH);
   
-  wxAcceleratorEntry accelEntries[5];
-  accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('O'), wxID_OPEN);
-  accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('S'), wxID_SAVE);
-  accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('W'), wxID_CLOSE);
-  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('H'), MAINMENU_HELP_TOPICS);
-  accelEntries[4].Set (wxACCEL_NORMAL, WXK_F1, MAINMENU_HELP_CONTENTS);
-  wxAcceleratorTable accelTable (5, accelEntries);
-  subframe->SetAcceleratorTable (accelTable);
-  
   return subframe;
 }