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