r153: *** empty log message ***
[ctsim.git] / src / views.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   Name:          view.cpp
5 **   Purpose:       View & Canvas routines for CTSim program
6 **   Programmer:    Kevin Rosenberg
7 **   Date Started:  July 2000
8 **
9 **  This is part of the CTSim program
10 **  Copyright (C) 1983-2000 Kevin Rosenberg
11 **
12 **  $Id: views.cpp,v 1.4 2000/07/18 14:51:06 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 #ifdef __GNUG__
29 // #pragma implementation
30 #endif
31
32 // For compilers that support precompilation, includes "wx/wx.h".
33 #include "wx/wxprec.h"
34
35 #ifdef __BORLANDC__
36 #pragma hdrstop
37 #endif
38
39 #ifndef WX_PRECOMP
40 #include "wx/wx.h"
41 #endif
42
43 #if !wxUSE_DOC_VIEW_ARCHITECTURE
44 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h!
45 #endif
46
47 #include "wx/image.h"
48
49 #include "ct.h"
50 #include "ctsim.h"
51 #include "docs.h"
52 #include "views.h"
53 #include "dialogs.h"
54 #include <sstream>
55
56 // ImageFileCanvas
57
58 BEGIN_EVENT_TABLE(ImageFileCanvas, wxScrolledWindow)
59     EVT_MOUSE_EVENTS(ImageFileCanvas::OnMouseEvent)
60 END_EVENT_TABLE()
61
62
63 ImageFileCanvas::ImageFileCanvas (ImageFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
64   : wxScrolledWindow(frame, -1, pos, size, style)
65 {
66     m_pView = v;
67 }
68
69 void 
70 ImageFileCanvas::OnDraw(wxDC& dc)
71 {
72     if (m_pView)
73         m_pView->OnDraw(& dc);
74 }
75
76 void 
77 ImageFileCanvas::OnMouseEvent(wxMouseEvent& event)
78 {
79     if (! m_pView)
80         return;
81     
82     wxClientDC dc(this);
83     PrepareDC(dc);
84     
85     wxPoint pt(event.GetLogicalPosition(dc));
86
87     if (event.LeftIsDown()) {
88         const ImageFile& rIF = m_pView->GetDocument()->getImageFile();
89         ImageFileArrayConst v = rIF.getArray();
90         int nx = rIF.nx();
91         int ny = rIF.ny();
92
93         if (pt.x >= 0 && pt.x < nx && pt.y >= 0 & pt.y < ny) {
94           ostringstream os;
95           os << "Image value (" << pt.x << "," << pt.y << ") = " << v[pt.x][pt.y] << "\n";
96             *theApp->getLog() << os.str().c_str();
97         } else
98             *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << pt.y << ")\n";
99             
100     }
101 }
102
103
104 // ImageFileView
105
106 IMPLEMENT_DYNAMIC_CLASS(ImageFileView, wxView)
107
108 BEGIN_EVENT_TABLE(ImageFileView, wxView)
109   EVT_MENU(IFMENU_FILE_PROPERTIES, ImageFileView::OnProperties)
110   EVT_MENU(IFMENU_VIEW_WINDOW_MINMAX, ImageFileView::OnWindowMinMax)
111   EVT_MENU(IFMENU_VIEW_WINDOW_AUTO, ImageFileView::OnWindowAuto)
112 END_EVENT_TABLE()
113
114 ImageFileView::ImageFileView(void) 
115   : wxView(), m_canvas(NULL), m_frame(NULL), m_bMinSpecified(false), m_bMaxSpecified(false)
116 {
117 }
118
119 ImageFileView::~ImageFileView(void)
120 {
121 }
122
123 void
124 ImageFileView::OnProperties (wxCommandEvent& event)
125 {
126   double min, max, mean, mode, median, stddev;
127   const ImageFile& rIF = GetDocument()->getImageFile();
128   if (rIF.nx() == 0 || rIF.ny() == 0)
129     *theApp->getLog() << "Properties: empty imagefile\n";
130   else {
131     const string& rFilename = rIF.getFilename();
132     rIF.statistics (min, max, mean, mode, median, stddev);
133     ostringstream os;
134     os << "file: " << rFilename << "\nmin: "<<min<<"\nmax: "<<max<<"\nmean: "<<mean<<"\nmode: "<<mode<<"\nstddev: "<<stddev << "\n";
135     *theApp->getLog() << os.str().c_str();
136
137     int xSize, ySize;
138     ostringstream osSize;
139     m_frame->GetSize (&xSize, &ySize);
140     osSize << "Frame size: (" << xSize << "," << ySize << ")\n";
141     m_frame->GetClientSize (&xSize, &ySize);
142     osSize << "Frame Client size: (" << xSize << "," << ySize << ")\n";
143     m_canvas->GetSize (&xSize, &ySize);
144     osSize << "Canvas size: (" << xSize << "," << ySize << ")\n";
145     *theApp->getLog() << osSize.str().c_str();
146   }
147 }
148
149 void 
150 ImageFileView::OnWindowAuto (wxCommandEvent& event)
151 {
152     *theApp->getLog() << "ImageFile: Window Auto\n";
153 }
154
155 void 
156 ImageFileView::OnWindowMinMax (wxCommandEvent& event)
157 {
158     const ImageFile& rIF = GetDocument()->getImageFile();
159     double min, max;
160     if (! m_bMinSpecified && ! m_bMaxSpecified)
161       rIF.getMinMax (min, max);
162
163     if (m_bMinSpecified)
164       min = m_dMinPixel;
165     if (m_bMaxSpecified)
166       max = m_dMaxPixel;
167
168     DialogGetImageMinMax dialogMinMax (m_frame, rIF, min, max);
169     int retVal = dialogMinMax.ShowModal();
170     if (retVal == wxID_OK) {
171       m_bMinSpecified = true;
172       m_bMaxSpecified = true;
173       m_dMinPixel = dialogMinMax.getMinimum();
174       m_dMaxPixel = dialogMinMax.getMaximum();
175       OnUpdate (this, NULL);
176     }
177 }
178
179
180 ImageFileCanvas* 
181 ImageFileView::CreateCanvas (wxView *view, wxFrame *parent)
182 {
183     ImageFileCanvas* pCanvas;
184     int width, height;
185     parent->GetClientSize(&width, &height);
186     
187     pCanvas = new ImageFileCanvas (dynamic_cast<ImageFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
188     
189     pCanvas->SetScrollbars(20, 20, 50, 50);
190     pCanvas->SetBackgroundColour(*wxWHITE);
191     pCanvas->Clear();
192     
193     return pCanvas;
194 }
195
196 wxFrame*
197 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
198 {
199     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
200     
201     wxMenu *file_menu = new wxMenu;
202     
203     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "&Create Phantom...");
204     file_menu->Append(wxID_OPEN, "&Open...");
205     file_menu->Append(wxID_CLOSE, "&Close");
206     file_menu->Append(wxID_SAVE, "&Save");
207     file_menu->Append(wxID_SAVEAS, "Save &As...");
208     
209     file_menu->AppendSeparator();
210     file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
211
212     file_menu->AppendSeparator();
213     file_menu->Append(wxID_PRINT, "&Print...");
214     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
215     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
216     
217     wxMenu *view_menu = new wxMenu;
218     view_menu->Append(IFMENU_VIEW_WINDOW_MINMAX, "&Set Window Min/Max");
219     view_menu->Append(IFMENU_VIEW_WINDOW_AUTO, "&Auto Window...");
220     
221     wxMenu *help_menu = new wxMenu;
222     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
223     
224     wxMenuBar *menu_bar = new wxMenuBar;
225     
226     menu_bar->Append(file_menu, "&File");
227     menu_bar->Append(view_menu, "&View");
228     menu_bar->Append(help_menu, "&Help");
229     
230     subframe->SetMenuBar(menu_bar);
231     
232     subframe->Centre(wxBOTH);
233     
234     return subframe;
235 }
236
237
238 bool 
239 ImageFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
240 {
241     m_frame = CreateChildFrame(doc, this);
242     
243     m_bMinSpecified = false;
244     m_bMaxSpecified = false;
245
246     int width, height;
247     m_frame->GetClientSize(&width, &height);
248     m_frame->SetTitle("ImageFileView");
249     m_canvas = CreateCanvas(this, m_frame);
250
251 #ifdef __X__
252     int x, y;  // X requires a forced resize
253     m_frame->GetSize(&x, &y);
254     m_frame->SetSize(-1, -1, x, y);
255 #endif
256
257     m_frame->Show(true);
258     Activate(true);
259     
260     return true;
261 }
262
263 void 
264 ImageFileView::OnDraw (wxDC* dc)
265 {
266   if (m_bitmap.Ok())
267     dc->DrawBitmap(m_bitmap, 0, 0, false);
268 }
269
270
271 void 
272 ImageFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
273 {
274     const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
275     ImageFileArrayConst v = rIF.getArray();
276     int nx = rIF.nx();
277     int ny = rIF.ny();
278     if (v != NULL && nx != 0 && ny != 0) {
279         if (! m_bMinSpecified || ! m_bMaxSpecified) {
280             double min, max;
281             rIF.getMinMax (min, max);
282             if (! m_bMinSpecified)
283                 m_dMinPixel = min;
284             if (! m_bMaxSpecified)
285                 m_dMaxPixel = max;
286         }
287         double scaleWidth = m_dMaxPixel - m_dMinPixel;
288     
289         unsigned char* imageData = new unsigned char [nx * ny * 3];
290         for (int ix = 0; ix < nx; ix++) {
291             for (int iy = 0; iy < ny; iy++) {
292                 double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
293                 int intensity = static_cast<int>(scaleValue + 0.5);
294                 intensity = clamp (intensity, 0, 255);
295                 int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
296                 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
297             }
298         }
299         wxImage image (ny, nx, imageData, true);
300         m_bitmap = image.ConvertToBitmap();
301         delete imageData;
302         int xSize = nx;
303         int ySize = ny;
304         xSize = clamp (xSize, 0, 800);
305         ySize = clamp (ySize, 0, 800);
306         m_frame->SetClientSize (xSize, ySize);
307         m_canvas->SetScrollbars(20, 20, nx/20, ny/20);
308         m_canvas->SetBackgroundColour(*wxWHITE);
309     } 
310
311     if (m_canvas)
312         m_canvas->Refresh();
313 }
314
315 bool 
316 ImageFileView::OnClose (bool deleteWindow)
317 {
318     if (!GetDocument()->Close())
319         return false;
320
321     m_canvas->Clear();
322     m_canvas->m_pView = NULL;
323     m_canvas = NULL;
324     wxString s(theApp->GetAppName());
325     if (m_frame)
326       m_frame->SetTitle(s);
327     SetFrame(NULL);
328
329     Activate(false);
330     
331     if (deleteWindow) {
332         delete m_frame;
333         return true;
334     }
335     return true;
336 }
337
338
339
340 // PhantomCanvas
341
342 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
343   : wxPanel(frame, -1, pos, size, style)
344 {
345     m_pView = v;
346 }
347
348 void 
349 PhantomCanvas::OnDraw(wxDC& dc)
350 {
351     if (m_pView)
352         m_pView->OnDraw(& dc);
353 }
354
355 // PhantomView
356
357 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
358
359 BEGIN_EVENT_TABLE(PhantomView, wxView)
360     EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
361     EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
362     EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
363 END_EVENT_TABLE()
364
365 PhantomView::PhantomView(void) 
366   : wxView(), m_canvas(NULL), m_frame(NULL)
367 {
368 }
369
370 PhantomView::~PhantomView(void)
371 {
372 }
373
374 void
375 PhantomView::OnProperties (wxCommandEvent& event)
376 {
377   const Phantom::PhantomID idPhantom = GetDocument()->getPhantomID();
378   const string& namePhantom = GetDocument()->getPhantomName();
379   ostringstream os;
380   os << "Phantom " << namePhantom << " (" << static_cast<int>(idPhantom) << ")\n";
381   *theApp->getLog() << os.str().c_str();
382 #if DEBUG
383   const Phantom& rPhantom = GetDocument()->getPhantom();
384   rPhantom.print();
385 #endif
386 }
387
388
389 void
390 PhantomView::OnProjections (wxCommandEvent& event)
391 {
392   DialogGetProjectionParameters dialogProjection (m_frame, 367, 320, 1, 1., Scanner::GEOMETRY_PARALLEL_STR);
393   int retVal = dialogProjection.ShowModal();
394   if (retVal == wxID_OK) {
395     int nDet = dialogProjection.getNDet();
396     int nView = dialogProjection.getNView();
397     int nSamples = dialogProjection.getNSamples();
398     double dRotAngle = dialogProjection.getRotAngle();
399     string sGeometry = dialogProjection.getGeometry();
400     if (nDet > 0 && nView > 0 && sGeometry != "") {
401       const Phantom& rPhantom = GetDocument()->getPhantom();
402       ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));
403       Projections& rProj = pProjectionDoc->getProjections();
404       Scanner theScanner (rPhantom, sGeometry.c_str(), nDet, nView, nSamples, dRotAngle);
405       rProj.initFromScanner (theScanner);
406       theScanner.collectProjections (rProj, rPhantom, 0, TRACE_NONE);
407       pProjectionDoc->Modify(true);
408       pProjectionDoc->UpdateAllViews(this);
409     }
410   }
411 }
412
413
414 void
415 PhantomView::OnRasterize (wxCommandEvent& event)
416 {
417   DialogGetRasterParameters dialogRaster (m_frame, 256, 256, 1);
418   int retVal = dialogRaster.ShowModal();
419   if (retVal == wxID_OK) {
420     int xSize = dialogRaster.getXSize();
421     int ySize = dialogRaster.getYSize();
422     int nSamples = dialogRaster.getNSamples();
423     if (nSamples < 1)
424       nSamples = 1;
425     if (xSize > 0 && ySize > 0) {
426       const Phantom& rPhantom = GetDocument()->getPhantom();
427       ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
428       ImageFile& imageFile = pRasterDoc->getImageFile();
429
430       imageFile.setArraySize (xSize, ySize);
431       rPhantom.convertToImagefile (imageFile, nSamples, TRACE_NONE);
432       pRasterDoc->Modify(true);
433       pRasterDoc->UpdateAllViews(this);
434
435       ostringstream os;
436       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << xSize << ", YSize=" << ySize << ", nSamples=" << nSamples << "\n";
437       *theApp->getLog() << os.str().c_str();
438     }
439   }
440 }
441
442
443 PhantomCanvas* 
444 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
445 {
446     PhantomCanvas* pCanvas;
447     int width, height;
448     parent->GetClientSize(&width, &height);
449     
450     pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
451     
452     pCanvas->SetBackgroundColour(*wxWHITE);
453     pCanvas->Clear();
454     
455     return pCanvas;
456 }
457
458 wxFrame*
459 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
460 {
461     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
462     
463     wxMenu *file_menu = new wxMenu;
464     
465     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "&Create Phantom...");
466     file_menu->Append(wxID_OPEN, "&Open...");
467     file_menu->Append(wxID_CLOSE, "&Close");
468     
469     file_menu->AppendSeparator();
470     file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
471
472     file_menu->AppendSeparator();
473     file_menu->Append(wxID_PRINT, "&Print...");
474     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
475     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
476     
477     wxMenu *process_menu = new wxMenu;
478     process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
479     process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
480
481     wxMenu *help_menu = new wxMenu;
482     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
483     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
484     
485     wxMenuBar *menu_bar = new wxMenuBar;
486     
487     menu_bar->Append(file_menu, "&File");
488     menu_bar->Append(process_menu, "&Process");
489     menu_bar->Append(help_menu, "&Help");
490     
491     subframe->SetMenuBar(menu_bar);
492     
493     subframe->Centre(wxBOTH);
494     
495     return subframe;
496 }
497
498
499 bool 
500 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
501 {
502     m_frame = CreateChildFrame(doc, this);
503     
504     int width, height;
505     m_frame->GetClientSize(&width, &height);
506     m_frame->SetTitle("PhantomView");
507     m_canvas = CreateCanvas(this, m_frame);
508
509 #ifdef __X__
510     int x, y;  // X requires a forced resize
511     m_frame->GetSize(&x, &y);
512     m_frame->SetSize(-1, -1, x, y);
513 #endif
514
515     m_frame->Show(true);
516     Activate(true);
517     
518     return true;
519 }
520
521 void 
522 PhantomView::OnDraw (wxDC* dc)
523 {
524     //  if (m_bitmap.Ok())
525     //    dc->DrawBitmap (m_bitmap, 0, 0, false);
526 }
527
528
529 void 
530 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
531 {
532     if (m_canvas)
533         m_canvas->Refresh();
534 }
535
536 bool 
537 PhantomView::OnClose (bool deleteWindow)
538 {
539     if (!GetDocument()->Close())
540         return false;
541
542     m_canvas->Clear();
543     m_canvas->m_pView = NULL;
544     m_canvas = NULL;
545     wxString s(wxTheApp->GetAppName());
546     if (m_frame)
547       m_frame->SetTitle(s);
548     SetFrame(NULL);
549
550     Activate(false);
551     
552     if (deleteWindow) {
553         delete m_frame;
554         return true;
555     }
556     return true;
557 }
558
559
560 // ProjectionCanvas
561
562 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
563   : wxScrolledWindow(frame, -1, pos, size, style)
564 {
565     m_pView = v;
566 }
567
568 void 
569 ProjectionFileCanvas::OnDraw(wxDC& dc)
570 {
571     if (m_pView)
572         m_pView->OnDraw(& dc);
573 }
574
575 // ProjectionFileView
576
577 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
578
579 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
580     EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
581     EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
582 END_EVENT_TABLE()
583
584 ProjectionFileView::ProjectionFileView(void) 
585   : wxView(), m_canvas(NULL), m_frame(NULL)
586 {
587 }
588
589 ProjectionFileView::~ProjectionFileView(void)
590 {
591 }
592
593 void
594 ProjectionFileView::OnProperties (wxCommandEvent& event)
595 {
596   const Projections& rProj = GetDocument()->getProjections();
597   ostringstream os;
598   os << "ProjectionFile " << rProj.getFilename() << ":  Number of Detectors = " << rProj.nDet() << ", Number of Views = " << rProj.nView() << "\n";
599   *theApp->getLog() << os.str().c_str();
600 }
601
602
603 void
604 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
605 {
606   ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
607   ImageFile& imageFile = pReconDoc->getImageFile();
608   const Projections& rProj = GetDocument()->getProjections();
609   string optFilterName = "abs_bandlimit";
610   double optFilterParam = 1.;
611   string optFilterMethodName = "convolution";
612   int optZeropad = 3;
613   string optInterpName = "linear";
614   int optInterpParam = 1;
615   string optBackprojectName = "idiff3";
616   imageFile.setArraySize (256, 256);
617   rProj.reconstruct (imageFile, optFilterName.c_str(), optFilterParam, optFilterMethodName.c_str(), optZeropad, optInterpName.c_str(), optInterpParam, optBackprojectName.c_str(), TRACE_NONE);
618   pReconDoc->Modify(true);
619   pReconDoc->UpdateAllViews(this);
620 }
621
622
623 ProjectionFileCanvas* 
624 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
625 {
626     ProjectionFileCanvas* pCanvas;
627     int width, height;
628     parent->GetClientSize(&width, &height);
629     
630     pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
631     
632     pCanvas->SetScrollbars(20, 20, 50, 50);
633     pCanvas->SetBackgroundColour(*wxWHITE);
634     pCanvas->Clear();
635     
636     return pCanvas;
637 }
638
639 wxFrame*
640 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
641 {
642     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
643     
644     wxMenu *file_menu = new wxMenu;
645     
646     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "&Create Phantom...");
647     file_menu->Append(wxID_OPEN, "&Open...");
648     file_menu->Append(wxID_CLOSE, "&Close");
649     
650     file_menu->AppendSeparator();
651     file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
652
653     file_menu->AppendSeparator();
654     file_menu->Append(wxID_PRINT, "&Print...");
655     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
656     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
657     
658     wxMenu *process_menu = new wxMenu;
659     process_menu->Append(PJMENU_PROCESS_RECONSTRUCT, "R&econstruct...");
660
661     wxMenu *help_menu = new wxMenu;
662     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
663     help_menu->AppendSeparator();
664     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
665     
666     wxMenuBar *menu_bar = new wxMenuBar;
667     
668     menu_bar->Append(file_menu, "&File");
669     menu_bar->Append(process_menu, "&Process");
670     menu_bar->Append(help_menu, "&Help");
671     
672     subframe->SetMenuBar(menu_bar);
673     
674     subframe->Centre(wxBOTH);
675     
676     return subframe;
677 }
678
679
680 bool 
681 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
682 {
683     m_frame = CreateChildFrame(doc, this);
684     
685     int width, height;
686     m_frame->GetClientSize(&width, &height);
687     m_frame->SetTitle("ProjectionFileView");
688     m_canvas = CreateCanvas(this, m_frame);
689
690 #ifdef __X__
691     int x, y;  // X requires a forced resize
692     m_frame->GetSize(&x, &y);
693     m_frame->SetSize(-1, -1, x, y);
694 #endif
695
696     m_frame->Show(true);
697     Activate(true);
698     
699     return true;
700 }
701
702 void 
703 ProjectionFileView::OnDraw (wxDC* dc)
704 {
705     if (m_bitmap.Ok())
706         dc->DrawBitmap (m_bitmap, 0, 0, false);
707 }
708
709
710 void 
711 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
712 {
713     const Projections& rProj = GetDocument()->getProjections();
714     const int nDet = rProj.nDet();
715     const int nView = rProj.nView();
716     if (nDet != 0 && nView != 0) {
717         const DetectorArray& detarray = rProj.getDetectorArray(0);
718         const DetectorValue* detval = detarray.detValues();
719         double min = detval[0];
720         double max = detval[0];
721         for (int iy = 0; iy < nView; iy++) {
722             const DetectorArray& detarray = rProj.getDetectorArray(iy);
723             const DetectorValue* detval = detarray.detValues();
724             for (int ix = 0; ix < nDet; ix++) {
725                 if (min > detval[ix])
726                     min = detval[ix];
727                 else if (max < detval[ix])
728                     max = detval[ix];
729             }
730         }
731
732         unsigned char* imageData = new unsigned char [nDet * nView * 3];
733         double scale = (max - min) / 255;
734         for (int iy = 0; iy < nView; iy++) {
735             const DetectorArray& detarray = rProj.getDetectorArray(iy);
736             const DetectorValue* detval = detarray.detValues();
737             for (int ix = 0; ix < nDet; ix++) {
738                 int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
739                 intensity = clamp(intensity, 0, 255);
740                 int baseAddr = (iy * nDet + ix) * 3;
741                 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
742             }
743         }
744         wxImage image (nDet, nView, imageData, true);
745         m_bitmap = image.ConvertToBitmap();
746         delete imageData;
747         int xSize = nDet;
748         int ySize = nView;
749         xSize = clamp (xSize, 0, 800);
750         ySize = clamp (ySize, 0, 800);
751         m_frame->SetClientSize (xSize, ySize);
752         m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
753     }
754
755     if (m_canvas)
756         m_canvas->Refresh();
757 }
758
759 bool 
760 ProjectionFileView::OnClose (bool deleteWindow)
761 {
762     if (!GetDocument()->Close())
763         return false;
764
765     m_canvas->Clear();
766     m_canvas->m_pView = NULL;
767     m_canvas = NULL;
768     wxString s(wxTheApp->GetAppName());
769     if (m_frame)
770       m_frame->SetTitle(s);
771     SetFrame(NULL);
772
773     Activate(false);
774     
775     if (deleteWindow) {
776         delete m_frame;
777         return true;
778     }
779     return true;
780 }
781