r582: no message
[ctsim.git] / src / views.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   Name:          view.cpp
5 **   Purpose:       View & Canvas routines for CTSim program
6 **   Programmer:    Kevin Rosenberg
7 **   Date Started:  July 2000
8 **
9 **  This is part of the CTSim program
10 **  Copyright (c) 1983-2001 Kevin Rosenberg
11 **
12 **  $Id: views.cpp,v 1.118 2001/02/25 10:52:55 kevin Exp $
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 #include "wx/wxprec.h"
29 #ifndef WX_PRECOMP
30 #include "wx/wx.h"
31 #endif
32
33 #if !wxUSE_DOC_VIEW_ARCHITECTURE
34 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h!
35 #endif
36
37 #include "wx/image.h"
38 #include "wx/progdlg.h"
39
40 #include "ct.h"
41 #include "ctsim.h"
42 #include "docs.h"
43 #include "views.h"
44 #include "dialogs.h"
45 #include "dlgprojections.h"
46 #include "dlgreconstruct.h"
47 #include "backprojectors.h"
48 #include "reconstruct.h"
49 #include "timer.h"
50 #include "threadrecon.h"
51
52 #if defined(MSVC) || HAVE_SSTREAM
53 #include <sstream>
54 #else
55 #include <sstream_subst>
56 #endif
57
58
59 // ImageFileCanvas
60
61 BEGIN_EVENT_TABLE(ImageFileCanvas, wxScrolledWindow)
62 EVT_MOUSE_EVENTS(ImageFileCanvas::OnMouseEvent)
63 EVT_CHAR(ImageFileCanvas::OnChar)
64 END_EVENT_TABLE()
65
66
67 ImageFileCanvas::ImageFileCanvas (ImageFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
68 : wxScrolledWindow(frame, -1, pos, size, style), m_pView(v), m_xCursor(-1), m_yCursor(-1)
69 {
70 }
71
72 ImageFileCanvas::~ImageFileCanvas()
73 {
74   m_pView = NULL;
75 }
76
77 void 
78 ImageFileCanvas::OnDraw(wxDC& dc)
79 {
80   if (m_pView)
81     m_pView->OnDraw(& dc);
82 }
83
84 void 
85 ImageFileCanvas::DrawRubberBandCursor (wxDC& dc, int x, int y)
86 {
87   const ImageFile& rIF = m_pView->GetDocument()->getImageFile();
88   int nx = rIF.nx();
89   int ny = rIF.ny();
90   
91   int yPt = ny - y - 1;
92   dc.SetLogicalFunction (wxINVERT);
93   dc.SetPen (*wxGREEN_PEN);
94   dc.DrawLine (0, yPt, nx, yPt);
95   dc.DrawLine (x, 0, x, ny);
96   dc.SetLogicalFunction (wxCOPY);
97 }
98
99 bool
100 ImageFileCanvas::GetCurrentCursor (int& x, int& y)
101 {
102   x = m_xCursor;
103   y = m_yCursor;
104   
105   if (m_xCursor >= 0 && m_yCursor >= 0)
106     return true;
107   else
108     return false;
109 }
110
111 void 
112 ImageFileCanvas::OnMouseEvent(wxMouseEvent& event)
113 {
114   if (! m_pView)
115     return;
116
117   
118   wxClientDC dc(this);
119   PrepareDC(dc);
120   
121   wxPoint pt(event.GetLogicalPosition(dc));
122   
123   const ImageFileDocument* pIFDoc = m_pView->GetDocument();
124   if (! pIFDoc)
125     return;
126   const ImageFile& rIF = pIFDoc->getImageFile();
127   ImageFileArrayConst v = rIF.getArray();
128   int nx = rIF.nx();
129   int ny = rIF.ny();
130   const int yPt = ny - 1 - pt.y;
131   if (event.RightIsDown()) {
132     if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {
133       std::ostringstream os;
134       os << "Image value (" << pt.x << "," << yPt << ") = " << v[pt.x][yPt];
135       if (rIF.isComplex()) {
136         double dImag = rIF.getImaginaryArray()[pt.x][yPt];
137         if (dImag < 0)
138           os << " - " << -dImag;
139         else
140           os << " + " << dImag;
141         os << "i\n";
142       } else
143         os << "\n";
144       *theApp->getLog() << os.str().c_str();
145     } else
146       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << yPt << ")\n";
147   }
148   else if (event.LeftIsDown() || event.LeftUp() || event.RightUp()) {
149     if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {
150       if (m_xCursor >= 0 && m_yCursor >= 0) {
151         DrawRubberBandCursor (dc, m_xCursor, m_yCursor);
152       }
153       DrawRubberBandCursor (dc, pt.x, yPt);
154       m_xCursor = pt.x;
155       m_yCursor = yPt;
156       wxMenu* pMenu = m_pView->getMenuAnalyze();
157       if (pMenu && ! pMenu->IsEnabled(IFMENU_PLOT_ROW)) {
158         pMenu->Enable (IFMENU_PLOT_ROW, true);
159         pMenu->Enable (IFMENU_PLOT_COL, true);
160         pMenu->Enable (IFMENU_COMPARE_ROW, true);
161         pMenu->Enable (IFMENU_COMPARE_COL, true);
162         pMenu->Enable (IFMENU_PLOT_FFT_ROW, true);
163         pMenu->Enable (IFMENU_PLOT_FFT_COL, true);
164       }
165     } else
166       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << yPt << ")\n";
167   }
168   if (event.LeftUp()) {
169     std::ostringstream os;
170     os << "Selected column " << pt.x << " , row " << yPt << "\n";
171     *theApp->getLog() << os.str().c_str();
172   }
173 }
174
175 void
176 ImageFileCanvas::OnChar (wxKeyEvent& event)
177 {
178   if (event.GetKeyCode() == WXK_ESCAPE) {
179     m_xCursor = -1;
180     m_yCursor = -1;
181     if (m_pView)
182       m_pView->OnUpdate (NULL);
183   } else
184     wxScrolledWindow::OnChar (event);
185 }
186
187 wxSize
188 ImageFileCanvas::GetBestSize() const
189 {
190   if (! m_pView)
191     return wxSize(0,0);
192   
193   const ImageFile& rIF = m_pView->GetDocument()->getImageFile();
194   return wxSize (rIF.nx(), rIF.ny());
195 }
196
197
198 // ImageFileView
199
200 IMPLEMENT_DYNAMIC_CLASS(ImageFileView, wxView)
201
202 BEGIN_EVENT_TABLE(ImageFileView, wxView)
203 EVT_MENU(IFMENU_FILE_EXPORT, ImageFileView::OnExport)
204 EVT_MENU(IFMENU_FILE_PROPERTIES, ImageFileView::OnProperties)
205 EVT_MENU(IFMENU_VIEW_SCALE_MINMAX, ImageFileView::OnScaleMinMax)
206 EVT_MENU(IFMENU_VIEW_SCALE_AUTO, ImageFileView::OnScaleAuto)
207 EVT_MENU(IFMENU_VIEW_SCALE_FULL, ImageFileView::OnScaleFull)
208 EVT_MENU(IFMENU_COMPARE_IMAGES, ImageFileView::OnCompare)
209 EVT_MENU(IFMENU_COMPARE_ROW, ImageFileView::OnCompareRow)
210 EVT_MENU(IFMENU_COMPARE_COL, ImageFileView::OnCompareCol)
211 EVT_MENU(IFMENU_FILTER_INVERTVALUES, ImageFileView::OnInvertValues)
212 EVT_MENU(IFMENU_FILTER_SQUARE, ImageFileView::OnSquare)
213 EVT_MENU(IFMENU_FILTER_SQRT, ImageFileView::OnSquareRoot)
214 EVT_MENU(IFMENU_FILTER_LOG, ImageFileView::OnLog)
215 EVT_MENU(IFMENU_FILTER_EXP, ImageFileView::OnExp)
216 EVT_MENU(IFMENU_FILTER_FOURIER, ImageFileView::OnFourier)
217 EVT_MENU(IFMENU_FILTER_INVERSE_FOURIER, ImageFileView::OnInverseFourier)
218 EVT_MENU(IFMENU_FILTER_SHUFFLEFOURIERTONATURALORDER, ImageFileView::OnShuffleFourierToNaturalOrder)
219 EVT_MENU(IFMENU_FILTER_SHUFFLENATURALTOFOURIERORDER, ImageFileView::OnShuffleNaturalToFourierOrder)
220 EVT_MENU(IFMENU_IMAGE_ADD, ImageFileView::OnAdd)
221 EVT_MENU(IFMENU_IMAGE_SUBTRACT, ImageFileView::OnSubtract)
222 EVT_MENU(IFMENU_IMAGE_MULTIPLY, ImageFileView::OnMultiply)
223 EVT_MENU(IFMENU_IMAGE_DIVIDE, ImageFileView::OnDivide)
224 EVT_MENU(IFMENU_IMAGE_SCALESIZE, ImageFileView::OnScaleSize)
225 #if wxUSE_GLCANVAS
226 EVT_MENU(IFMENU_IMAGE_CONVERT3D, ImageFileView::OnConvert3d)
227 #endif
228 #ifdef HAVE_FFT
229 EVT_MENU(IFMENU_FILTER_FFT, ImageFileView::OnFFT)
230 EVT_MENU(IFMENU_FILTER_IFFT, ImageFileView::OnIFFT)
231 EVT_MENU(IFMENU_FILTER_FFT_ROWS, ImageFileView::OnFFTRows)
232 EVT_MENU(IFMENU_FILTER_IFFT_ROWS, ImageFileView::OnIFFTRows)
233 EVT_MENU(IFMENU_FILTER_FFT_COLS, ImageFileView::OnFFTCols)
234 EVT_MENU(IFMENU_FILTER_IFFT_COLS, ImageFileView::OnIFFTCols)
235 #endif
236 EVT_MENU(IFMENU_FILTER_MAGNITUDE, ImageFileView::OnMagnitude)
237 EVT_MENU(IFMENU_FILTER_PHASE, ImageFileView::OnPhase)
238 EVT_MENU(IFMENU_PLOT_ROW, ImageFileView::OnPlotRow)
239 EVT_MENU(IFMENU_PLOT_COL, ImageFileView::OnPlotCol)
240 #ifdef HAVE_FFT
241 EVT_MENU(IFMENU_PLOT_FFT_ROW, ImageFileView::OnPlotFFTRow)
242 EVT_MENU(IFMENU_PLOT_FFT_COL, ImageFileView::OnPlotFFTCol)
243 #endif
244 EVT_MENU(IFMENU_PLOT_HISTOGRAM, ImageFileView::OnPlotHistogram)
245 END_EVENT_TABLE()
246
247 ImageFileView::ImageFileView() 
248 : wxView(), m_pFrame(NULL), m_pCanvas(NULL), m_pFileMenu(0), m_bMinSpecified(false), m_bMaxSpecified(false)
249 {
250   m_iDefaultExportFormatID = ImageFile::FORMAT_PNG;
251 }
252
253 ImageFileView::~ImageFileView()
254 {
255   GetDocumentManager()->FileHistoryRemoveMenu (m_pFileMenu);
256   GetDocumentManager()->ActivateView(this, FALSE, TRUE);
257 }
258
259
260 void
261 ImageFileView::OnProperties (wxCommandEvent& event)
262 {
263   const ImageFile& rIF = GetDocument()->getImageFile();
264   if (rIF.nx() == 0 || rIF.ny() == 0)
265     *theApp->getLog() << "Properties: empty imagefile\n";
266   else {
267     const std::string rFilename = m_pFrame->GetTitle().c_str();
268     std::ostringstream os;
269     double min, max, mean, mode, median, stddev;
270     rIF.statistics (rIF.getArray(), min, max, mean, mode, median, stddev);
271     os << "Filename: " << rFilename << "\n";
272     os << "Size: (" << rIF.nx() << "," << rIF.ny() << ")\n";
273     os << "Data type: ";
274     if (rIF.isComplex())
275       os << "Complex\n";
276     else
277       os << "Real\n";
278     os << "Minimum: "<<min<<"\nMaximum: "<<max<<"\nMean: "<<mean<<"\nMedian: "<<median<<"\nMode: "<<mode<<"\nStandard Deviation: "<<stddev << "\n";
279     if (rIF.isComplex()) {
280       rIF.statistics (rIF.getImaginaryArray(), min, max, mean, mode, median, stddev);
281       os << "Imaginary: min: "<<min<<"\nmax: "<<max<<"\nmean: "<<mean<<"\nmedian: "<<median<<"\nmode: "<<mode<<"\nstddev: "<<stddev << "\n";
282     }
283     if (rIF.nLabels() > 0) {
284       rIF.printLabelsBrief (os);
285     }
286     *theApp->getLog() << ">>>>\n" << os.str().c_str() << "<<<<\n";
287     wxMessageDialog dialogMsg (getFrameForChild(), os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION);
288     dialogMsg.ShowModal();
289   }
290 }
291
292 void 
293 ImageFileView::OnScaleAuto (wxCommandEvent& event)
294 {
295   const ImageFile& rIF = GetDocument()->getImageFile();
296   double min, max, mean, mode, median, stddev;
297   rIF.statistics(min, max, mean, mode, median, stddev);
298   DialogAutoScaleParameters dialogAutoScale (getFrameForChild(), mean, mode, median, stddev, m_dAutoScaleFactor);
299   int iRetVal = dialogAutoScale.ShowModal();
300   if (iRetVal == wxID_OK) {
301     m_bMinSpecified = true;
302     m_bMaxSpecified = true;
303     double dMin, dMax;
304     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {
305       m_dMinPixel = dMin;
306       m_dMaxPixel = dMax;
307       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
308       OnUpdate (this, NULL);
309     }
310   }
311 }
312
313 void 
314 ImageFileView::OnScaleMinMax (wxCommandEvent& event)
315 {
316   const ImageFile& rIF = GetDocument()->getImageFile();
317   double min, max;
318   if (! m_bMinSpecified && ! m_bMaxSpecified)
319     rIF.getMinMax (min, max);
320   
321   if (m_bMinSpecified)
322     min = m_dMinPixel;
323   if (m_bMaxSpecified)
324     max = m_dMaxPixel;
325   
326   DialogGetMinMax dialogMinMax (getFrameForChild(), "Set Image Minimum & Maximum", min, max);
327   int retVal = dialogMinMax.ShowModal();
328   if (retVal == wxID_OK) {
329     m_bMinSpecified = true;
330     m_bMaxSpecified = true;
331     m_dMinPixel = dialogMinMax.getMinimum();
332     m_dMaxPixel = dialogMinMax.getMaximum();
333     OnUpdate (this, NULL);
334   }
335 }
336
337 void 
338 ImageFileView::OnScaleFull (wxCommandEvent& event)
339 {
340   if (m_bMinSpecified || m_bMaxSpecified) {
341     m_bMinSpecified = false;
342     m_bMaxSpecified = false;
343     OnUpdate (this, NULL);
344   }
345 }
346
347 void
348 ImageFileView::OnCompare (wxCommandEvent& event)
349 {
350   std::vector<ImageFileDocument*> vecIF;
351   theApp->getCompatibleImages (GetDocument(), vecIF);
352   
353   if (vecIF.size() == 0) {
354     wxMessageBox("There are no compatible image files open for comparision", "No comparison images");
355   } else {
356     DialogGetComparisonImage dialogGetCompare(getFrameForChild(), "Get Comparison Image", vecIF, true);
357     
358     if (dialogGetCompare.ShowModal() == wxID_OK) {
359       const ImageFile& rIF = GetDocument()->getImageFile();
360       ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();
361       const ImageFile& rCompareIF = pCompareDoc->getImageFile();
362       std::ostringstream os;
363       double min, max, mean, mode, median, stddev;
364       rIF.statistics (min, max, mean, mode, median, stddev);
365       os << GetFrame()->GetTitle().c_str() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";
366       rCompareIF.statistics (min, max, mean, mode, median, stddev);
367       os << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";
368       double d, r, e;
369       rIF.comparativeStatistics (rCompareIF, d, r, e);
370       os << "Comparative Statistics: d=" << d << ", r=" << r << ", e=" << e << "\n";
371       *theApp->getLog() << ">>>>\n" << os.str().c_str() << "<<<<\n";
372       if (dialogGetCompare.getMakeDifferenceImage()) {
373         ImageFile* pDifferenceImage = new ImageFile;
374         
375         pDifferenceImage->setArraySize (rIF.nx(), rIF.ny());
376         if (! rIF.subtractImages (rCompareIF, *pDifferenceImage)) {
377           *theApp->getLog() << "Unable to subtract images\n";
378           delete pDifferenceImage;
379           return;
380         }
381         ImageFileDocument* pDifferenceDoc = theApp->newImageDoc();
382         if (! pDifferenceDoc) {
383           sys_error (ERR_SEVERE, "Unable to create image file");
384           return;
385         }
386         pDifferenceDoc->setImageFile (pDifferenceImage);
387         
388         wxString s = GetFrame()->GetTitle() + ": ";
389         pDifferenceImage->labelsCopy (rIF, s.c_str());
390         s = pCompareDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";
391         pDifferenceImage->labelsCopy (rCompareIF, s.c_str());
392         std::ostringstream osLabel;
393         osLabel << "Compare image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() 
394           << " and " << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str() << ": "
395           << os.str().c_str();
396         pDifferenceImage->labelAdd (os.str().c_str());
397         if (theApp->getAskDeleteNewDocs())
398           pDifferenceDoc->Modify (true);
399         pDifferenceDoc->UpdateAllViews (this);
400         pDifferenceDoc->getView()->OnUpdate (this, NULL);
401         pDifferenceDoc->getView()->getFrame()->Show(true);
402       }
403       wxMessageBox(os.str().c_str(), "Image Comparison");
404     }
405   }
406 }
407
408 void
409 ImageFileView::OnInvertValues (wxCommandEvent& event)
410 {
411   ImageFile& rIF = GetDocument()->getImageFile();
412   rIF.invertPixelValues (rIF);
413   rIF.labelAdd ("Invert Pixel Values");
414   if (theApp->getAskDeleteNewDocs())
415     GetDocument()->Modify (true);
416   GetDocument()->UpdateAllViews (this);
417 }
418
419 void
420 ImageFileView::OnSquare (wxCommandEvent& event)
421 {
422   ImageFile& rIF = GetDocument()->getImageFile();
423   rIF.square (rIF);
424   rIF.labelAdd ("Square Pixel Values");
425   if (theApp->getAskDeleteNewDocs())
426     GetDocument()->Modify (true);
427   GetDocument()->UpdateAllViews (this);
428 }
429
430 void
431 ImageFileView::OnSquareRoot (wxCommandEvent& event)
432 {
433   ImageFile& rIF = GetDocument()->getImageFile();
434   rIF.sqrt (rIF);
435   rIF.labelAdd ("Square-root Pixel Values");
436   if (theApp->getAskDeleteNewDocs())
437     GetDocument()->Modify (true);
438   GetDocument()->UpdateAllViews (this);
439 }
440
441 void
442 ImageFileView::OnLog (wxCommandEvent& event)
443 {
444   ImageFile& rIF = GetDocument()->getImageFile();
445   rIF.log (rIF);
446   rIF.labelAdd ("Logrithm base-e Pixel Values");
447   if (theApp->getAskDeleteNewDocs())
448     GetDocument()->Modify (true);
449   GetDocument()->UpdateAllViews (this);
450 }
451
452 void
453 ImageFileView::OnExp (wxCommandEvent& event)
454 {
455   ImageFile& rIF = GetDocument()->getImageFile();
456   rIF.exp (rIF);
457   rIF.labelAdd ("Exponent base-e Pixel Values");
458   if (theApp->getAskDeleteNewDocs())
459     GetDocument()->Modify (true);
460   GetDocument()->UpdateAllViews (this);
461 }
462
463 void
464 ImageFileView::OnAdd (wxCommandEvent& event)
465 {
466   std::vector<ImageFileDocument*> vecIF;
467   theApp->getCompatibleImages (GetDocument(), vecIF);
468   
469   if (vecIF.size() == 0) {
470     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");
471   } else {
472     DialogGetComparisonImage dialogGetCompare (getFrameForChild(), "Get Image to Add", vecIF, false);
473     
474     if (dialogGetCompare.ShowModal() == wxID_OK) {
475       ImageFile& rIF = GetDocument()->getImageFile();
476       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();
477       const ImageFile& rRHSIF = pRHSDoc->getImageFile();
478       ImageFileDocument* pNewDoc = theApp->newImageDoc();
479       if (! pNewDoc) {
480         sys_error (ERR_SEVERE, "Unable to create image file");
481         return;
482       }
483       ImageFile& newImage = pNewDoc->getImageFile();  
484       newImage.setArraySize (rIF.nx(), rIF.ny());
485       rIF.addImages (rRHSIF, newImage);
486       std::ostringstream os;
487       os << "Add image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and " 
488         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
489       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";
490       newImage.labelsCopy (rIF, s.c_str());
491       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";
492       newImage.labelsCopy (rRHSIF, s.c_str());
493       newImage.labelAdd (os.str().c_str());
494       *theApp->getLog() << os.str().c_str() << "\n";
495       if (theApp->getAskDeleteNewDocs())
496         pNewDoc->Modify (true);
497       pNewDoc->UpdateAllViews (this);
498       pNewDoc->getView()->OnUpdate (this, NULL);
499       pNewDoc->getView()->getFrame()->Show(true);
500     }
501   }
502 }
503
504 void
505 ImageFileView::OnSubtract (wxCommandEvent& event)
506 {
507   std::vector<ImageFileDocument*> vecIF;
508   theApp->getCompatibleImages (GetDocument(), vecIF);
509   
510   if (vecIF.size() == 0) {
511     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");
512   } else {
513     DialogGetComparisonImage dialogGetCompare (getFrameForChild(), "Get Image to Subtract", vecIF, false);
514     
515     if (dialogGetCompare.ShowModal() == wxID_OK) {
516       ImageFile& rIF = GetDocument()->getImageFile();
517       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();
518       const ImageFile& rRHSIF = pRHSDoc->getImageFile();
519       ImageFileDocument* pNewDoc = theApp->newImageDoc();
520       if (! pNewDoc) {
521         sys_error (ERR_SEVERE, "Unable to create image file");
522         return;
523       }
524       ImageFile& newImage = pNewDoc->getImageFile();  
525       newImage.setArraySize (rIF.nx(), rIF.ny());
526       rIF.subtractImages (rRHSIF, newImage);
527       std::ostringstream os;
528       os << "Subtract image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and " 
529         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
530       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";
531       newImage.labelsCopy (rIF, s.c_str());
532       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";
533       newImage.labelsCopy (rRHSIF, s.c_str());
534       newImage.labelAdd (os.str().c_str());
535       *theApp->getLog() << os.str().c_str() << "\n";
536       if (theApp->getAskDeleteNewDocs())
537         pNewDoc->Modify (true);
538       pNewDoc->UpdateAllViews (this);
539       pNewDoc->getView()->OnUpdate (this, NULL);
540       pNewDoc->getView()->getFrame()->Show(true);
541     }
542   }
543 }
544
545 void
546 ImageFileView::OnMultiply (wxCommandEvent& event)
547 {
548   std::vector<ImageFileDocument*> vecIF;
549   theApp->getCompatibleImages (GetDocument(), vecIF);
550   
551   if (vecIF.size() == 0) {
552     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");
553   } else {
554     DialogGetComparisonImage dialogGetCompare (getFrameForChild(), "Get Image to Multiply", vecIF, false);
555     
556     if (dialogGetCompare.ShowModal() == wxID_OK) {
557       ImageFile& rIF = GetDocument()->getImageFile();
558       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();
559       const ImageFile& rRHSIF = pRHSDoc->getImageFile();
560       ImageFileDocument* pNewDoc = theApp->newImageDoc();
561       if (! pNewDoc) {
562         sys_error (ERR_SEVERE, "Unable to create image file");
563         return;
564       }
565       ImageFile& newImage = pNewDoc->getImageFile();  
566       newImage.setArraySize (rIF.nx(), rIF.ny());
567       rIF.multiplyImages (rRHSIF, newImage);
568       std::ostringstream os;
569       os << "Multiply image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and " 
570         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
571       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";
572       newImage.labelsCopy (rIF, s.c_str());
573       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";
574       newImage.labelsCopy (rRHSIF, s.c_str());
575       newImage.labelAdd (os.str().c_str());
576       *theApp->getLog() << os.str().c_str() << "\n";
577       if (theApp->getAskDeleteNewDocs())
578         pNewDoc->Modify (true);
579       pNewDoc->UpdateAllViews (this);
580       pNewDoc->getView()->OnUpdate (this, NULL);
581       pNewDoc->getView()->getFrame()->Show(true);
582     }
583   }
584 }
585
586 void
587 ImageFileView::OnDivide (wxCommandEvent& event)
588 {
589   std::vector<ImageFileDocument*> vecIF;
590   theApp->getCompatibleImages (GetDocument(), vecIF);
591   
592   if (vecIF.size() == 0) {
593     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");
594   } else {
595     DialogGetComparisonImage dialogGetCompare (getFrameForChild(), "Get Image to Divide", vecIF, false);
596     
597     if (dialogGetCompare.ShowModal() == wxID_OK) {
598       ImageFile& rIF = GetDocument()->getImageFile();
599       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();
600       const ImageFile& rRHSIF = pRHSDoc->getImageFile();
601       ImageFileDocument* pNewDoc = theApp->newImageDoc();
602       if (! pNewDoc) {
603         sys_error (ERR_SEVERE, "Unable to create image file");
604         return;
605       }
606       ImageFile& newImage = pNewDoc->getImageFile();  
607       newImage.setArraySize (rIF.nx(), rIF.ny());
608       rIF.divideImages (rRHSIF, newImage);
609       std::ostringstream os;
610       os << "Divide image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " by " 
611         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
612       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";
613       newImage.labelsCopy (rIF, s.c_str());
614       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";
615       newImage.labelsCopy (rRHSIF, s.c_str());
616       newImage.labelAdd (os.str().c_str());
617       *theApp->getLog() << os.str().c_str() << "\n";
618       if (theApp->getAskDeleteNewDocs())
619         pNewDoc->Modify (true);
620       pNewDoc->UpdateAllViews (this);
621       pNewDoc->getView()->OnUpdate (this, NULL);
622       pNewDoc->getView()->getFrame()->Show(true);
623     }
624   }
625 }
626
627
628 #ifdef HAVE_FFT
629 void
630 ImageFileView::OnFFT (wxCommandEvent& event)
631 {
632   ImageFile& rIF = GetDocument()->getImageFile();
633   rIF.fft (rIF);
634   rIF.labelAdd ("FFT Image");
635   m_bMinSpecified = false;
636   m_bMaxSpecified = false;
637   if (theApp->getAskDeleteNewDocs())
638     GetDocument()->Modify (true);
639   GetDocument()->UpdateAllViews (this);
640 }
641
642 void
643 ImageFileView::OnIFFT (wxCommandEvent& event)
644 {
645   ImageFile& rIF = GetDocument()->getImageFile();
646   rIF.ifft (rIF);
647   rIF.labelAdd ("IFFT Image");
648   m_bMinSpecified = false;
649   m_bMaxSpecified = false;
650   if (theApp->getAskDeleteNewDocs())
651     GetDocument()->Modify (true);
652   GetDocument()->UpdateAllViews (this);
653 }
654
655 void
656 ImageFileView::OnFFTRows (wxCommandEvent& event)
657 {
658   ImageFile& rIF = GetDocument()->getImageFile();
659   rIF.fftRows (rIF);
660   rIF.labelAdd ("FFT Rows");
661   m_bMinSpecified = false;
662   m_bMaxSpecified = false;
663   if (theApp->getAskDeleteNewDocs())
664     GetDocument()->Modify (true);
665   GetDocument()->UpdateAllViews (this);
666 }
667
668 void
669 ImageFileView::OnIFFTRows (wxCommandEvent& event)
670 {
671   ImageFile& rIF = GetDocument()->getImageFile();
672   rIF.ifftRows (rIF);
673   rIF.labelAdd ("IFFT Rows");
674   m_bMinSpecified = false;
675   m_bMaxSpecified = false;
676   if (theApp->getAskDeleteNewDocs())
677     GetDocument()->Modify (true);
678   GetDocument()->UpdateAllViews (this);
679 }
680
681 void
682 ImageFileView::OnFFTCols (wxCommandEvent& event)
683 {
684   ImageFile& rIF = GetDocument()->getImageFile();
685   rIF.fftCols (rIF);
686   rIF.labelAdd ("FFT Columns");
687   m_bMinSpecified = false;
688   m_bMaxSpecified = false;
689   if (theApp->getAskDeleteNewDocs())
690     GetDocument()->Modify (true);
691   GetDocument()->UpdateAllViews (this);
692 }
693
694 void
695 ImageFileView::OnIFFTCols (wxCommandEvent& event)
696 {
697   ImageFile& rIF = GetDocument()->getImageFile();
698   rIF.ifftCols (rIF);
699   rIF.labelAdd ("IFFT Columns");
700   m_bMinSpecified = false;
701   m_bMaxSpecified = false;
702   if (theApp->getAskDeleteNewDocs())
703     GetDocument()->Modify (true);
704   GetDocument()->UpdateAllViews (this);
705 }
706 #endif
707
708 void
709 ImageFileView::OnFourier (wxCommandEvent& event)
710 {
711   ImageFile& rIF = GetDocument()->getImageFile();
712   wxProgressDialog dlgProgress (wxString("Fourier"), wxString("Fourier Progress"), 1, getFrameForChild(), wxPD_APP_MODAL);
713   rIF.fourier (rIF);
714   rIF.labelAdd ("Fourier Image");
715   m_bMinSpecified = false;
716   m_bMaxSpecified = false;
717   if (theApp->getAskDeleteNewDocs())
718     GetDocument()->Modify (true);
719   GetDocument()->UpdateAllViews (this);
720 }
721
722 void
723 ImageFileView::OnInverseFourier (wxCommandEvent& event)
724 {
725   ImageFile& rIF = GetDocument()->getImageFile();
726   wxProgressDialog dlgProgress (wxString("Inverse Fourier"), wxString("Inverse Fourier Progress"), 1, getFrameForChild(), wxPD_APP_MODAL);
727   rIF.inverseFourier (rIF);
728   rIF.labelAdd ("Inverse Fourier Image");
729   m_bMinSpecified = false;
730   m_bMaxSpecified = false;
731   if (theApp->getAskDeleteNewDocs())
732     GetDocument()->Modify (true);
733   GetDocument()->UpdateAllViews (this);
734 }
735
736 void
737 ImageFileView::OnShuffleNaturalToFourierOrder (wxCommandEvent& event)
738 {
739   ImageFile& rIF = GetDocument()->getImageFile();
740   Fourier::shuffleNaturalToFourierOrder (rIF);
741   rIF.labelAdd ("Shuffle Natural To Fourier Order");
742   m_bMinSpecified = false;
743   m_bMaxSpecified = false;
744   if (theApp->getAskDeleteNewDocs())
745     GetDocument()->Modify (true);
746   GetDocument()->UpdateAllViews (this);
747 }
748
749 void
750 ImageFileView::OnShuffleFourierToNaturalOrder (wxCommandEvent& event)
751 {
752   ImageFile& rIF = GetDocument()->getImageFile();
753   Fourier::shuffleFourierToNaturalOrder (rIF);
754   rIF.labelAdd ("Shuffle Fourier To Natural Order");
755   m_bMinSpecified = false;
756   m_bMaxSpecified = false;
757   if (theApp->getAskDeleteNewDocs())
758     GetDocument()->Modify (true);
759   GetDocument()->UpdateAllViews (this);
760 }
761
762 void
763 ImageFileView::OnMagnitude (wxCommandEvent& event)
764 {
765   ImageFile& rIF = GetDocument()->getImageFile();
766   if (rIF.isComplex()) {
767     rIF.magnitude (rIF);
768     rIF.labelAdd ("Magnitude of complex-image");
769     m_bMinSpecified = false;
770     m_bMaxSpecified = false;
771     if (theApp->getAskDeleteNewDocs())
772       GetDocument()->Modify (true);
773     GetDocument()->UpdateAllViews (this);
774   }
775 }
776
777 void
778 ImageFileView::OnPhase (wxCommandEvent& event)
779 {
780   ImageFile& rIF = GetDocument()->getImageFile();
781   if (rIF.isComplex()) {
782     rIF.phase (rIF);
783     rIF.labelAdd ("Phase of complex-image");
784     m_bMinSpecified = false;
785     m_bMaxSpecified = false;
786     if (theApp->getAskDeleteNewDocs())
787       GetDocument()->Modify (true);
788     GetDocument()->UpdateAllViews (this);
789   }
790 }
791
792
793 ImageFileCanvas* 
794 ImageFileView::CreateCanvas (wxFrame* parent)
795 {
796   ImageFileCanvas* pCanvas;
797   int width, height;
798   parent->GetClientSize(&width, &height);
799   
800   pCanvas = new ImageFileCanvas (this, parent, wxPoint(0, 0), wxSize(width, height), 0);
801   
802   pCanvas->SetScrollbars(20, 20, 50, 50);
803   pCanvas->SetBackgroundColour(*wxWHITE);
804   pCanvas->Clear();
805   
806   return pCanvas;
807 }
808
809 #if CTSIM_MDI
810 wxDocMDIChildFrame*
811 #else
812 wxDocChildFrame*
813 #endif
814 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
815 {
816 #if CTSIM_MDI
817   wxDocMDIChildFrame* subframe = new wxDocMDIChildFrame (doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
818 #else
819   wxDocChildFrame* subframe = new wxDocChildFrame (doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
820 #endif
821   theApp->setIconForFrame (subframe);
822   
823   m_pFileMenu = new wxMenu;
824   
825   m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P");
826   m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F");
827   m_pFileMenu->Append(wxID_OPEN, "&Open...\tCtrl-O");
828   m_pFileMenu->Append(wxID_SAVE, "&Save\tCtrl-S");
829   m_pFileMenu->Append(wxID_SAVEAS, "Save &As...");
830   m_pFileMenu->Append(wxID_CLOSE, "&Close\tCtrl-W");
831   m_pFileMenu->Append(wxID_REVERT, "Re&vert");
832   
833   m_pFileMenu->AppendSeparator();
834   m_pFileMenu->Append(IFMENU_FILE_PROPERTIES, "P&roperties\tCtrl-I");
835   m_pFileMenu->Append(IFMENU_FILE_EXPORT, "&Export...");
836   
837   m_pFileMenu->AppendSeparator();
838   m_pFileMenu->Append(wxID_PRINT, "&Print...");
839   m_pFileMenu->Append(wxID_PRINT_SETUP, "Print &Setup...");
840   m_pFileMenu->Append(wxID_PREVIEW, "Print Preview");
841 #ifdef CTSIM_MDI
842   m_pFileMenu->AppendSeparator();
843   m_pFileMenu->Append (MAINMENU_FILE_PREFERENCES, "Prefere&nces...");
844   m_pFileMenu->Append(MAINMENU_FILE_EXIT, "E&xit");
845 #endif
846   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
847   GetDocumentManager()->FileHistoryUseMenu(m_pFileMenu);
848   
849   wxMenu *view_menu = new wxMenu;
850   view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale S&et...\tCtrl-E");
851   view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...\tCtrl-A");
852   view_menu->Append(IFMENU_VIEW_SCALE_FULL, "Display F&ull Scale\tCtrl-U");
853   
854   wxMenu* filter_menu = new wxMenu;
855   filter_menu->Append (IFMENU_FILTER_INVERTVALUES, "&Invert Values");
856   filter_menu->Append (IFMENU_FILTER_SQUARE, "&Square");
857   filter_menu->Append (IFMENU_FILTER_SQRT, "Square &Root");
858   filter_menu->Append (IFMENU_FILTER_LOG, "&Log");
859   filter_menu->Append (IFMENU_FILTER_EXP, "&Exp");
860   filter_menu->AppendSeparator();
861 #ifdef HAVE_FFT
862   filter_menu->Append (IFMENU_FILTER_FFT, "2-D &FFT");
863   filter_menu->Append (IFMENU_FILTER_IFFT, "2-D &IFFT");
864   filter_menu->Append (IFMENU_FILTER_FFT_ROWS, "FFT Rows");
865   filter_menu->Append (IFMENU_FILTER_IFFT_ROWS, "IFFT Rows");
866   filter_menu->Append (IFMENU_FILTER_FFT_COLS, "FFT Columns");
867   filter_menu->Append (IFMENU_FILTER_IFFT_COLS, "IFFT Columns");
868   filter_menu->Append (IFMENU_FILTER_FOURIER, "2-D F&ourier");
869   filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "2-D Inverse Fo&urier");
870 #else
871   filter_menu->Append (IFMENU_FILTER_FOURIER, "&Fourier");
872   filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "&Inverse Fourier");
873 #endif
874   filter_menu->Append (IFMENU_FILTER_SHUFFLEFOURIERTONATURALORDER, "S&huffle Fourier to Natural Order");
875   filter_menu->Append (IFMENU_FILTER_SHUFFLENATURALTOFOURIERORDER, "Shu&ffle Natural to Fourier Order");
876   filter_menu->Append (IFMENU_FILTER_MAGNITUDE, "&Magnitude");
877   filter_menu->Append (IFMENU_FILTER_PHASE, "&Phase");
878   
879   wxMenu* image_menu = new wxMenu;
880   image_menu->Append (IFMENU_IMAGE_ADD, "&Add...");
881   image_menu->Append (IFMENU_IMAGE_SUBTRACT, "&Subtract...");
882   image_menu->Append (IFMENU_IMAGE_MULTIPLY, "&Multiply...");
883   image_menu->Append (IFMENU_IMAGE_DIVIDE, "&Divide...");
884   image_menu->AppendSeparator();
885   image_menu->Append (IFMENU_IMAGE_SCALESIZE, "S&cale Size...");
886 #if wxUSE_GLCANVAS
887   image_menu->Append (IFMENU_IMAGE_CONVERT3D, "Convert &3-D\tCtrl-3");
888 #endif
889   
890   m_pMenuAnalyze = new wxMenu;
891   m_pMenuAnalyze->Append (IFMENU_PLOT_ROW, "Plot &Row");
892   m_pMenuAnalyze->Append (IFMENU_PLOT_COL, "Plot &Column");
893   m_pMenuAnalyze->Append (IFMENU_PLOT_HISTOGRAM, "Plot &Histogram");
894   m_pMenuAnalyze->AppendSeparator();
895   m_pMenuAnalyze->Append (IFMENU_PLOT_FFT_ROW, "Plot FFT Row");
896   m_pMenuAnalyze->Append (IFMENU_PLOT_FFT_COL, "Plot FFT Column");
897   m_pMenuAnalyze->AppendSeparator();
898   m_pMenuAnalyze->Append (IFMENU_COMPARE_IMAGES, "Compare &Images...");
899   m_pMenuAnalyze->Append (IFMENU_COMPARE_ROW, "Compare &Row");
900   m_pMenuAnalyze->Append (IFMENU_COMPARE_COL, "Compare &Column");
901   m_pMenuAnalyze->Enable (IFMENU_PLOT_ROW, false);
902   m_pMenuAnalyze->Enable (IFMENU_PLOT_COL, false);
903   m_pMenuAnalyze->Enable (IFMENU_COMPARE_ROW, false);
904   m_pMenuAnalyze->Enable (IFMENU_COMPARE_COL, false);
905   m_pMenuAnalyze->Enable (IFMENU_PLOT_FFT_ROW, false);
906   m_pMenuAnalyze->Enable (IFMENU_PLOT_FFT_COL, false);
907   
908   wxMenu *help_menu = new wxMenu;
909   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
910   help_menu->Append (MAINMENU_HELP_TIPS, "&Tips");
911   help_menu->Append (IDH_QUICKSTART, "&Quick Start");
912   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
913   
914   wxMenuBar *menu_bar = new wxMenuBar;
915   
916   menu_bar->Append(m_pFileMenu, "&File");
917   menu_bar->Append(view_menu, "&View");
918   menu_bar->Append(image_menu, "&Image");
919   menu_bar->Append(filter_menu, "Fi&lter");
920   menu_bar->Append(m_pMenuAnalyze, "&Analyze");
921   menu_bar->Append(help_menu, "&Help");
922   
923   subframe->SetMenuBar(menu_bar);
924   
925   subframe->Centre(wxBOTH);
926   
927   wxAcceleratorEntry accelEntries[5];
928   accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('A'), IFMENU_VIEW_SCALE_AUTO);
929   accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('U'), IFMENU_VIEW_SCALE_FULL);
930   accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('E'), IFMENU_VIEW_SCALE_MINMAX);
931   accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('I'), IFMENU_FILE_PROPERTIES);
932 #if wxUSE_GLCANVAS
933   accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('3'), IFMENU_IMAGE_CONVERT3D);
934   wxAcceleratorTable accelTable (5, accelEntries);
935 #else
936   wxAcceleratorTable accelTable (4, accelEntries);
937 #endif
938   
939   subframe->SetAcceleratorTable (accelTable);
940   
941   return subframe;
942 }
943
944
945 bool 
946 ImageFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
947 {
948   m_pFrame = CreateChildFrame(doc, this);
949   
950   m_bMinSpecified = false;
951   m_bMaxSpecified = false;
952   m_dAutoScaleFactor = 1.;
953   
954   int width, height;
955   m_pFrame->GetClientSize (&width, &height);
956   m_pFrame->SetTitle("ImageFileView");
957   m_pCanvas = CreateCanvas (m_pFrame);
958   
959   int x, y;  // X requires a forced resize
960   m_pFrame->GetSize(&x, &y);
961   m_pFrame->SetSize(-1, -1, x, y);
962   m_pFrame->SetFocus();
963   m_pFrame->Show(true);
964   Activate(true);
965   
966   return true;
967 }
968
969 void 
970 ImageFileView::OnDraw (wxDC* dc)
971 {
972   wxSize sizeWindow = m_pFrame->GetClientSize();
973   wxSize sizeBest = m_pCanvas->GetBestSize();
974   if (sizeWindow.x > sizeBest.x || sizeWindow.y > sizeBest.y)
975     m_pFrame->SetClientSize (sizeBest);
976   
977   if (m_bitmap.Ok())
978     dc->DrawBitmap(m_bitmap, 0, 0, false);
979   
980   int xCursor, yCursor;
981   if (m_pCanvas->GetCurrentCursor (xCursor, yCursor))
982     m_pCanvas->DrawRubberBandCursor (*dc, xCursor, yCursor);
983 }
984
985
986 void 
987 ImageFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
988 {
989   const ImageFile& rIF = GetDocument()->getImageFile();
990   ImageFileArrayConst v = rIF.getArray();
991   int nx = rIF.nx();
992   int ny = rIF.ny();
993   if (v != NULL && nx != 0 && ny != 0) {
994     if (! m_bMinSpecified || ! m_bMaxSpecified) {
995       double min, max;
996       rIF.getMinMax (min, max);
997       if (! m_bMinSpecified)
998         m_dMinPixel = min;
999       if (! m_bMaxSpecified)
1000         m_dMaxPixel = max;
1001     }
1002     double scaleWidth = m_dMaxPixel - m_dMinPixel;
1003     
1004     unsigned char* imageData = new unsigned char [nx * ny * 3];
1005     if (! imageData) {
1006       sys_error (ERR_SEVERE, "Unable to allocate memory for Image display");
1007       return;
1008     }
1009     for (int ix = 0; ix < nx; ix++) {
1010       for (int iy = 0; iy < ny; iy++) {
1011         double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
1012         int intensity = static_cast<int>(scaleValue + 0.5);
1013         intensity = clamp (intensity, 0, 255);
1014         int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
1015         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
1016       }
1017     }
1018     wxImage image (nx, ny, imageData, true);
1019     m_bitmap = image.ConvertToBitmap();
1020     delete imageData;
1021     int xSize = nx;
1022     int ySize = ny;
1023     ySize = clamp (ySize, 0, 800);
1024     m_pFrame->SetClientSize (xSize, ySize);
1025     m_pCanvas->SetScrollbars(20, 20, nx/20, ny/20);
1026     m_pCanvas->SetBackgroundColour(*wxWHITE);
1027   } 
1028   
1029   if (m_pCanvas)
1030     m_pCanvas->Refresh();
1031 }
1032
1033 bool 
1034 ImageFileView::OnClose (bool deleteWindow)
1035 {
1036   //GetDocumentManager()->ActivateView (this, false, true);
1037   if (! GetDocument() || ! GetDocument()->Close())
1038     return false;
1039   
1040   Activate (false);
1041   if (m_pCanvas) {
1042     m_pCanvas->setView(NULL);
1043     m_pCanvas = NULL;
1044   }
1045   wxString s(theApp->GetAppName());
1046   if (m_pFrame)
1047     m_pFrame->SetTitle(s);
1048   
1049   SetFrame(NULL);
1050   
1051   if (deleteWindow) {
1052     delete m_pFrame;
1053     m_pFrame = NULL;
1054     if (GetDocument() && GetDocument()->getBadFileOpen())
1055       ::wxYield();  // wxWindows bug workaround
1056   }
1057   
1058   return true;
1059 }
1060
1061 void
1062 ImageFileView::OnExport (wxCommandEvent& event)
1063 {
1064   ImageFile& rIF = GetDocument()->getImageFile();
1065   ImageFileArrayConst v = rIF.getArray();
1066   int nx = rIF.nx();
1067   int ny = rIF.ny();
1068   if (v != NULL && nx != 0 && ny != 0) {
1069     if (! m_bMinSpecified || ! m_bMaxSpecified) {
1070       double min, max;
1071       rIF.getMinMax (min, max);
1072       if (! m_bMinSpecified)
1073         m_dMinPixel = min;
1074       if (! m_bMaxSpecified)
1075         m_dMaxPixel = max;
1076     }
1077     
1078     DialogExportParameters dialogExport (getFrameForChild(), m_iDefaultExportFormatID);
1079     if (dialogExport.ShowModal() == wxID_OK) {
1080       wxString strFormatName (dialogExport.getFormatName ());
1081       m_iDefaultExportFormatID = ImageFile::convertFormatNameToID (strFormatName.c_str());
1082       
1083       wxString strExt;
1084       wxString strWildcard;
1085       if (m_iDefaultExportFormatID == ImageFile::FORMAT_PGM || m_iDefaultExportFormatID == ImageFile::FORMAT_PGMASCII) {
1086         strExt = ".pgm";
1087         strWildcard = "PGM Files (*.pgm)|*.pgm";
1088       }
1089 #ifdef HAVE_PNG
1090       else if (m_iDefaultExportFormatID == ImageFile::FORMAT_PNG || m_iDefaultExportFormatID == ImageFile::FORMAT_PNG16) {
1091         strExt = ".png";
1092         strWildcard = "PNG Files (*.png)|*.png";
1093       }
1094 #endif
1095       
1096       const wxString& strFilename = wxFileSelector (wxString("Export Filename"), wxString(""), 
1097         wxString(""), strExt, strWildcard, wxOVERWRITE_PROMPT | wxHIDE_READONLY | wxSAVE);
1098       if (strFilename) {
1099         rIF.exportImage (strFormatName.c_str(), strFilename.c_str(), 1, 1, m_dMinPixel, m_dMaxPixel);
1100         *theApp->getLog() << "Exported file " << strFilename << "\n";
1101       }
1102     }
1103   }
1104 }
1105
1106 void
1107 ImageFileView::OnScaleSize (wxCommandEvent& event)
1108 {
1109   ImageFile& rIF = GetDocument()->getImageFile();
1110   unsigned int iOldNX = rIF.nx();
1111   unsigned int iOldNY = rIF.ny();
1112   
1113   DialogGetXYSize dialogGetXYSize (getFrameForChild(), "Set New X & Y Dimensions", iOldNX, iOldNY);
1114   if (dialogGetXYSize.ShowModal() == wxID_OK) {
1115     unsigned int iNewNX = dialogGetXYSize.getXSize();
1116     unsigned int iNewNY = dialogGetXYSize.getYSize();
1117     std::ostringstream os;
1118     os << "Scale Size from (" << iOldNX << "," << iOldNY << ") to (" << iNewNX << "," << iNewNY << ")";
1119     ImageFileDocument* pScaledDoc = theApp->newImageDoc();
1120     if (! pScaledDoc) {
1121       sys_error (ERR_SEVERE, "Unable to create image file");
1122       return;
1123     }
1124     ImageFile& rScaledIF = pScaledDoc->getImageFile();
1125     rScaledIF.setArraySize (iNewNX, iNewNY);
1126     rScaledIF.labelsCopy (rIF);
1127     rScaledIF.labelAdd (os.str().c_str());
1128     rIF.scaleImage (rScaledIF);
1129     *theApp->getLog() << os.str().c_str() << "\n";
1130     if (theApp->getAskDeleteNewDocs())
1131       pScaledDoc->Modify (true);
1132     pScaledDoc->UpdateAllViews (this);
1133     pScaledDoc->getView()->OnUpdate (this, NULL);
1134     pScaledDoc->getView()->getFrame()->Show(true);
1135   }
1136 }
1137
1138 #if wxUSE_GLCANVAS
1139 void
1140 ImageFileView::OnConvert3d (wxCommandEvent& event)
1141 {
1142   ImageFile& rIF = GetDocument()->getImageFile();
1143   Graph3dFileDocument* pGraph3d = theApp->newGraph3dDoc();
1144   pGraph3d->setBadFileOpen();
1145   pGraph3d->createFromImageFile (rIF);
1146   pGraph3d->getView()->OnUpdate (this, NULL);
1147   pGraph3d->UpdateAllViews();
1148   pGraph3d->getView()->getFrame()->SetClientSize (400, 400);
1149   pGraph3d->getView()->getFrame()->Show (true);
1150   GetDocumentManager()->ActivateView (pGraph3d->getView(), true, false);
1151   ::wxYield();
1152   pGraph3d->getView()->getCanvas()->SetFocus();
1153 }
1154 #endif
1155
1156 void
1157 ImageFileView::OnPlotRow (wxCommandEvent& event)
1158 {
1159   int xCursor, yCursor;
1160   if (! m_pCanvas->GetCurrentCursor (xCursor, yCursor)) {
1161     wxMessageBox ("No row selected. Please use left mouse button on image to select column","Error");
1162     return;
1163   }
1164   
1165   const ImageFile& rIF = GetDocument()->getImageFile();
1166   ImageFileArrayConst v = rIF.getArray();
1167   ImageFileArrayConst vImag = rIF.getImaginaryArray();
1168   int nx = rIF.nx();
1169   int ny = rIF.ny();
1170   
1171   if (v != NULL && yCursor < ny) {
1172     double* pX = new double [nx];
1173     double* pYReal = new double [nx];
1174     double *pYImag = NULL;
1175     double *pYMag = NULL;
1176     if (rIF.isComplex()) {
1177       pYImag = new double [nx];
1178       pYMag = new double [nx];
1179     }
1180     for (int i = 0; i < nx; i++) {
1181       pX[i] = i;
1182       pYReal[i] = v[i][yCursor];
1183       if (rIF.isComplex()) {
1184         pYImag[i] = vImag[i][yCursor];
1185         pYMag[i] = ::sqrt (v[i][yCursor] * v[i][yCursor] + vImag[i][yCursor] * vImag[i][yCursor]);
1186       }
1187     }
1188     PlotFileDocument* pPlotDoc = theApp->newPlotDoc();
1189     if (! pPlotDoc) {
1190       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1191     } else {
1192       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1193       std::ostringstream os;
1194       os << "Row " << yCursor;
1195       std::string title("title ");
1196       title += os.str();
1197       rPlotFile.addEzsetCommand (title.c_str());
1198       rPlotFile.addEzsetCommand ("xlabel Column");
1199       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1200       rPlotFile.addEzsetCommand ("lxfrac 0");
1201       rPlotFile.addEzsetCommand ("box");
1202       rPlotFile.addEzsetCommand ("grid");
1203       rPlotFile.addEzsetCommand ("curve 1");
1204       rPlotFile.addEzsetCommand ("color 1");
1205       if (rIF.isComplex()) {
1206         rPlotFile.addEzsetCommand ("dash 1");
1207         rPlotFile.addEzsetCommand ("curve 2");
1208         rPlotFile.addEzsetCommand ("color 4");
1209         rPlotFile.addEzsetCommand ("dash 3");
1210         rPlotFile.addEzsetCommand ("curve 3");
1211         rPlotFile.addEzsetCommand ("color 0");
1212         rPlotFile.addEzsetCommand ("solid");
1213         rPlotFile.setCurveSize (4, nx);
1214       } else
1215         rPlotFile.setCurveSize (2, nx);
1216       rPlotFile.addColumn (0, pX);
1217       rPlotFile.addColumn (1, pYReal); 
1218       if (rIF.isComplex()) {
1219         rPlotFile.addColumn (2, pYImag);
1220         rPlotFile.addColumn (3, pYMag);
1221       }
1222       for (unsigned int iL = 0; iL < rIF.nLabels(); iL++)
1223         rPlotFile.addDescription (rIF.labelGet(iL).getLabelString().c_str());
1224       os << " Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1225       *theApp->getLog() << os.str().c_str() << "\n";
1226       rPlotFile.addDescription (os.str().c_str());
1227     }
1228     delete pX;
1229     delete pYReal;
1230     if (rIF.isComplex()) {
1231       delete pYImag;
1232       delete pYMag;
1233     }
1234     if (theApp->getAskDeleteNewDocs())
1235       pPlotDoc->Modify (true);
1236     pPlotDoc->UpdateAllViews ();
1237     pPlotDoc->getView()->OnUpdate (this, NULL);
1238     pPlotDoc->getView()->getFrame()->Show(true);
1239   }
1240 }
1241
1242 void
1243 ImageFileView::OnPlotCol (wxCommandEvent& event)
1244 {
1245   int xCursor, yCursor;
1246   if (! m_pCanvas->GetCurrentCursor (xCursor, yCursor)) {
1247     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1248     return;
1249   }
1250   
1251   const ImageFile& rIF = GetDocument()->getImageFile();
1252   ImageFileArrayConst v = rIF.getArray();
1253   ImageFileArrayConst vImag = rIF.getImaginaryArray();
1254   int nx = rIF.nx();
1255   int ny = rIF.ny();
1256   
1257   if (v != NULL && xCursor < nx) {
1258     double* pX = new double [ny];
1259     double* pYReal = new double [ny];
1260     double* pYImag = NULL;
1261     double* pYMag = NULL;
1262     if (rIF.isComplex()) {
1263       pYImag = new double [ny];
1264       pYMag = new double [ny];
1265     }
1266     for (int i = 0; i < ny; i++) {
1267       pX[i] = i;
1268       pYReal[i] = v[xCursor][i];
1269       if (rIF.isComplex()) {
1270         pYImag[i] = vImag[xCursor][i];
1271         pYMag[i] = ::sqrt (v[xCursor][i] * v[xCursor][i] + vImag[xCursor][i] * vImag[xCursor][i]);
1272       }
1273     }
1274     PlotFileDocument* pPlotDoc = theApp->newPlotDoc();
1275     if (! pPlotDoc) {
1276       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1277     } else {
1278       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1279       std::ostringstream os;
1280       os << "Column " << xCursor;
1281       std::string title("title ");
1282       title += os.str();
1283       rPlotFile.addEzsetCommand (title.c_str());
1284       rPlotFile.addEzsetCommand ("xlabel Row");
1285       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1286       rPlotFile.addEzsetCommand ("lxfrac 0");
1287       rPlotFile.addEzsetCommand ("box");
1288       rPlotFile.addEzsetCommand ("grid");
1289       rPlotFile.addEzsetCommand ("curve 1");
1290       rPlotFile.addEzsetCommand ("color 1");
1291       if (rIF.isComplex()) {
1292         rPlotFile.addEzsetCommand ("dash 1");
1293         rPlotFile.addEzsetCommand ("curve 2");
1294         rPlotFile.addEzsetCommand ("color 4");
1295         rPlotFile.addEzsetCommand ("dash 3");
1296         rPlotFile.addEzsetCommand ("curve 3");
1297         rPlotFile.addEzsetCommand ("color 0");
1298         rPlotFile.addEzsetCommand ("solid");
1299         rPlotFile.setCurveSize (4, ny);
1300       } else
1301         rPlotFile.setCurveSize (2, ny);
1302       rPlotFile.addColumn (0, pX);
1303       rPlotFile.addColumn (1, pYReal); 
1304       if (rIF.isComplex()) {
1305         rPlotFile.addColumn (2, pYImag);
1306         rPlotFile.addColumn (3, pYMag);
1307       }
1308       for (unsigned int iL = 0; iL < rIF.nLabels(); iL++)
1309         rPlotFile.addDescription (rIF.labelGet(iL).getLabelString().c_str());
1310       os << " Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1311       *theApp->getLog() << os.str().c_str() << "\n";
1312       rPlotFile.addDescription (os.str().c_str());
1313     }
1314     delete pX;
1315     delete pYReal;
1316     if (rIF.isComplex()) {
1317       delete pYImag;
1318       delete pYMag;
1319     }
1320     if (theApp->getAskDeleteNewDocs())
1321       pPlotDoc->Modify (true);
1322     pPlotDoc->UpdateAllViews ();
1323     pPlotDoc->getView()->OnUpdate (this, NULL);
1324     pPlotDoc->getView()->getFrame()->Show(true);
1325   }
1326 }
1327
1328 #ifdef HAVE_FFT
1329 void
1330 ImageFileView::OnPlotFFTRow (wxCommandEvent& event)
1331 {
1332   int xCursor, yCursor;
1333   if (! m_pCanvas->GetCurrentCursor (xCursor, yCursor)) {
1334     wxMessageBox ("No row selected. Please use left mouse button on image to select column","Error");
1335     return;
1336   }
1337   
1338   const ImageFile& rIF = GetDocument()->getImageFile();
1339   ImageFileArrayConst v = rIF.getArray();
1340   ImageFileArrayConst vImag = rIF.getImaginaryArray();
1341   int nx = rIF.nx();
1342   int ny = rIF.ny();
1343   
1344   if (v != NULL && yCursor < ny) {
1345     fftw_complex* pcIn = new fftw_complex [nx];
1346     
1347     int i;
1348     for (i = 0; i < nx; i++) {
1349       pcIn[i].re = v[i][yCursor];
1350       if (rIF.isComplex())
1351         pcIn[i].im = vImag[i][yCursor];
1352       else
1353         pcIn[i].im = 0;
1354     }
1355     
1356     fftw_plan plan = fftw_create_plan (nx, FFTW_FORWARD, FFTW_IN_PLACE);
1357     fftw_one (plan, pcIn, NULL);
1358     fftw_destroy_plan (plan);
1359     
1360     double* pX = new double [nx];
1361     double* pYReal = new double [nx];
1362     double* pYImag = new double [nx];
1363     double* pYMag = new double [nx];
1364     for (i = 0; i < nx; i++) {
1365       pX[i] = i;
1366       pYReal[i] = pcIn[i].re;
1367       pYImag[i] = pcIn[i].im;
1368       pYMag[i] = ::sqrt (pcIn[i].re * pcIn[i].re + pcIn[i].im * pcIn[i].im);
1369     }
1370     Fourier::shuffleFourierToNaturalOrder (pYReal, nx);
1371     Fourier::shuffleFourierToNaturalOrder (pYImag, nx);
1372     Fourier::shuffleFourierToNaturalOrder (pYMag, nx);
1373     
1374     PlotFileDocument* pPlotDoc = theApp->newPlotDoc();
1375     if (! pPlotDoc) {
1376       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1377     } else {
1378       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1379       std::ostringstream os;
1380       os << "Row " << yCursor;
1381       std::string title("title ");
1382       title += os.str();
1383       rPlotFile.addEzsetCommand (title.c_str());
1384       rPlotFile.addEzsetCommand ("xlabel Column");
1385       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1386       rPlotFile.addEzsetCommand ("lxfrac 0");
1387       rPlotFile.addEzsetCommand ("curve 1");
1388       rPlotFile.addEzsetCommand ("color 1");
1389       rPlotFile.addEzsetCommand ("dash 1");
1390       rPlotFile.addEzsetCommand ("curve 2");
1391       rPlotFile.addEzsetCommand ("color 4");
1392       rPlotFile.addEzsetCommand ("dash 3");
1393       rPlotFile.addEzsetCommand ("curve 3");
1394       rPlotFile.addEzsetCommand ("color 0");
1395       rPlotFile.addEzsetCommand ("solid");
1396       rPlotFile.addEzsetCommand ("box");
1397       rPlotFile.addEzsetCommand ("grid");
1398       rPlotFile.setCurveSize (4, nx);
1399       rPlotFile.addColumn (0, pX);
1400       rPlotFile.addColumn (1, pYReal);
1401       rPlotFile.addColumn (2, pYImag);
1402       rPlotFile.addColumn (3, pYMag);
1403       for (int iL = 0; iL < rIF.nLabels(); iL++)
1404         rPlotFile.addDescription (rIF.labelGet(iL).getLabelString().c_str());
1405       os << " FFT Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1406       *theApp->getLog() << os.str().c_str() << "\n";
1407       rPlotFile.addDescription (os.str().c_str());
1408     }
1409     delete pX;
1410     delete pYReal;
1411     delete pYImag;
1412     delete pYMag;
1413     delete [] pcIn;
1414     
1415     if (theApp->getAskDeleteNewDocs())
1416       pPlotDoc->Modify (true);
1417     pPlotDoc->UpdateAllViews ();
1418     pPlotDoc->getView()->OnUpdate (this, NULL);
1419     pPlotDoc->getView()->getFrame()->Show(true);
1420   }
1421 }
1422
1423 void
1424 ImageFileView::OnPlotFFTCol (wxCommandEvent& event)
1425 {
1426   int xCursor, yCursor;
1427   if (! m_pCanvas->GetCurrentCursor (xCursor, yCursor)) {
1428     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1429     return;
1430   }
1431   
1432   const ImageFile& rIF = GetDocument()->getImageFile();
1433   ImageFileArrayConst v = rIF.getArray();
1434   ImageFileArrayConst vImag = rIF.getImaginaryArray();
1435   int nx = rIF.nx();
1436   int ny = rIF.ny();
1437   
1438   if (v != NULL && xCursor < nx) {
1439     fftw_complex* pcIn = new fftw_complex [ny];
1440     double *pdTemp = new double [ny];
1441     
1442     int i;
1443     for (i = 0; i < ny; i++)
1444       pdTemp[i] = v[xCursor][i];
1445     Fourier::shuffleNaturalToFourierOrder (pdTemp, ny);
1446     for (i = 0; i < ny; i++) 
1447       pcIn[i].re = pdTemp[i];
1448     
1449     for (i = 0; i < ny; i++) {
1450       if (rIF.isComplex())
1451         pdTemp[i] = vImag[xCursor][i];
1452       else
1453         pdTemp[i] = 0;
1454     }
1455     Fourier::shuffleNaturalToFourierOrder (pdTemp, ny);
1456     for (i = 0; i < ny; i++)
1457       pcIn[i].im = pdTemp[i];
1458     
1459     fftw_plan plan = fftw_create_plan (ny, FFTW_BACKWARD, FFTW_IN_PLACE);
1460     fftw_one (plan, pcIn, NULL);
1461     fftw_destroy_plan (plan);
1462     
1463     double* pX = new double [ny];
1464     double* pYReal = new double [ny];
1465     double* pYImag = new double [ny];
1466     double* pYMag = new double [ny];
1467     for (i = 0; i < ny; i++) {
1468       pX[i] = i;
1469       pYReal[i] = pcIn[i].re;
1470       pYImag[i] = pcIn[i].im;
1471       pYMag[i] = ::sqrt (pcIn[i].re * pcIn[i].re + pcIn[i].im * pcIn[i].im);
1472     }
1473     
1474     PlotFileDocument* pPlotDoc = theApp->newPlotDoc();
1475     if (! pPlotDoc) {
1476       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1477     } else {
1478       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1479       std::ostringstream os;
1480       os << "Column " << xCursor;
1481       std::string title("title ");
1482       title += os.str();
1483       rPlotFile.addEzsetCommand (title.c_str());
1484       rPlotFile.addEzsetCommand ("xlabel Column");
1485       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1486       rPlotFile.addEzsetCommand ("lxfrac 0");
1487       rPlotFile.addEzsetCommand ("curve 1");
1488       rPlotFile.addEzsetCommand ("color 1");
1489       rPlotFile.addEzsetCommand ("dash 1");
1490       rPlotFile.addEzsetCommand ("curve 2");
1491       rPlotFile.addEzsetCommand ("color 4");
1492       rPlotFile.addEzsetCommand ("dash 3");
1493       rPlotFile.addEzsetCommand ("curve 3");
1494       rPlotFile.addEzsetCommand ("color 0");
1495       rPlotFile.addEzsetCommand ("solid");
1496       rPlotFile.addEzsetCommand ("box");
1497       rPlotFile.addEzsetCommand ("grid");
1498       rPlotFile.setCurveSize (4, ny);
1499       rPlotFile.addColumn (0, pX);
1500       rPlotFile.addColumn (1, pYReal);
1501       rPlotFile.addColumn (2, pYImag);
1502       rPlotFile.addColumn (3, pYMag);
1503       for (int iL = 0; iL < rIF.nLabels(); iL++)
1504         rPlotFile.addDescription (rIF.labelGet(iL).getLabelString().c_str());
1505       os << " FFT Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1506       *theApp->getLog() << os.str().c_str() << "\n";
1507       rPlotFile.addDescription (os.str().c_str());
1508     }
1509     delete pX;
1510     delete pYReal;
1511     delete pYImag;
1512     delete pYMag;
1513     delete pdTemp;
1514     delete [] pcIn;
1515     
1516     if (theApp->getAskDeleteNewDocs())
1517       pPlotDoc->Modify (true);
1518     pPlotDoc->UpdateAllViews ();
1519     pPlotDoc->getView()->OnUpdate (this, NULL);
1520     pPlotDoc->getView()->getFrame()->Show(true);
1521   }
1522 }
1523 #endif
1524
1525 void
1526 ImageFileView::OnCompareCol (wxCommandEvent& event)
1527 {
1528   int xCursor, yCursor;
1529   if (! m_pCanvas->GetCurrentCursor (xCursor, yCursor)) {
1530     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1531     return;
1532   }
1533   
1534   std::vector<ImageFileDocument*> vecIFDoc;
1535   theApp->getCompatibleImages (GetDocument(), vecIFDoc);
1536   if (vecIFDoc.size() == 0) {
1537     wxMessageBox ("No compatible images for Column Comparison", "Error");
1538     return;
1539   }
1540   DialogGetComparisonImage dialogGetCompare (getFrameForChild(), "Get Comparison Image", vecIFDoc, false);
1541   
1542   if (dialogGetCompare.ShowModal() == wxID_OK) {
1543     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();
1544     const ImageFile& rIF = GetDocument()->getImageFile();
1545     const ImageFile& rCompareIF = pCompareDoc->getImageFile();
1546     
1547     ImageFileArrayConst v1 = rIF.getArray();
1548     ImageFileArrayConst v2 = rCompareIF.getArray();
1549     int nx = rIF.nx();
1550     int ny = rIF.ny();
1551     
1552     if (v1 != NULL && xCursor < nx) {
1553       double* pX = new double [ny];
1554       double* pY1 = new double [ny];
1555       double* pY2 = new double [ny];
1556       for (int i = 0; i < ny; i++) {
1557         pX[i] = i;
1558         pY1[i] = v1[xCursor][i];
1559         pY2[i] = v2[xCursor][i];
1560       }
1561       PlotFileDocument* pPlotDoc = theApp->newPlotDoc();
1562       if (! pPlotDoc) {
1563         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1564       } else {
1565         PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1566         std::ostringstream os;
1567         os << "Column " << xCursor << " Comparison";
1568         std::string title("title ");
1569         title += os.str();
1570         rPlotFile.addEzsetCommand (title.c_str());
1571         rPlotFile.addEzsetCommand ("xlabel Row");
1572         rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1573         rPlotFile.addEzsetCommand ("lxfrac 0");
1574         rPlotFile.addEzsetCommand ("curve 1");
1575         rPlotFile.addEzsetCommand ("color 2");
1576         rPlotFile.addEzsetCommand ("curve 2");
1577         rPlotFile.addEzsetCommand ("color 4");
1578         rPlotFile.addEzsetCommand ("dash 5");
1579         rPlotFile.addEzsetCommand ("box");
1580         rPlotFile.addEzsetCommand ("grid");
1581         rPlotFile.setCurveSize (3, ny);
1582         rPlotFile.addColumn (0, pX);
1583         rPlotFile.addColumn (1, pY1);
1584         rPlotFile.addColumn (2, pY2);
1585         
1586         unsigned int iL;
1587         for (iL = 0; iL < rIF.nLabels(); iL++) {
1588           std::string s = GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1589           s += ": ";
1590           s += rIF.labelGet(iL).getLabelString();
1591           rPlotFile.addDescription (s.c_str());
1592         }
1593         for (iL = 0; iL < rCompareIF.nLabels(); iL++) {
1594           std::string s = pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
1595           s += ": ";
1596           s += rCompareIF.labelGet(iL).getLabelString();
1597           rPlotFile.addDescription (s.c_str());
1598         }
1599         os << " Between " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and "
1600           << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
1601         *theApp->getLog() << os.str().c_str() << "\n";
1602         rPlotFile.addDescription (os.str().c_str());
1603       }
1604       delete pX;
1605       delete pY1;
1606       delete pY2;
1607       if (theApp->getAskDeleteNewDocs())
1608         pPlotDoc->Modify (true);
1609       pPlotDoc->UpdateAllViews ();
1610       pPlotDoc->getView()->OnUpdate (this, NULL);
1611       pPlotDoc->getView()->getFrame()->Show(true);
1612     }
1613   }
1614 }
1615
1616 void
1617 ImageFileView::OnCompareRow (wxCommandEvent& event)
1618 {
1619   int xCursor, yCursor;
1620   if (! m_pCanvas->GetCurrentCursor (xCursor, yCursor)) {
1621     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1622     return;
1623   }
1624   
1625   std::vector<ImageFileDocument*> vecIFDoc;
1626   theApp->getCompatibleImages (GetDocument(), vecIFDoc);
1627   
1628   if (vecIFDoc.size() == 0) {
1629     wxMessageBox ("No compatible images for Row Comparison", "Error");
1630     return;
1631   }
1632   
1633   DialogGetComparisonImage dialogGetCompare (getFrameForChild(), "Get Comparison Image", vecIFDoc, false);
1634   
1635   if (dialogGetCompare.ShowModal() == wxID_OK) {
1636     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();
1637     const ImageFile& rIF = GetDocument()->getImageFile();
1638     const ImageFile& rCompareIF = pCompareDoc->getImageFile();
1639     
1640     ImageFileArrayConst v1 = rIF.getArray();
1641     ImageFileArrayConst v2 = rCompareIF.getArray();
1642     int nx = rIF.nx();
1643     int ny = rIF.ny();
1644     
1645     if (v1 != NULL && yCursor < ny) {
1646       double* pX = new double [nx];
1647       double* pY1 = new double [nx];
1648       double* pY2 = new double [nx];
1649       for (int i = 0; i < nx; i++) {
1650         pX[i] = i;
1651         pY1[i] = v1[i][yCursor];
1652         pY2[i] = v2[i][yCursor];
1653       }
1654       PlotFileDocument* pPlotDoc = theApp->newPlotDoc();
1655       if (! pPlotDoc) {
1656         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1657       } else {
1658         PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1659         std::ostringstream os;
1660         os << "Row " << yCursor << " Comparison";
1661         std::string title("title ");
1662         title += os.str();
1663         rPlotFile.addEzsetCommand (title.c_str());
1664         rPlotFile.addEzsetCommand ("xlabel Column");
1665         rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1666         rPlotFile.addEzsetCommand ("lxfrac 0");
1667         rPlotFile.addEzsetCommand ("curve 1");
1668         rPlotFile.addEzsetCommand ("color 2");
1669         rPlotFile.addEzsetCommand ("curve 2");
1670         rPlotFile.addEzsetCommand ("color 4");
1671         rPlotFile.addEzsetCommand ("dash 5");
1672         rPlotFile.addEzsetCommand ("box");
1673         rPlotFile.addEzsetCommand ("grid");
1674         rPlotFile.setCurveSize (3, nx);
1675         rPlotFile.addColumn (0, pX);
1676         rPlotFile.addColumn (1, pY1);
1677         rPlotFile.addColumn (2, pY2);
1678         unsigned int iL;
1679         for (iL = 0; iL < rIF.nLabels(); iL++) {
1680           std::string s = GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1681           s += ": ";
1682           s += rIF.labelGet(iL).getLabelString();
1683           rPlotFile.addDescription (s.c_str());
1684         }
1685         for (iL = 0; iL < rCompareIF.nLabels(); iL++) {
1686           std::string s = pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
1687           s += ": ";
1688           s += rCompareIF.labelGet(iL).getLabelString();
1689           rPlotFile.addDescription (s.c_str());
1690         }
1691         os << " Between " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and "
1692           << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
1693         *theApp->getLog() << os.str().c_str() << "\n";
1694         rPlotFile.addDescription (os.str().c_str());
1695       }
1696       delete pX;
1697       delete pY1;
1698       delete pY2;
1699       if (theApp->getAskDeleteNewDocs())
1700         pPlotDoc->Modify (true);
1701       pPlotDoc->UpdateAllViews ();
1702       pPlotDoc->getView()->OnUpdate (this, NULL);
1703       pPlotDoc->getView()->getFrame()->Show(true);
1704     }
1705   }
1706 }
1707
1708 static int NUMBER_HISTOGRAM_BINS = 256;
1709
1710 void
1711 ImageFileView::OnPlotHistogram (wxCommandEvent& event)
1712
1713   const ImageFile& rIF = GetDocument()->getImageFile();
1714   ImageFileArrayConst v = rIF.getArray();
1715   int nx = rIF.nx();
1716   int ny = rIF.ny();
1717   
1718   if (v != NULL && nx > 0 && ny > 0) {
1719     PlotFileDocument* pPlotDoc = theApp->newPlotDoc();
1720     if (! pPlotDoc) {
1721       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1722       return;
1723     }
1724     
1725     double* pX = new double [NUMBER_HISTOGRAM_BINS];
1726     double* pY = new double [NUMBER_HISTOGRAM_BINS];
1727     double dMin, dMax;
1728     rIF.getMinMax (dMin, dMax);
1729     double dBinWidth = (dMax - dMin) / NUMBER_HISTOGRAM_BINS;
1730     
1731     for (int i = 0; i < NUMBER_HISTOGRAM_BINS; i++) {
1732       pX[i] = dMin + (i + 0.5) * dBinWidth;
1733       pY[i] = 0;
1734     }
1735     for (int ix = 0; ix < nx; ix++)
1736       for (int iy = 0; iy < ny; iy++) {
1737         int iBin = nearest<int> ((v[ix][iy] - dMin) / dBinWidth);
1738         if (iBin >= 0 && iBin < NUMBER_HISTOGRAM_BINS)
1739           pY[iBin] += 1;
1740       }
1741       
1742       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1743       std::ostringstream os;
1744       os << "Histogram";
1745       std::string title("title ");
1746       title += os.str();
1747       rPlotFile.addEzsetCommand (title.c_str());
1748       rPlotFile.addEzsetCommand ("xlabel Pixel Value");
1749       rPlotFile.addEzsetCommand ("ylabel Count");
1750       rPlotFile.addEzsetCommand ("box");
1751       rPlotFile.addEzsetCommand ("grid");
1752       rPlotFile.setCurveSize (2, NUMBER_HISTOGRAM_BINS);
1753       rPlotFile.addColumn (0, pX);
1754       rPlotFile.addColumn (1, pY);
1755       for (unsigned int iL = 0; iL < rIF.nLabels(); iL++) {
1756         std::string s = GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1757         s += ": ";
1758         s += rIF.labelGet(iL).getLabelString();
1759         rPlotFile.addDescription (s.c_str());
1760       }
1761       os << " Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1762       *theApp->getLog() << os.str().c_str() << "\n";
1763       rPlotFile.addDescription (os.str().c_str());
1764       delete pX;
1765       delete pY;
1766       if (theApp->getAskDeleteNewDocs())
1767         pPlotDoc->Modify (true);
1768       pPlotDoc->UpdateAllViews ();
1769       pPlotDoc->getView()->OnUpdate (this, NULL);
1770       pPlotDoc->getView()->getFrame()->Show(true);
1771   }
1772 }
1773
1774
1775 // PhantomCanvas
1776
1777 PhantomCanvas::PhantomCanvas (PhantomFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1778 : wxScrolledWindow(frame, -1, pos, size, style)
1779 {
1780   m_pView = v;
1781 }
1782
1783 PhantomCanvas::~PhantomCanvas ()
1784 {
1785   m_pView = NULL;
1786 }
1787
1788 void 
1789 PhantomCanvas::OnDraw (wxDC& dc)
1790 {
1791   if (m_pView)
1792     m_pView->OnDraw(& dc);
1793 }
1794
1795 wxSize
1796 PhantomCanvas::GetBestSize() const
1797 {
1798   if (! m_pView)
1799     return wxSize(0,0);
1800   
1801   int xSize, ySize;
1802   theApp->getMainFrame()->GetClientSize (&xSize, &ySize);
1803   xSize = maxValue<int> (xSize, ySize);
1804   ySize = xSize = (xSize / 3);
1805   return wxSize (xSize, ySize);
1806 }
1807
1808
1809
1810 // PhantomFileView
1811
1812 IMPLEMENT_DYNAMIC_CLASS(PhantomFileView, wxView)
1813
1814 BEGIN_EVENT_TABLE(PhantomFileView, wxView)
1815 EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomFileView::OnProperties)
1816 EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomFileView::OnRasterize)
1817 EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomFileView::OnProjections)
1818 END_EVENT_TABLE()
1819
1820 PhantomFileView::PhantomFileView() 
1821 : wxView(), m_pFrame(NULL), m_pCanvas(NULL), m_pFileMenu(0)
1822 {
1823 #if defined(DEBUG) || defined(_DEBUG)
1824   m_iDefaultNDet = 165;
1825   m_iDefaultNView = 180;
1826 #else
1827   m_iDefaultNDet = 367;
1828   m_iDefaultNView = 320;
1829 #endif
1830   m_iDefaultNSample = 2;
1831   m_dDefaultRotation = 1;
1832   m_dDefaultFocalLength = 2;
1833   m_dDefaultViewRatio = 1;
1834   m_dDefaultScanRatio = 1;
1835   m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL;
1836   m_iDefaultTrace = Trace::TRACE_NONE;
1837   
1838 #ifdef DEBUG 
1839   m_iDefaultRasterNX = 115;
1840   m_iDefaultRasterNY = 115;
1841   m_iDefaultRasterNSamples = 1;
1842 #else
1843   m_iDefaultRasterNX = 256;
1844   m_iDefaultRasterNY = 256;
1845   m_iDefaultRasterNSamples = 2;
1846 #endif
1847   m_dDefaultRasterViewRatio = 1;
1848 }
1849
1850 PhantomFileView::~PhantomFileView()
1851 {
1852   GetDocumentManager()->FileHistoryRemoveMenu (m_pFileMenu);
1853   GetDocumentManager()->ActivateView(this, FALSE, TRUE);
1854 }
1855
1856 void
1857 PhantomFileView::OnProperties (wxCommandEvent& event)
1858 {
1859   const int idPhantom = GetDocument()->getPhantomID();
1860   const wxString& namePhantom = GetDocument()->getPhantomName();
1861   std::ostringstream os;
1862   os << "Phantom " << namePhantom.c_str() << " (" << idPhantom << ")" << "\n";
1863   const Phantom& rPhantom = GetDocument()->getPhantom();
1864   rPhantom.printDefinitions (os);
1865 #if DEBUG
1866   rPhantom.print (os);
1867 #endif
1868   *theApp->getLog() << ">>>>\n" << os.str().c_str() << "<<<<\n";
1869   wxMessageBox (os.str().c_str(), "Phantom Properties");
1870 }
1871
1872
1873 void
1874 PhantomFileView::OnProjections (wxCommandEvent& event)
1875 {
1876   DialogGetProjectionParameters dialogProjection (getFrameForChild(), 
1877     m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, 
1878     m_dDefaultFocalLength, m_dDefaultViewRatio, m_dDefaultScanRatio, m_iDefaultGeometry, 
1879     m_iDefaultTrace);
1880   int retVal = dialogProjection.ShowModal();
1881   if (retVal == wxID_OK) {
1882     m_iDefaultNDet = dialogProjection.getNDet();
1883     m_iDefaultNView = dialogProjection.getNView();
1884     m_iDefaultNSample = dialogProjection.getNSamples();
1885     m_iDefaultTrace = dialogProjection.getTrace();
1886     m_dDefaultRotation = dialogProjection.getRotAngle();
1887     m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
1888     m_dDefaultViewRatio = dialogProjection.getViewRatio();
1889     m_dDefaultScanRatio = dialogProjection.getScanRatio();
1890     wxString sGeometry = dialogProjection.getGeometry();
1891     m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
1892     
1893     if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
1894       const Phantom& rPhantom = GetDocument()->getPhantom();
1895       Projections* pProj = new Projections;
1896       Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, 
1897         m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultViewRatio, m_dDefaultScanRatio);
1898       if (theScanner.fail()) {
1899         wxString msg = "Failed making scanner\n";
1900         msg += theScanner.failMessage().c_str();
1901         *theApp->getLog() << msg << "\n";
1902         wxMessageBox (msg, "Error");
1903         return;
1904       }
1905       std::ostringstream os;
1906       os << "Projections for " << rPhantom.name() << ": nDet=" << m_iDefaultNDet 
1907         << ", nView=" << m_iDefaultNView << ", nSamples=" << m_iDefaultNSample 
1908         << ", RotAngle=" << m_dDefaultRotation << ", FocalLengthRatio=" << m_dDefaultFocalLength 
1909         << ", ViewRatio=" << m_dDefaultViewRatio << ", ScanRatio=" << m_dDefaultScanRatio 
1910         << ", Geometry=" << sGeometry.c_str() << ", FanBeamAngle=" << 
1911         convertRadiansToDegrees (theScanner.fanBeamAngle());
1912       pProj->initFromScanner (theScanner);
1913       m_dDefaultRotation /= TWOPI;  // convert back to fraction of a circle
1914       
1915       Timer timer;
1916       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
1917         ProjectionsDialog dialogProjections (theScanner, *pProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(getFrameForChild()));
1918         for (int iView = 0; iView < pProj->nView(); iView++) {
1919           ::wxYield();
1920           if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
1921             delete pProj;
1922             return;
1923           }
1924           ::wxYield();
1925           while (dialogProjections.isPaused()) {
1926             ::wxYield();
1927             ::wxUsleep(50);
1928           }
1929         }
1930       } else {
1931         wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), pProj->nView() + 1, getFrameForChild(), wxPD_CAN_ABORT );
1932         for (int i = 0; i < pProj->nView(); i++) {
1933           theScanner.collectProjections (*pProj, rPhantom, i, 1, true, m_iDefaultTrace);
1934           if (! dlgProgress.Update (i+1)) {
1935             delete pProj;
1936             return;
1937           }
1938         }
1939       }
1940       
1941       pProj->setRemark (os.str());
1942       pProj->setCalcTime (timer.timerEnd());
1943       *theApp->getLog() << os.str().c_str() << "\n";
1944       
1945       ::wxYield();
1946       ProjectionFileDocument* pProjectionDoc = theApp->newProjectionDoc();
1947       if (! pProjectionDoc) {
1948         sys_error (ERR_SEVERE, "Unable to create projection document");
1949         return;
1950       }
1951       pProjectionDoc->setProjections (pProj);
1952       ProjectionFileView* projView = pProjectionDoc->getView();
1953       if (projView) {
1954         projView->OnUpdate (projView, NULL);
1955         if (projView->getCanvas())
1956               projView->getCanvas()->SetClientSize (m_iDefaultNDet, m_iDefaultNView);
1957         if (wxFrame* pFrame = projView->getFrame()) {
1958           pFrame->Show(true);
1959           pFrame->SetFocus();
1960           pFrame->Raise();
1961         }
1962         GetDocumentManager()->ActivateView (projView, true, false);
1963       }
1964       ::wxYield();
1965       if (theApp->getAskDeleteNewDocs())
1966         pProjectionDoc-> Modify(true);
1967       pProjectionDoc->UpdateAllViews (this);
1968     }
1969   }
1970 }
1971
1972
1973 void
1974 PhantomFileView::OnRasterize (wxCommandEvent& event)
1975 {
1976   DialogGetRasterParameters dialogRaster (getFrameForChild(), m_iDefaultRasterNX, m_iDefaultRasterNY, 
1977     m_iDefaultRasterNSamples, m_dDefaultRasterViewRatio);
1978   int retVal = dialogRaster.ShowModal();
1979   if (retVal == wxID_OK) {
1980     m_iDefaultRasterNX = dialogRaster.getXSize();
1981     m_iDefaultRasterNY  = dialogRaster.getYSize();
1982     m_iDefaultRasterNSamples = dialogRaster.getNSamples();
1983     m_dDefaultRasterViewRatio = dialogRaster.getViewRatio();
1984     if (m_iDefaultRasterNSamples < 1)
1985       m_iDefaultRasterNSamples = 1;
1986     if (m_dDefaultRasterViewRatio < 0)
1987       m_dDefaultRasterViewRatio = 0;
1988     if (m_iDefaultRasterNX > 0 && m_iDefaultRasterNY > 0) {
1989       const Phantom& rPhantom = GetDocument()->getPhantom();
1990       
1991       ImageFile* pImageFile = new ImageFile;
1992       
1993       pImageFile->setArraySize (m_iDefaultRasterNX, m_iDefaultRasterNY);
1994       wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), 
1995         pImageFile->nx() + 1, getFrameForChild(), wxPD_CAN_ABORT );
1996       Timer timer;
1997       for (unsigned int i = 0; i < pImageFile->nx(); i++) {
1998         rPhantom.convertToImagefile (*pImageFile, m_dDefaultRasterViewRatio, m_iDefaultRasterNSamples, 
1999           Trace::TRACE_NONE, i, 1, true);
2000         if (! dlgProgress.Update (i+1)) {
2001           delete pImageFile;
2002           return;
2003         }
2004       }
2005       
2006       ImageFileDocument* pRasterDoc = theApp->newImageDoc();
2007       if (! pRasterDoc) {
2008         sys_error (ERR_SEVERE, "Unable to create image file");
2009         return;
2010       }
2011       pRasterDoc->setImageFile (pImageFile);
2012       
2013       if (theApp->getAskDeleteNewDocs())
2014         pRasterDoc->Modify (true);
2015       pRasterDoc->UpdateAllViews (this);
2016       pRasterDoc->getView()->getFrame()->Show(true);
2017       std::ostringstream os;
2018       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << m_iDefaultRasterNX << ", YSize=" 
2019         << m_iDefaultRasterNY << ", ViewRatio=" << m_dDefaultRasterViewRatio << ", nSamples=" 
2020         << m_iDefaultRasterNSamples;;
2021       *theApp->getLog() << os.str().c_str() << "\n";
2022       pImageFile->labelAdd (os.str().c_str(), timer.timerEnd());
2023       ImageFileView* rasterView = pRasterDoc->getView();
2024       if (rasterView) {
2025         rasterView->getFrame()->SetFocus();
2026         rasterView->OnUpdate (rasterView, NULL);
2027       }
2028       
2029     }
2030   }
2031 }
2032
2033
2034 PhantomCanvas* 
2035 PhantomFileView::CreateCanvas (wxFrame *parent)
2036 {
2037   PhantomCanvas* pCanvas;
2038   
2039   pCanvas = new PhantomCanvas (this, parent, wxPoint(0, 0), wxSize(0,0), 0);
2040   pCanvas->SetBackgroundColour(*wxWHITE);
2041   pCanvas->Clear();
2042   
2043   return pCanvas;
2044 }
2045
2046 #if CTSIM_MDI
2047 wxDocMDIChildFrame*
2048 #else
2049 wxDocChildFrame*
2050 #endif
2051 PhantomFileView::CreateChildFrame(wxDocument *doc, wxView *view)
2052 {
2053 #if CTSIM_MDI
2054   wxDocMDIChildFrame *subframe = new wxDocMDIChildFrame (doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
2055 #else
2056   wxDocChildFrame *subframe = new wxDocChildFrame (doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
2057 #endif
2058   theApp->setIconForFrame (subframe);
2059   
2060   m_pFileMenu = new wxMenu;
2061   
2062   m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P");
2063   m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F");
2064   m_pFileMenu->Append(wxID_OPEN, "&Open...\tCtrl-O");
2065   m_pFileMenu->Append(wxID_SAVEAS, "Save &As...");
2066   m_pFileMenu->Append(wxID_CLOSE, "&Close");
2067   
2068   m_pFileMenu->AppendSeparator();
2069   m_pFileMenu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties\tCtrl-I");
2070   
2071   m_pFileMenu->AppendSeparator();
2072   m_pFileMenu->Append(wxID_PRINT, "&Print...");
2073   m_pFileMenu->Append(wxID_PRINT_SETUP, "Print &Setup...");
2074   m_pFileMenu->Append(wxID_PREVIEW, "Print Pre&view");
2075 #ifdef CTSIM_MDI
2076   m_pFileMenu->AppendSeparator();
2077   m_pFileMenu->Append (MAINMENU_FILE_PREFERENCES, "Prefere&nces...");
2078   m_pFileMenu->Append(MAINMENU_FILE_EXIT, "E&xit");
2079 #endif
2080   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
2081   GetDocumentManager()->FileHistoryUseMenu(m_pFileMenu);
2082   
2083   wxMenu *process_menu = new wxMenu;
2084   process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...\tCtrl-R");
2085   process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...\tCtrl-J");
2086   
2087   wxMenu *help_menu = new wxMenu;
2088   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
2089   help_menu->Append (MAINMENU_HELP_TIPS, "&Tips");
2090   help_menu->Append (IDH_QUICKSTART, "&Quick Start");
2091   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
2092   
2093   wxMenuBar *menu_bar = new wxMenuBar;
2094   
2095   menu_bar->Append(m_pFileMenu, "&File");
2096   menu_bar->Append(process_menu, "&Process");
2097   menu_bar->Append(help_menu, "&Help");
2098   
2099   subframe->SetMenuBar(menu_bar);
2100   subframe->Centre(wxBOTH);
2101   
2102   wxAcceleratorEntry accelEntries[3];
2103   accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('J'), PHMMENU_PROCESS_PROJECTIONS);
2104   accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('R'), PHMMENU_PROCESS_RASTERIZE);
2105   accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('I'), PHMMENU_FILE_PROPERTIES);
2106   wxAcceleratorTable accelTable (3, accelEntries);
2107   subframe->SetAcceleratorTable (accelTable);
2108   
2109   return subframe;
2110 }
2111
2112
2113 bool 
2114 PhantomFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
2115 {
2116   m_pFrame = CreateChildFrame(doc, this);
2117   SetFrame(m_pFrame);
2118   m_pCanvas = CreateCanvas (m_pFrame);
2119   m_pFrame->SetClientSize (m_pCanvas->GetBestSize());
2120   m_pCanvas->SetClientSize (m_pCanvas->GetBestSize());
2121   
2122   m_pFrame->SetTitle ("PhantomFileView");
2123   
2124 #ifdef __X__
2125   int x, y;  // X requires a forced resize
2126   m_pFrame->GetSize(&x, &y);
2127   m_pFrame->SetSize(-1, -1, x, y);
2128 #endif
2129   
2130   m_pFrame->Show(true);
2131   Activate(true);
2132   
2133   return true;
2134 }
2135
2136 void 
2137 PhantomFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
2138 {
2139   if (m_pCanvas)
2140     m_pCanvas->Refresh();
2141 }
2142
2143 bool 
2144 PhantomFileView::OnClose (bool deleteWindow)
2145 {
2146   //GetDocumentManager()->ActivateView (this, false, true);
2147   if (! GetDocument() || ! GetDocument()->Close())
2148     return false;
2149   
2150   Activate(false);
2151   if (m_pCanvas) {
2152     m_pCanvas->setView(NULL);
2153     m_pCanvas = NULL;
2154   }
2155   wxString s(wxTheApp->GetAppName());
2156   if (m_pFrame)
2157     m_pFrame->SetTitle(s);
2158   
2159   SetFrame(NULL);
2160   
2161   if (deleteWindow) {
2162     delete m_pFrame;
2163     m_pFrame = NULL;
2164     if (GetDocument() && GetDocument()->getBadFileOpen())
2165       ::wxYield();  // wxWindows bug workaround
2166   }
2167   
2168   return true;
2169 }
2170
2171 void
2172 PhantomFileView::OnDraw (wxDC* dc)
2173 {
2174   int xsize, ysize;
2175   m_pCanvas->GetClientSize (&xsize, &ysize);
2176   SGPDriver driver (dc, xsize, ysize);
2177   SGP sgp (driver);
2178   const Phantom& rPhantom = GetDocument()->getPhantom();
2179   sgp.setColor (C_RED);
2180   rPhantom.show (sgp);
2181 }
2182
2183 // ProjectionCanvas
2184
2185 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
2186 : wxScrolledWindow(frame, -1, pos, size, style)
2187 {
2188   m_pView = v;
2189 }
2190
2191 ProjectionFileCanvas::~ProjectionFileCanvas ()
2192 {
2193   m_pView = NULL;
2194 }
2195
2196 void 
2197 ProjectionFileCanvas::OnDraw(wxDC& dc)
2198 {
2199   if (m_pView)
2200     m_pView->OnDraw(& dc);
2201 }
2202
2203 wxSize
2204 ProjectionFileCanvas::GetBestSize () const
2205 {
2206   wxSize best (0, 0);
2207   if (m_pView) {
2208     Projections& rProj = m_pView->GetDocument()->getProjections();
2209     best.Set (rProj.nDet(), rProj.nView());
2210   }
2211   
2212   return best;
2213 }
2214
2215
2216 // ProjectionFileView
2217
2218 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
2219
2220 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
2221 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
2222 EVT_MENU(PJMENU_RECONSTRUCT_FBP, ProjectionFileView::OnReconstructFBP)
2223 EVT_MENU(PJMENU_RECONSTRUCT_FOURIER, ProjectionFileView::OnReconstructFourier)
2224 EVT_MENU(PJMENU_CONVERT_POLAR, ProjectionFileView::OnConvertPolar)
2225 EVT_MENU(PJMENU_CONVERT_FFT_POLAR, ProjectionFileView::OnConvertFFTPolar)
2226 END_EVENT_TABLE()
2227
2228 ProjectionFileView::ProjectionFileView() 
2229 : wxView(), m_pFrame(0), m_pCanvas(0), m_pFileMenu(0)
2230 {
2231 #ifdef DEBUG
2232   m_iDefaultNX = 115;
2233   m_iDefaultNY = 115;
2234 #else
2235   m_iDefaultNX = 256;
2236   m_iDefaultNY = 256;
2237 #endif
2238   
2239   m_iDefaultFilter = SignalFilter::FILTER_ABS_BANDLIMIT;
2240   m_dDefaultFilterParam = 1.;
2241 #if HAVE_FFTW
2242   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_RFFTW;
2243   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER;
2244 #else
2245   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_CONVOLUTION;
2246   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_DIRECT;
2247 #endif
2248   m_iDefaultZeropad = 1;
2249   m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF;
2250   m_iDefaultInterpolation = Backprojector::INTERP_LINEAR;
2251   m_iDefaultInterpParam = 1;
2252   m_iDefaultTrace = Trace::TRACE_NONE;
2253   
2254   m_iDefaultPolarNX = 256;
2255   m_iDefaultPolarNY = 256;
2256   m_iDefaultPolarInterpolation = Projections::POLAR_INTERP_BILINEAR;
2257   m_iDefaultPolarZeropad = 1;
2258 }
2259
2260 ProjectionFileView::~ProjectionFileView()
2261 {
2262   GetDocumentManager()->FileHistoryRemoveMenu (m_pFileMenu);
2263   GetDocumentManager()->ActivateView(this, FALSE, TRUE);;
2264 }
2265
2266 void
2267 ProjectionFileView::OnProperties (wxCommandEvent& event)
2268 {
2269   const Projections& rProj = GetDocument()->getProjections();
2270   std::ostringstream os;
2271   rProj.printScanInfo(os);
2272   *theApp->getLog() << ">>>>\n" << os.str().c_str() << "<<<<\n";
2273   wxMessageDialog dialogMsg (getFrameForChild(), os.str().c_str(), "Projection File Properties", wxOK | wxICON_INFORMATION);
2274   dialogMsg.ShowModal();
2275 }
2276
2277
2278 void
2279 ProjectionFileView::OnConvertPolar (wxCommandEvent& event)
2280 {
2281   Projections& rProj = GetDocument()->getProjections();
2282   DialogGetConvertPolarParameters dialogPolar (getFrameForChild(), "Convert Polar", m_iDefaultPolarNX, m_iDefaultPolarNY,
2283     m_iDefaultPolarInterpolation, -1);
2284   if (dialogPolar.ShowModal() == wxID_OK) {
2285     wxString strInterpolation (dialogPolar.getInterpolationName());
2286     m_iDefaultPolarNX = dialogPolar.getXSize();
2287     m_iDefaultPolarNY = dialogPolar.getYSize();
2288     ImageFileDocument* pPolarDoc = theApp->newImageDoc();
2289     ImageFile* pIF = new ImageFile (m_iDefaultPolarNX, m_iDefaultPolarNY);
2290     m_iDefaultPolarInterpolation = Projections::convertInterpNameToID (strInterpolation.c_str());
2291     if (! rProj.convertPolar (*pIF, m_iDefaultPolarInterpolation)) {
2292       delete pIF;
2293       *theApp->getLog() << "Error converting to Polar\n";
2294       return;
2295     }
2296     pPolarDoc = theApp->newImageDoc ();
2297     if (! pPolarDoc) {
2298       sys_error (ERR_SEVERE, "Unable to create image file");
2299       return;
2300     }
2301     pPolarDoc->setImageFile (pIF);
2302     pIF->labelAdd (rProj.getLabel().getLabelString().c_str(), rProj.calcTime());
2303     std::ostringstream os;
2304     os << "Convert projection file " << GetFrame()->GetTitle().c_str() << " to polar image: xSize=" 
2305       << m_iDefaultPolarNX << ", ySize=" << m_iDefaultPolarNY << ", interpolation=" 
2306       << strInterpolation.c_str();
2307     *theApp->getLog() << os.str().c_str() << "\n";
2308     pIF->labelAdd (os.str().c_str());
2309     if (theApp->getAskDeleteNewDocs())
2310       pPolarDoc->Modify (true);
2311     pPolarDoc->UpdateAllViews ();
2312     pPolarDoc->getView()->OnUpdate (this, NULL);
2313     pPolarDoc->getView()->getFrame()->Show(true);
2314   }
2315 }
2316
2317 void
2318 ProjectionFileView::OnConvertFFTPolar (wxCommandEvent& event)
2319 {
2320   Projections& rProj = GetDocument()->getProjections();
2321   DialogGetConvertPolarParameters dialogPolar (getFrameForChild(), "Convert to FFT Polar", m_iDefaultPolarNX, m_iDefaultPolarNY,
2322     m_iDefaultPolarInterpolation, m_iDefaultPolarZeropad);
2323   if (dialogPolar.ShowModal() == wxID_OK) {
2324     wxString strInterpolation (dialogPolar.getInterpolationName());
2325     m_iDefaultPolarNX = dialogPolar.getXSize();
2326     m_iDefaultPolarNY = dialogPolar.getYSize();
2327     m_iDefaultPolarZeropad = dialogPolar.getZeropad();
2328     ImageFile* pIF = new ImageFile (m_iDefaultPolarNX, m_iDefaultPolarNY);
2329     
2330     m_iDefaultPolarInterpolation = Projections::convertInterpNameToID (strInterpolation.c_str());
2331     if (! rProj.convertFFTPolar (*pIF, m_iDefaultPolarInterpolation, m_iDefaultPolarZeropad)) {
2332       delete pIF;
2333       *theApp->getLog() << "Error converting to polar\n";
2334       return;
2335     }
2336     ImageFileDocument* pPolarDoc = theApp->newImageDoc();
2337     if (! pPolarDoc) {
2338       sys_error (ERR_SEVERE, "Unable to create image file");
2339       return;
2340     }
2341     pPolarDoc->setImageFile (pIF);
2342     pIF->labelAdd (rProj.getLabel().getLabelString().c_str(), rProj.calcTime());
2343     std::ostringstream os;
2344     os << "Convert projection file " << GetFrame()->GetTitle().c_str() << " to FFT polar image: xSize=" 
2345       << m_iDefaultPolarNX << ", ySize=" << m_iDefaultPolarNY << ", interpolation=" 
2346       << strInterpolation.c_str() << ", zeropad=" << m_iDefaultPolarZeropad;
2347     *theApp->getLog() << os.str().c_str() << "\n";
2348     pIF->labelAdd (os.str().c_str());
2349     if (theApp->getAskDeleteNewDocs())
2350       pPolarDoc->Modify (true);
2351     pPolarDoc->UpdateAllViews ();
2352     pPolarDoc->getView()->OnUpdate (this, NULL);
2353     pPolarDoc->getView()->getFrame()->Show(true);
2354   }
2355 }
2356
2357 void
2358 ProjectionFileView::OnReconstructFourier (wxCommandEvent& event)
2359 {
2360   wxMessageBox ("Fourier Reconstruction is not yet supported", "Unimplemented function");
2361 }
2362
2363 void
2364 ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
2365 {
2366   DialogGetReconstructionParameters dialogReconstruction (getFrameForChild(), m_iDefaultNX, m_iDefaultNY, 
2367     m_iDefaultFilter, m_dDefaultFilterParam, m_iDefaultFilterMethod, m_iDefaultFilterGeneration, 
2368     m_iDefaultZeropad, m_iDefaultInterpolation, m_iDefaultInterpParam, m_iDefaultBackprojector, 
2369     m_iDefaultTrace);
2370   
2371   int retVal = dialogReconstruction.ShowModal();
2372   if (retVal == wxID_OK) {
2373     m_iDefaultNX = dialogReconstruction.getXSize();
2374     m_iDefaultNY = dialogReconstruction.getYSize();
2375     wxString optFilterName = dialogReconstruction.getFilterName();
2376     m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
2377     m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
2378     wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
2379     m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
2380     m_iDefaultZeropad = dialogReconstruction.getZeropad();
2381     wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
2382     m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
2383     wxString optInterpName = dialogReconstruction.getInterpName();
2384     m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
2385     m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
2386     wxString optBackprojectName = dialogReconstruction.getBackprojectName();
2387     m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
2388     m_iDefaultTrace = dialogReconstruction.getTrace();
2389     
2390     if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
2391       const Projections& rProj = GetDocument()->getProjections();
2392       std::ostringstream os;
2393       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();
2394       
2395       Timer timerRecon;
2396       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
2397         ImageFile* pImageFile = new ImageFile;
2398         pImageFile->setArraySize (m_iDefaultNX, m_iDefaultNY);
2399         Reconstructor* pReconstructor = new Reconstructor (rProj, *pImageFile, optFilterName.c_str(), 
2400           m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
2401           optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace);
2402         
2403         ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstructor, rProj, *pImageFile, m_iDefaultTrace, getFrameForChild());
2404         for (int iView = 0; iView < rProj.nView(); iView++) {
2405           ::wxYield();
2406           if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView, true)) {
2407             delete pDlgReconstruct;
2408             delete pReconstructor;
2409             delete pImageFile;
2410             return;
2411           }
2412           ::wxYield();
2413           ::wxYield();
2414           while (pDlgReconstruct->isPaused()) {
2415             ::wxYield();
2416             ::wxUsleep(50);
2417           }
2418         }
2419         pReconstructor->postProcessing();
2420         delete pDlgReconstruct;
2421         delete pReconstructor;
2422         ImageFileDocument* pReconDoc = theApp->newImageDoc();
2423         if (! pReconDoc) {
2424           sys_error (ERR_SEVERE, "Unable to create image file");
2425           return;
2426         }
2427         pReconDoc->setImageFile (pImageFile);
2428         if (theApp->getAskDeleteNewDocs())
2429           pReconDoc->Modify (true);
2430         pReconDoc->UpdateAllViews (this);
2431         if (ImageFileView* rasterView = pReconDoc->getView()) {
2432           rasterView->OnUpdate (rasterView, NULL);
2433           rasterView->getFrame()->SetFocus();
2434           rasterView->getFrame()->Show(true);
2435         }
2436         *theApp->getLog() << os.str().c_str() << "\n";
2437         pImageFile->labelAdd (rProj.getLabel());
2438         pImageFile->labelAdd (os.str().c_str(), timerRecon.timerEnd());
2439         
2440       } else {
2441         if (theApp->getUseBackgroundTasks() || theApp->getNumberCPU() > 1) {
2442           ReconstructorSupervisorThread* pReconstructor = new ReconstructorSupervisorThread (this, 
2443             m_iDefaultNX, m_iDefaultNY, optFilterName.c_str(), 
2444             m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
2445             optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), os.str().c_str());
2446           if (pReconstructor->Create() != wxTHREAD_NO_ERROR) {
2447             sys_error (ERR_SEVERE, "Error creating reconstructor thread");
2448             delete pReconstructor;
2449             return;
2450           }
2451 //          pReconstructor->SetPriority (60);
2452           pReconstructor->Run();
2453         } else {
2454           ImageFile* pImageFile = new ImageFile;
2455           pImageFile->setArraySize (m_iDefaultNX, m_iDefaultNY);
2456           Reconstructor* pReconstructor = new Reconstructor (rProj, *pImageFile, optFilterName.c_str(), 
2457             m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
2458             optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace);
2459           
2460           wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, getFrameForChild(), wxPD_CAN_ABORT );
2461           for (int iView = 0; iView < rProj.nView(); iView++) {
2462             pReconstructor->reconstructView (iView, 1);
2463             if (! dlgProgress.Update (iView + 1)) {
2464               delete pReconstructor;
2465               delete pImageFile;
2466               return;
2467             }
2468           }
2469           pReconstructor->postProcessing();
2470           delete pReconstructor;
2471           ImageFileDocument* pReconDoc = theApp->newImageDoc();
2472           if (! pReconDoc) {
2473             sys_error (ERR_SEVERE, "Unable to create image file");
2474             return;
2475           }
2476           pReconDoc->setImageFile (pImageFile);
2477           if (theApp->getAskDeleteNewDocs())
2478             pReconDoc->Modify (true);
2479           pReconDoc->UpdateAllViews (this);
2480           if (ImageFileView* rasterView = pReconDoc->getView()) {
2481             rasterView->OnUpdate (rasterView, NULL);
2482             rasterView->getFrame()->SetFocus();
2483             rasterView->getFrame()->Show(true);
2484           }
2485           *theApp->getLog() << os.str().c_str() << "\n";
2486           pImageFile->labelAdd (rProj.getLabel());
2487           pImageFile->labelAdd (os.str().c_str(), timerRecon.timerEnd());
2488         }
2489       }
2490     }
2491   }
2492 }
2493
2494
2495 ProjectionFileCanvas* 
2496 ProjectionFileView::CreateCanvas (wxFrame *parent)
2497 {
2498   ProjectionFileCanvas* pCanvas;
2499   int width, height;
2500   parent->GetClientSize(&width, &height);
2501   
2502   pCanvas = new ProjectionFileCanvas (this, parent, wxPoint(0, 0), wxSize(width, height), 0);
2503   
2504   pCanvas->SetScrollbars(20, 20, 50, 50);
2505   pCanvas->SetBackgroundColour(*wxWHITE);
2506   pCanvas->Clear();
2507   
2508   return pCanvas;
2509 }
2510
2511 #if CTSIM_MDI
2512 wxDocMDIChildFrame*
2513 #else
2514 wxDocChildFrame*
2515 #endif
2516 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
2517 {
2518 #ifdef CTSIM_MDI
2519   wxDocMDIChildFrame *subframe = new wxDocMDIChildFrame (doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
2520 #else
2521   wxDocChildFrame *subframe = new wxDocChildFrame (doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
2522 #endif
2523   theApp->setIconForFrame (subframe);
2524   
2525   m_pFileMenu = new wxMenu;
2526   
2527   m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P");
2528   m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F");
2529   m_pFileMenu->Append(wxID_OPEN, "&Open...\tCtrl-O");
2530   m_pFileMenu->Append(wxID_SAVE, "&Save\tCtrl-S");
2531   m_pFileMenu->Append(wxID_SAVEAS, "Save &As...");
2532   m_pFileMenu->Append(wxID_CLOSE, "&Close\tCtrl-W");
2533   
2534   m_pFileMenu->AppendSeparator();
2535   m_pFileMenu->Append(PJMENU_FILE_PROPERTIES, "P&roperties\tCtrl-I");
2536   
2537   m_pFileMenu->AppendSeparator();
2538   m_pFileMenu->Append(wxID_PRINT, "&Print...");
2539   m_pFileMenu->Append(wxID_PRINT_SETUP, "Print &Setup...");
2540   m_pFileMenu->Append(wxID_PREVIEW, "Print Pre&view");
2541 #ifdef CTSIM_MDI
2542   m_pFileMenu->AppendSeparator();
2543   m_pFileMenu->Append (MAINMENU_FILE_PREFERENCES, "Prefere&nces...");
2544   m_pFileMenu->Append(MAINMENU_FILE_EXIT, "E&xit");
2545 #endif
2546   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
2547   GetDocumentManager()->FileHistoryUseMenu(m_pFileMenu);
2548   
2549   wxMenu *convert_menu = new wxMenu;
2550   convert_menu->Append (PJMENU_CONVERT_POLAR, "&Polar Image...\tCtrl-L");
2551   convert_menu->Append (PJMENU_CONVERT_FFT_POLAR, "&FFT->Polar Image...\tCtrl-M");
2552   
2553   wxMenu *reconstruct_menu = new wxMenu;
2554   reconstruct_menu->Append (PJMENU_RECONSTRUCT_FBP, "&Filtered Backprojection...\tCtrl-R", "Reconstruct image using filtered backprojection");
2555   reconstruct_menu->Append (PJMENU_RECONSTRUCT_FOURIER, "&Fourier...\tCtrl-E", "Reconstruct image using inverse Fourier");
2556   reconstruct_menu->Enable (PJMENU_RECONSTRUCT_FOURIER, false);
2557   
2558   wxMenu *help_menu = new wxMenu;
2559   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
2560   help_menu->Append (MAINMENU_HELP_TIPS, "&Tips");
2561   help_menu->Append (IDH_QUICKSTART, "&Quick Start");
2562   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
2563   
2564   wxMenuBar *menu_bar = new wxMenuBar;
2565   
2566   menu_bar->Append (m_pFileMenu, "&File");
2567   menu_bar->Append (convert_menu, "&Convert");
2568   menu_bar->Append (reconstruct_menu, "&Reconstruct");
2569   menu_bar->Append (help_menu, "&Help");
2570   
2571   subframe->SetMenuBar(menu_bar);  
2572   subframe->Centre(wxBOTH);
2573   
2574   wxAcceleratorEntry accelEntries[5];
2575   accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('L'), PJMENU_CONVERT_POLAR);
2576   accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('M'), PJMENU_CONVERT_FFT_POLAR);
2577   accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('R'), PJMENU_RECONSTRUCT_FBP);
2578   accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('E'), PJMENU_RECONSTRUCT_FOURIER);
2579   accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('I'), PJMENU_FILE_PROPERTIES);
2580   wxAcceleratorTable accelTable (5, accelEntries);
2581   subframe->SetAcceleratorTable (accelTable);
2582   
2583   return subframe;
2584 }
2585
2586
2587 bool 
2588 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
2589 {
2590   m_pFrame = CreateChildFrame(doc, this);
2591   SetFrame(m_pFrame);
2592   
2593   int width, height;
2594   m_pFrame->GetClientSize (&width, &height);
2595   m_pFrame->SetTitle ("ProjectionFileView");
2596   m_pCanvas = CreateCanvas (m_pFrame);
2597   
2598 #ifdef __X__
2599   int x, y;  // X requires a forced resize
2600   m_pFrame->GetSize(&x, &y);
2601   m_pFrame->SetSize(-1, -1, x, y);
2602 #endif
2603   
2604   m_pFrame->Show(true);
2605   Activate(true);
2606   
2607   return true;
2608 }
2609
2610 void 
2611 ProjectionFileView::OnDraw (wxDC* dc)
2612 {
2613   wxSize clientSize = m_pFrame->GetClientSize();
2614   wxSize bestSize = m_pCanvas->GetBestSize();
2615   
2616   if (clientSize.x > bestSize.x || clientSize.y > bestSize.y)
2617     m_pFrame->SetClientSize (bestSize);
2618   
2619   if (m_bitmap.Ok())
2620     dc->DrawBitmap (m_bitmap, 0, 0, false);
2621 }
2622
2623
2624 void 
2625 ProjectionFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
2626 {
2627   const Projections& rProj = GetDocument()->getProjections();
2628   const int nDet = rProj.nDet();
2629   const int nView = rProj.nView();
2630   if (nDet != 0 && nView != 0) {
2631     const DetectorArray& detarray = rProj.getDetectorArray(0);
2632     const DetectorValue* detval = detarray.detValues();
2633     double min = detval[0];
2634     double max = detval[0];
2635     for (int iy = 0; iy < nView; iy++) {
2636       const DetectorArray& detarray = rProj.getDetectorArray(iy);
2637       const DetectorValue* detval = detarray.detValues();
2638       for (int ix = 0; ix < nDet; ix++) {
2639         if (min > detval[ix])
2640           min = detval[ix];
2641         else if (max < detval[ix])
2642           max = detval[ix];
2643       }
2644     }
2645     
2646     unsigned char* imageData = new unsigned char [nDet * nView * 3];
2647     if (! imageData) {
2648       sys_error (ERR_SEVERE, "Unable to allocate memory for image display");
2649       return;
2650     }
2651     double scale = (max - min) / 255;
2652     for (int iy2 = 0; iy2 < nView; iy2++) {
2653       const DetectorArray& detarray = rProj.getDetectorArray (iy2);
2654       const DetectorValue* detval = detarray.detValues();
2655       for (int ix = 0; ix < nDet; ix++) {
2656         int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
2657         intensity = clamp(intensity, 0, 255);
2658         int baseAddr = (iy2 * nDet + ix) * 3;
2659         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
2660       }
2661     }
2662     wxImage image (nDet, nView, imageData, true);
2663     m_bitmap = image.ConvertToBitmap();
2664     delete imageData;
2665     int xSize = nDet;
2666     int ySize = nView;
2667     xSize = clamp (xSize, 0, 800);
2668     ySize = clamp (ySize, 0, 800);
2669     m_pFrame->SetClientSize (xSize, ySize);
2670     m_pCanvas->SetScrollbars (20, 20, nDet/20, nView/20);
2671   }
2672   
2673   if (m_pCanvas)
2674     m_pCanvas->Refresh();
2675 }
2676
2677 bool 
2678 ProjectionFileView::OnClose (bool deleteWindow)
2679 {
2680   //GetDocumentManager()->ActivateView (this, false, true);
2681   if (! GetDocument() || ! GetDocument()->Close())
2682     return false;
2683   
2684   Activate(false);
2685   if (m_pCanvas) {
2686         m_pCanvas->setView(NULL);
2687     m_pCanvas = NULL;
2688   }
2689   wxString s(wxTheApp->GetAppName());
2690   if (m_pFrame)
2691     m_pFrame->SetTitle(s);
2692   
2693   SetFrame(NULL);
2694   
2695   if (deleteWindow) {
2696     delete m_pFrame;
2697     m_pFrame = NULL;
2698     if (GetDocument() && GetDocument()->getBadFileOpen())
2699       ::wxYield();  // wxWindows bug workaround
2700   }
2701   
2702   return true;
2703 }
2704
2705
2706
2707 // PlotFileCanvas
2708 PlotFileCanvas::PlotFileCanvas (PlotFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
2709 : wxScrolledWindow(frame, -1, pos, size, style)
2710 {
2711   m_pView = v;
2712 }
2713
2714 PlotFileCanvas::~PlotFileCanvas ()
2715 {
2716   m_pView = NULL;
2717 }
2718
2719 void 
2720 PlotFileCanvas::OnDraw(wxDC& dc)
2721 {
2722   if (m_pView)
2723     m_pView->OnDraw(& dc);
2724 }
2725
2726
2727 // PlotFileView
2728
2729 IMPLEMENT_DYNAMIC_CLASS(PlotFileView, wxView)
2730
2731 BEGIN_EVENT_TABLE(PlotFileView, wxView)
2732 EVT_MENU(PLOTMENU_FILE_PROPERTIES, PlotFileView::OnProperties)
2733 EVT_MENU(PLOTMENU_VIEW_SCALE_MINMAX, PlotFileView::OnScaleMinMax)
2734 EVT_MENU(PLOTMENU_VIEW_SCALE_AUTO, PlotFileView::OnScaleAuto)
2735 EVT_MENU(PLOTMENU_VIEW_SCALE_FULL, PlotFileView::OnScaleFull)
2736 END_EVENT_TABLE()
2737
2738 PlotFileView::PlotFileView() 
2739 : wxView(), m_pFrame(NULL), m_pCanvas(NULL), m_pEZPlot(NULL), m_pFileMenu(0), m_bMinSpecified(false), m_bMaxSpecified(false)
2740 {
2741 }
2742
2743 PlotFileView::~PlotFileView()
2744 {
2745   if (m_pEZPlot)
2746     delete m_pEZPlot;
2747   
2748   GetDocumentManager()->FileHistoryRemoveMenu (m_pFileMenu);  
2749 }
2750
2751 void
2752 PlotFileView::OnProperties (wxCommandEvent& event)
2753 {
2754   const PlotFile& rPlot = GetDocument()->getPlotFile();
2755   std::ostringstream os;
2756   os << "Columns: " << rPlot.getNumColumns() << ", Records: " << rPlot.getNumRecords() << "\n";
2757   rPlot.printHeadersBrief (os);
2758   *theApp->getLog() << ">>>>\n" << os.str().c_str() << "<<<<<\n";
2759   wxMessageDialog dialogMsg (getFrameForChild(), os.str().c_str(), "Plot File Properties", wxOK | wxICON_INFORMATION);
2760   dialogMsg.ShowModal();
2761 }
2762
2763
2764 void 
2765 PlotFileView::OnScaleAuto (wxCommandEvent& event)
2766 {
2767   const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2768   double min, max, mean, mode, median, stddev;
2769   rPlotFile.statistics (1, min, max, mean, mode, median, stddev);
2770   DialogAutoScaleParameters dialogAutoScale (getFrameForChild(), mean, mode, median, stddev, m_dAutoScaleFactor);
2771   int iRetVal = dialogAutoScale.ShowModal();
2772   if (iRetVal == wxID_OK) {
2773     m_bMinSpecified = true;
2774     m_bMaxSpecified = true;
2775     double dMin, dMax;
2776     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {
2777       m_dMinPixel = dMin;
2778       m_dMaxPixel = dMax;
2779       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
2780       OnUpdate (this, NULL);
2781     }
2782   }
2783 }
2784
2785 void 
2786 PlotFileView::OnScaleMinMax (wxCommandEvent& event)
2787 {
2788   const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2789   double min;
2790   double max;
2791   
2792   if (! m_bMinSpecified || ! m_bMaxSpecified) {
2793     if (! rPlotFile.getMinMax (1, min, max)) {
2794       *theApp->getLog() << "Error: unable to find Min/Max\n";
2795       return;
2796     }
2797   }
2798   
2799   if (m_bMinSpecified)
2800     min = m_dMinPixel;
2801   if (m_bMaxSpecified)
2802     max = m_dMaxPixel;
2803   
2804   DialogGetMinMax dialogMinMax (getFrameForChild(), "Set Y-axis Minimum & Maximum", min, max);
2805   int retVal = dialogMinMax.ShowModal();
2806   if (retVal == wxID_OK) {
2807     m_bMinSpecified = true;
2808     m_bMaxSpecified = true;
2809     m_dMinPixel = dialogMinMax.getMinimum();
2810     m_dMaxPixel = dialogMinMax.getMaximum();
2811     OnUpdate (this, NULL);
2812   }
2813 }
2814
2815 void 
2816 PlotFileView::OnScaleFull (wxCommandEvent& event)
2817 {
2818   if (m_bMinSpecified || m_bMaxSpecified) {
2819     m_bMinSpecified = false;
2820     m_bMaxSpecified = false;
2821     OnUpdate (this, NULL);
2822   }
2823 }
2824
2825
2826 PlotFileCanvas* 
2827 PlotFileView::CreateCanvas (wxFrame* parent)
2828 {
2829   PlotFileCanvas* pCanvas;
2830   int width, height;
2831   parent->GetClientSize(&width, &height);
2832   
2833   pCanvas = new PlotFileCanvas (this, parent, wxPoint(0, 0), wxSize(width, height), 0);
2834   
2835   pCanvas->SetBackgroundColour(*wxWHITE);
2836   pCanvas->Clear();
2837   
2838   return pCanvas;
2839 }
2840
2841 #if CTSIM_MDI
2842 wxDocMDIChildFrame*
2843 #else
2844 wxDocChildFrame*
2845 #endif
2846 PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
2847 {
2848 #ifdef CTSIM_MDI
2849   wxDocMDIChildFrame *subframe = new wxDocMDIChildFrame (doc, view, theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
2850 #else
2851   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
2852 #endif
2853   theApp->setIconForFrame (subframe);
2854   
2855   m_pFileMenu = new wxMenu;
2856   
2857   m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P");
2858   m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F");
2859   m_pFileMenu->Append(wxID_OPEN, "&Open...\tCtrl-O");
2860   m_pFileMenu->Append(wxID_SAVE, "&Save\tCtrl-S");
2861   m_pFileMenu->Append(wxID_SAVEAS, "Save &As...");
2862   m_pFileMenu->Append(wxID_CLOSE, "&Close\tCtrl-W");
2863   
2864   m_pFileMenu->AppendSeparator();
2865   m_pFileMenu->Append(PLOTMENU_FILE_PROPERTIES, "P&roperties\tCtrl-I");
2866   
2867   m_pFileMenu->AppendSeparator();
2868   m_pFileMenu->Append(wxID_PRINT, "&Print...");
2869   m_pFileMenu->Append(wxID_PRINT_SETUP, "Print &Setup...");
2870   m_pFileMenu->Append(wxID_PREVIEW, "Print Pre&view");
2871 #ifdef CTSIM_MDI
2872   m_pFileMenu->AppendSeparator();
2873   m_pFileMenu->Append (MAINMENU_FILE_PREFERENCES, "Prefere&nces...");
2874   m_pFileMenu->Append(MAINMENU_FILE_EXIT, "E&xit");
2875 #endif
2876   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
2877   GetDocumentManager()->FileHistoryUseMenu(m_pFileMenu);
2878   
2879   wxMenu *view_menu = new wxMenu;
2880   view_menu->Append(PLOTMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...\tCtrl-E");
2881   view_menu->Append(PLOTMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...\tCtrl-A");
2882   view_menu->Append(PLOTMENU_VIEW_SCALE_FULL, "Display &Full Scale\tCtrl-U");
2883   
2884   wxMenu *help_menu = new wxMenu;
2885   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
2886   help_menu->Append (MAINMENU_HELP_TIPS, "&Tips");
2887   help_menu->Append (IDH_QUICKSTART, "&Quick Start");
2888   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
2889   
2890   wxMenuBar *menu_bar = new wxMenuBar;
2891   
2892   menu_bar->Append(m_pFileMenu, "&File");
2893   menu_bar->Append(view_menu, "&View");
2894   menu_bar->Append(help_menu, "&Help");
2895   
2896   subframe->SetMenuBar(menu_bar);
2897   subframe->Centre(wxBOTH);
2898   
2899   wxAcceleratorEntry accelEntries[4];
2900   accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('E'), PLOTMENU_VIEW_SCALE_MINMAX);
2901   accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('A'), PLOTMENU_VIEW_SCALE_AUTO);
2902   accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('U'), PLOTMENU_VIEW_SCALE_FULL);
2903   accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('I'), PLOTMENU_FILE_PROPERTIES);
2904   wxAcceleratorTable accelTable (4, accelEntries);
2905   subframe->SetAcceleratorTable (accelTable);
2906   
2907   return subframe;
2908 }
2909
2910
2911 bool 
2912 PlotFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
2913 {
2914   m_pFrame = CreateChildFrame(doc, this);
2915   SetFrame(m_pFrame);
2916   
2917   m_bMinSpecified = false;
2918   m_bMaxSpecified = false;
2919   m_dAutoScaleFactor = 1.;
2920   
2921   int width, height;
2922   m_pFrame->GetClientSize(&width, &height);
2923   m_pFrame->SetTitle ("Plot File");
2924   m_pCanvas = CreateCanvas (m_pFrame);
2925   
2926 #ifdef __X__
2927   int x, y;  // X requires a forced resize
2928   m_pFrame->GetSize(&x, &y);
2929   m_pFrame->SetSize(-1, -1, x, y);
2930 #endif
2931   
2932   m_pFrame->Show(true);
2933   Activate(true);
2934   
2935   return true;
2936 }
2937
2938 void 
2939 PlotFileView::OnDraw (wxDC* dc)
2940 {
2941   const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2942   const int iNColumns = rPlotFile.getNumColumns();
2943   const int iNRecords = rPlotFile.getNumRecords();
2944   
2945   if (iNColumns > 0 && iNRecords > 0) {
2946     int xsize, ysize;
2947     m_pCanvas->GetClientSize (&xsize, &ysize);
2948     SGPDriver driver (dc, xsize, ysize);
2949     SGP sgp (driver);
2950     if (m_pEZPlot)
2951       m_pEZPlot->plot (&sgp);
2952   }
2953 }
2954
2955
2956 void 
2957 PlotFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
2958 {
2959   const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2960   const int iNColumns = rPlotFile.getNumColumns();
2961   const int iNRecords = rPlotFile.getNumRecords();
2962   
2963   if (iNColumns > 0 && iNRecords > 0) {
2964     if (m_pEZPlot)
2965       delete m_pEZPlot;
2966     m_pEZPlot = new EZPlot;
2967     
2968     for (unsigned int iEzset = 0; iEzset < rPlotFile.getNumEzsetCommands(); iEzset++)
2969       m_pEZPlot->ezset (rPlotFile.getEzsetCommand (iEzset));
2970     
2971     if (m_bMinSpecified) {
2972       std::ostringstream os;
2973       os << "ymin " << m_dMinPixel;
2974       m_pEZPlot->ezset (os.str());
2975     }
2976     
2977     if (m_bMaxSpecified) {
2978       std::ostringstream os;
2979       os << "ymax " << m_dMaxPixel;
2980       m_pEZPlot->ezset (os.str());
2981     }
2982     
2983     m_pEZPlot->ezset("box");
2984     m_pEZPlot->ezset("grid");
2985     
2986     double* pdXaxis = new double [iNRecords];
2987     rPlotFile.getColumn (0, pdXaxis);
2988     
2989     double* pdY = new double [iNRecords];
2990     for (int iCol = 1; iCol < iNColumns; iCol++) {
2991       rPlotFile.getColumn (iCol, pdY);
2992       m_pEZPlot->addCurve (pdXaxis, pdY, iNRecords);
2993     }
2994     
2995     delete pdXaxis;
2996     delete pdY;
2997   }
2998   
2999   if (m_pCanvas)
3000     m_pCanvas->Refresh();
3001 }
3002
3003 bool 
3004 PlotFileView::OnClose (bool deleteWindow)
3005 {
3006   //GetDocumentManager()->ActivateView (this, false, true);
3007   if (! GetDocument() || ! GetDocument()->Close())
3008     return false;
3009   
3010   Activate(false);
3011   if (m_pCanvas) {
3012     m_pCanvas->setView (NULL);
3013     m_pCanvas = NULL;
3014   }
3015   wxString s(wxTheApp->GetAppName());
3016   if (m_pFrame)
3017     m_pFrame->SetTitle(s);
3018   
3019   SetFrame(NULL);
3020   if (deleteWindow) {
3021     delete m_pFrame;
3022     m_pFrame = NULL;
3023     if (GetDocument() && GetDocument()->getBadFileOpen())
3024       ::wxYield();  // wxWindows bug workaround
3025   }
3026   
3027   return true;
3028 }
3029
3030
3031 ////////////////////////////////////////////////////////////////
3032
3033
3034 IMPLEMENT_DYNAMIC_CLASS(TextFileView, wxView)
3035
3036 TextFileView::~TextFileView() 
3037 {
3038   GetDocumentManager()->FileHistoryRemoveMenu (m_pFileMenu);
3039   GetDocumentManager()->ActivateView(this, FALSE, TRUE);;
3040 }
3041
3042 bool TextFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
3043 {
3044   m_pFrame = CreateChildFrame(doc, this);
3045   SetFrame (m_pFrame);
3046   
3047   int width, height;
3048   m_pFrame->GetClientSize(&width, &height);
3049   m_pFrame->SetTitle("TextFile");
3050   m_pCanvas = new TextFileCanvas (this, m_pFrame, wxPoint(0, 0), wxSize(width, height), wxTE_MULTILINE | wxTE_READONLY);
3051   m_pFrame->SetTitle("Log");
3052   
3053 #ifdef __X__
3054   // X seems to require a forced resize
3055   int x, y;
3056   frame->GetSize(&x, &y);
3057   frame->SetSize(-1, -1, x, y);
3058 #endif
3059   
3060   m_pFrame->Show (true);
3061   Activate (true);
3062   
3063   return true;
3064 }
3065
3066 // Handled by wxTextWindow
3067 void TextFileView::OnDraw(wxDC *WXUNUSED(dc) )
3068 {
3069 }
3070
3071 void TextFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
3072 {
3073 }
3074
3075 bool 
3076 TextFileView::OnClose (bool deleteWindow)
3077 {
3078   if (! theApp->getMainFrame()->getShuttingDown())
3079     return false;
3080   
3081   Activate(false);
3082   //GetDocumentManager()->ActivateView (this, false, true);
3083   if (! GetDocument() || ! GetDocument()->Close())
3084     return false;
3085   
3086   SetFrame(NULL);
3087   if (deleteWindow) {
3088     delete m_pFrame;
3089     m_pFrame = NULL;
3090     if (GetDocument() && GetDocument()->getBadFileOpen())
3091       ::wxYield();  // wxWindows bug workaround
3092   }
3093   
3094   return TRUE;
3095 }
3096
3097 #if CTSIM_MDI
3098 wxDocMDIChildFrame*
3099 #else
3100 wxDocChildFrame*
3101 #endif
3102 TextFileView::CreateChildFrame (wxDocument *doc, wxView *view)
3103 {
3104 #if CTSIM_MDI
3105   wxDocMDIChildFrame* subframe = new wxDocMDIChildFrame (doc, view, theApp->getMainFrame(), -1, "TextFile Frame", wxPoint(-1, -1), wxSize(0,0), wxDEFAULT_FRAME_STYLE, "Log");
3106 #else
3107   wxDocChildFrame* subframe = new wxDocChildFrame (doc, view, theApp->getMainFrame(), -1, "TextFile Frame", wxPoint(-1, -1), wxSize(300, 150), wxDEFAULT_FRAME_STYLE, "Log");
3108 #endif
3109   theApp->setIconForFrame (subframe);
3110   
3111   m_pFileMenu = new wxMenu;
3112   
3113   m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P");
3114   m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F");
3115   m_pFileMenu->Append(wxID_OPEN, "&Open...\tCtrl-O");
3116   m_pFileMenu->Append(wxID_SAVE, "&Save\tCtrl-S");
3117   m_pFileMenu->Append(wxID_SAVEAS, "Save &As...");
3118   //  m_pFileMenu->Append(wxID_CLOSE, "&Close\tCtrl-W");
3119   
3120   m_pFileMenu->AppendSeparator();
3121   m_pFileMenu->Append(wxID_PRINT, "&Print...");
3122   m_pFileMenu->Append(wxID_PRINT_SETUP, "Print &Setup...");
3123   m_pFileMenu->Append(wxID_PREVIEW, "Print Pre&view");
3124 #ifdef CTSIM_MDI
3125   m_pFileMenu->AppendSeparator();
3126   m_pFileMenu->Append (MAINMENU_FILE_PREFERENCES, "Prefere&nces...");
3127   m_pFileMenu->Append(MAINMENU_FILE_EXIT, "E&xit");
3128 #endif
3129   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
3130   GetDocumentManager()->FileHistoryUseMenu(m_pFileMenu);
3131   
3132   wxMenu *help_menu = new wxMenu;
3133   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
3134   help_menu->Append (MAINMENU_HELP_TIPS, "&Tips");
3135   help_menu->Append (IDH_QUICKSTART, "&Quick Start");
3136   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
3137   
3138   wxMenuBar *menu_bar = new wxMenuBar;
3139   
3140   menu_bar->Append(m_pFileMenu, "&File");
3141   menu_bar->Append(help_menu, "&Help");
3142   
3143   subframe->SetMenuBar(menu_bar);
3144   subframe->Centre(wxBOTH);
3145   
3146   return subframe;
3147 }
3148
3149
3150 // Define a constructor for my text subwindow
3151 TextFileCanvas::TextFileCanvas (TextFileView* v, wxFrame* frame, const wxPoint& pos, const wxSize& size, long style)
3152 : wxTextCtrl (frame, -1, "", pos, size, style), m_pView(v)
3153 {
3154 }
3155
3156 TextFileCanvas::~TextFileCanvas ()
3157 {
3158   m_pView = NULL;
3159 }