GUI (work in progress..)
[master-thesis.git] / Parasitemia / Parasitemia / GUI / GUI.fs
1 module Parasitemia.GUI.Main
2
3 open System.IO
4 open System.Linq
5 open System.Windows
6 open System.Windows.Media
7 open System.Windows.Markup
8 open System.Windows.Shapes
9 open System.Windows.Controls
10 open System.Diagnostics
11 open Microsoft.Win32 // For the common dialogs.
12
13 //open Emgu.CV
14 //open Emgu.CV.Structure
15 open Emgu.CV.WPF
16
17 open Config
18 open Types
19
20 let run (defaultConfig: Config) =
21 let app = new Application()
22 let mainWindow = Views.MainWindow()
23 let ctrl (name: string): 'a =
24 mainWindow.Root.FindName(name) :?> 'a
25
26 // Utils.log <- (fun m -> log mainWindow m)
27
28 let colorRBCHealthy = Brushes.Green
29 let colorRBCInfected = Brushes.Yellow
30
31 let state = State.State()
32
33 let exit: MenuItem = ctrl "menuExit"
34 let saveFile: MenuItem = ctrl "menuSave"
35 let loadFile: MenuItem = ctrl "menuOpen"
36 let newFile: MenuItem = ctrl "menuNew"
37
38 let addSourceImage: MenuItem = ctrl "menuAddSourceImage"
39 let txtPatient: TextBox = ctrl "txtPatient"
40 let stackPreviews: StackPanel = ctrl "stackPreviews"
41 let butStartAnalysis: Button = ctrl "butStartAnalysis"
42
43 let scrollViewCurrentImage: ScrollViewer = ctrl "scrollViewCurrentImage"
44 let borderCurrentImage: Border = ctrl "borderCurrentImage"
45 let canvasCurrentImage: Canvas = ctrl "canvasCurrentImage"
46
47 // Initializations.
48
49 // Operations.
50 let synchronizeState () =
51 state.PatientID <- txtPatient.Text
52
53 let setCurrentImage (srcImg: SourceImage) =
54 canvasCurrentImage.Height <- float srcImg.img.Height
55 canvasCurrentImage.Width <- float srcImg.img.Width
56 canvasCurrentImage.Background <- ImageBrush(BitmapSourceConvert.ToBitmapSource(srcImg.img))
57
58 // Remove all image canvas children and add the RBC.
59 canvasCurrentImage.Children.Clear()
60 for rbc in (*srcImg.rbcs*) [{ num = 1; infected = true; addedManually = false; removed = false; center = Point(100., 100.); size = Size(40., 40.); stainArea = 10 }] do
61 let rectangle =
62 Rectangle(
63 Height = rbc.size.Height,
64 Width = rbc.size.Width,
65 Stroke = (if rbc.infected then colorRBCInfected else colorRBCHealthy),
66 StrokeThickness = 1.)
67 Canvas.SetLeft(rectangle, rbc.center.X + rbc.size.Width / 2.)
68 Canvas.SetTop(rectangle, rbc.center.Y + rbc.size.Height / 2.)
69 canvasCurrentImage.Children.Add(rectangle) |> ignore
70
71 let addPreview (srcImg: SourceImage) =
72 let imgCtrl = Views.ImageSourcePreview(Margin = Thickness(3.))
73 imgCtrl.lblImageNumber.Content <- srcImg.num
74 let width = 200
75 let height = srcImg.img.Height * width / srcImg.img.Width
76 imgCtrl.imagePreview.Source <- BitmapSourceConvert.ToBitmapSource(srcImg.img.Resize(width, height, Emgu.CV.CvEnum.Inter.Cubic))
77 stackPreviews.Children.Add(imgCtrl) |> ignore
78
79 let updatePreviews () =
80 stackPreviews.Children.Clear ()
81 if state.SourceImages.Count() > 0
82 then
83 for srcImg in state.SourceImages do
84 addPreview srcImg
85 setCurrentImage (state.SourceImages.First())
86
87 let updateGUI () =
88 txtPatient.Text <- state.PatientID
89 updatePreviews ()
90
91 exit.Click.AddHandler(fun obj args -> mainWindow.Root.Close())
92 saveFile.Click.AddHandler(fun obj args ->
93 synchronizeState ()
94 if state.FilePath = ""
95 then
96 let dialog = SaveFileDialog(AddExtension = true, DefaultExt = Pia.extension, Filter = Pia.filter);
97 let res = dialog.ShowDialog()
98 if res.HasValue && res.Value
99 then
100 state.FilePath <- dialog.FileName
101 state.Save()
102 else
103 state.Save())
104
105 loadFile.Click.AddHandler(fun obj args ->
106 // TODO: if current state not saved and not empty, ask to save it.
107 let dialog = OpenFileDialog(Filter = Pia.filter)
108 let res = dialog.ShowDialog()
109 if res.HasValue && res.Value
110 then
111 state.FilePath <- dialog.FileName
112 state.Load()
113 updateGUI ())
114
115 newFile.Click.AddHandler(fun obj args ->
116 // TODO: if current state not saved and not empty, ask to save it.
117 state.Reset()
118 updateGUI())
119
120 addSourceImage.Click.AddHandler(fun obj args ->
121 let dialog = OpenFileDialog(Filter = "Image Files|*.png;*.jpg;*.tif;*.tiff")
122 let res = dialog.ShowDialog()
123 if res.HasValue && res.Value
124 then
125 let srcImg = state.AddSourceImage(dialog.FileName)
126 addPreview srcImg
127 if state.SourceImages.Count() = 1
128 then
129 setCurrentImage srcImg)
130
131 butStartAnalysis.Click.AddHandler(fun obj args -> ())
132
133 // Zoom on the current image.
134 let adjustCurrentImageBorders (deltaX: float) (deltaY: float) =
135 borderCurrentImage.BorderThickness <-
136 Thickness(
137 (scrollViewCurrentImage.ViewportWidth + deltaX) / 2.,
138 (scrollViewCurrentImage.ViewportHeight + deltaY) / 2.,
139 (scrollViewCurrentImage.ViewportWidth + deltaX) / 2.,
140 (scrollViewCurrentImage.ViewportHeight + deltaY) / 2.)
141
142 canvasCurrentImage.SizeChanged.AddHandler(fun obj args ->
143 let deltaX = args.NewSize.Width - args.PreviousSize.Width
144 let deltaY = args.NewSize.Height - args.PreviousSize.Height
145 if deltaX > 0.5 || deltaY > 0.5
146 then
147 adjustCurrentImageBorders 0.0 0.0
148 // Center the view at the center of the image initialy.
149 scrollViewCurrentImage.UpdateLayout()
150 scrollViewCurrentImage.ScrollToHorizontalOffset(borderCurrentImage.ActualWidth / 2. - scrollViewCurrentImage.ViewportWidth / 2.)
151 scrollViewCurrentImage.ScrollToVerticalOffset(borderCurrentImage.ActualHeight / 2. - scrollViewCurrentImage.ViewportHeight / 2.))
152
153 scrollViewCurrentImage.SizeChanged.AddHandler(fun obj args ->
154 let deltaX = args.NewSize.Width - args.PreviousSize.Width
155 let deltaY = args.NewSize.Height - args.PreviousSize.Height
156 adjustCurrentImageBorders deltaX deltaY
157 scrollViewCurrentImage.ScrollToHorizontalOffset(scrollViewCurrentImage.HorizontalOffset + deltaX / 8.)
158 scrollViewCurrentImage.ScrollToVerticalOffset(scrollViewCurrentImage.VerticalOffset + deltaY / 8.))
159
160 let mutable currentScale = 1.
161 let mutable maxScale = 5.
162 let mutable minScale = 0.1
163 let currentImageScaleTransform = ScaleTransform()
164 canvasCurrentImage.LayoutTransform <- currentImageScaleTransform
165 borderCurrentImage.PreviewMouseWheel.AddHandler(fun obj args ->
166 let scaleFactor = if args.Delta > 0 then 2.0 else 0.5
167 if scaleFactor > 1. && currentScale < maxScale || scaleFactor < 1. && currentScale > minScale
168 then
169 let previousScale = currentScale
170 currentScale <-
171 let newScale = currentScale * scaleFactor
172 if newScale > maxScale then maxScale elif newScale < minScale then minScale else newScale
173 let realScaleFactor = currentScale / previousScale
174
175 let centerX = scrollViewCurrentImage.HorizontalOffset + scrollViewCurrentImage.ViewportWidth / 2. - borderCurrentImage.BorderThickness.Left
176 let centerY = scrollViewCurrentImage.VerticalOffset + scrollViewCurrentImage.ViewportHeight / 2. - borderCurrentImage.BorderThickness.Top
177
178 //canvasCurrentImage.Margin <- Thickness(canvasCurrentImage.Margin.Top * realScaleFactor)
179 currentImageScaleTransform.ScaleX <- currentScale
180 currentImageScaleTransform.ScaleY <- currentScale
181
182 scrollViewCurrentImage.ScrollToHorizontalOffset(centerX * realScaleFactor - scrollViewCurrentImage.ViewportWidth / 2. + borderCurrentImage.BorderThickness.Left)
183 scrollViewCurrentImage.ScrollToVerticalOffset(centerY * realScaleFactor - scrollViewCurrentImage.ViewportHeight / 2. + borderCurrentImage.BorderThickness.Top)
184 args.Handled <- true)
185
186 // Pan on the current image.
187 let mutable scrollStartPosition = Point(0., 0.)
188 let mutable scrollStartOffsetX = 0.
189 let mutable scrollStartOffsetY = 0.
190 borderCurrentImage.PreviewMouseLeftButtonDown.AddHandler(fun obj args ->
191 scrollStartPosition <- args.GetPosition(scrollViewCurrentImage)
192 scrollStartOffsetX <- scrollViewCurrentImage.HorizontalOffset
193 scrollStartOffsetY <- scrollViewCurrentImage.VerticalOffset
194 borderCurrentImage.Cursor <- Input.Cursors.ScrollAll
195 borderCurrentImage.CaptureMouse() |> ignore
196 args.Handled <- true)
197
198 borderCurrentImage.PreviewMouseMove.AddHandler(fun obj args ->
199 if borderCurrentImage.IsMouseCaptured
200 then
201 let position = args.GetPosition(scrollViewCurrentImage)
202 let deltaX = scrollStartPosition.X - position.X
203 let deltaY = scrollStartPosition.Y - position.Y
204 scrollViewCurrentImage.ScrollToHorizontalOffset(deltaX + scrollStartOffsetX)
205 scrollViewCurrentImage.ScrollToVerticalOffset(deltaY + scrollStartOffsetY)
206 args.Handled <- true)
207
208 borderCurrentImage.PreviewMouseLeftButtonUp.AddHandler(fun obj args ->
209 if borderCurrentImage.IsMouseCaptured
210 then
211 borderCurrentImage.Cursor <- Input.Cursors.Arrow
212 borderCurrentImage.ReleaseMouseCapture()
213 args.Handled <- true)
214
215 (* let txtPatient: Controls.TextBox = ctrl "txtPatient"
216 txtPatient.TextChanged.AddHandler(fun obj args ->
217 state.PatientID <- txtPatient.Text) *)
218
219 (* saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*" ;
220 saveFileDialog1.FilterIndex = 2 ;
221 saveFileDialog1.RestoreDirectory = true ; *)
222
223 // display mainWindow img
224 mainWindow.Root.Show()
225 app.Run()