Add some GUI elements :
[master-thesis.git] / Parasitemia / ParasitemiaUI / GUI.fs
index 2ff3116..d749479 100644 (file)
@@ -27,12 +27,14 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
     let state = State.State()
     let mutable currentScale = 1.
     let mutable displayHealthy = false
+    let warningBelowNumberOfRBC = 1000
 
     let menuExit: MenuItem = ctrl "menuExit"
     let menuSaveFile: MenuItem = ctrl "menuSave"
     let menuSaveAsFile: MenuItem = ctrl "menuSaveAs"
     let menuLoadFile: MenuItem = ctrl "menuOpen"
     let menuNewFile: MenuItem = ctrl "menuNew"
+    let menuExportResults: MenuItem = ctrl "menuExportResults"
     let menuAddSourceImage: MenuItem = ctrl "menuAddSourceImage"
     let menuAnalysis: MenuItem = ctrl "menuAnalysis"
     let menuStartAnalysis: MenuItem = ctrl "menuStartAnalysis"
@@ -44,15 +46,18 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
     let txtMessageStatus: TextBlock = ctrl "txtMessageStatus"
 
     let txtPatient: TextBox = ctrl "txtPatient"
-    let txtGlobalParasitemia: TextBox = ctrl "txtGlobalParasitemia"
+    let txtGlobalParasitemia: TextBlock = ctrl "txtGlobalParasitemia"
 
     let stackPreviews: StackPanel = ctrl "stackPreviews"
 
     let scrollViewCurrentImage: ScrollViewer = ctrl "scrollViewCurrentImage"
     let borderCurrentImage: Border = ctrl "borderCurrentImage"
     let canvasCurrentImage: Canvas = ctrl "canvasCurrentImage"
+
+    let gridImageInformation: Grid = ctrl "gridImageInformation"
     let txtImageInformation1: TextBlock = ctrl "txtImageInformation1"
     let txtImageInformation2: TextBlock = ctrl "txtImageInformation2"
+    let txtImageName: TextBox = ctrl "txtImageName"
 
     let scrollRBC: ScrollViewer = ctrl "scrollRBC"
     let stackRBC: StackPanel = ctrl "stackRBC"
@@ -117,21 +122,24 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
         scrollViewCurrentImage.ScrollToHorizontalOffset(rbc.center.X * currentScale - scrollViewCurrentImage.ViewportWidth / 2. + borderCurrentImage.BorderThickness.Left)
         scrollViewCurrentImage.ScrollToVerticalOffset(rbc.center.Y * currentScale - scrollViewCurrentImage.ViewportHeight / 2. + borderCurrentImage.BorderThickness.Top)
 
-    let percentText (nbTotal: int, nb: int) : string =
-        if nbTotal = 0
-        then
-            ""
-        else
-            let percent = 100. * (float nb) / (float nbTotal)
-            sprintf "%.1f %% (%d / %d)" percent nb nbTotal
+
+    let txtImageName_TextChanged =
+        TextChangedEventHandler(fun obj args -> state.CurrentImage |> Option.iter(fun srcImg -> state.SetName srcImg txtImageName.Text))
 
     let updateCurrentImageInformation () =
+        txtImageName.TextChanged.RemoveHandler(txtImageName_TextChanged)
         txtImageInformation1.Inlines.Clear()
         txtImageInformation2.Inlines.Clear()
+        txtImageName.Text <- ""
 
         match state.CurrentImage with
         | Some srcImg ->
-            let parasitemiaStr = percentText (state.ImageParasitemia srcImg)
+            gridImageInformation.Visibility <- Visibility.Visible
+            txtImageName.Text <- srcImg.name
+            txtImageName.TextChanged.AddHandler(txtImageName_TextChanged)
+
+            // The left part.
+            let parasitemiaStr = Utils.percentText (state.ImageParasitemia srcImg)
             txtImageInformation1.Inlines.Add(Documents.Run("Parasitemia: ", FontWeight = FontWeights.Bold))
             txtImageInformation1.Inlines.Add(parasitemiaStr)
             txtImageInformation1.Inlines.Add(Documents.LineBreak())
@@ -139,17 +147,27 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
             txtImageInformation1.Inlines.Add(Documents.Run("Last analysis: ", FontWeight = FontWeights.Bold))
             txtImageInformation1.Inlines.Add(Documents.Run(if srcImg.dateLastAnalysis.Ticks = 0L then "<Never>" else srcImg.dateLastAnalysis.ToLocalTime().ToString()))
 
-            let alteredStr = percentText (state.ImageNbAltered srcImg)
-            txtImageInformation2.Inlines.Add(Documents.Run("Number of erytrocytes manually altered: ", FontWeight = FontWeights.Bold))
-            txtImageInformation2.Inlines.Add(Documents.Run(alteredStr))
+            // The right part part.
+            txtImageInformation2.Inlines.Add(Documents.Run("Added infected erythrocyte: ", FontWeight = FontWeights.Bold))
+            txtImageInformation2.Inlines.Add(Documents.Run((state.ImageNbManuallyChangedRBCStr srcImg true) + " " + (state.ImageManuallyChangedRBCStr srcImg true)))
             txtImageInformation2.Inlines.Add(Documents.LineBreak())
+            txtImageInformation2.Inlines.Add(Documents.Run("Removed infected erythrocyte: ", FontWeight = FontWeights.Bold))
+            txtImageInformation2.Inlines.Add(Documents.Run((state.ImageNbManuallyChangedRBCStr srcImg false) + " " + (state.ImageManuallyChangedRBCStr srcImg false)))
 
-            txtImageInformation2.Inlines.Add(Documents.Run("Average erytrocyte diameter: ", FontWeight = FontWeights.Bold))
-            txtImageInformation2.Inlines.Add(Documents.Run(srcImg.config.RBCRadius.ToString()))
-        | _ -> ()
+        | _ ->
+            gridImageInformation.Visibility <- Visibility.Hidden
 
     let updateGlobalParasitemia () =
-        txtGlobalParasitemia.Text <- percentText state.GlobalParasitemia
+        txtGlobalParasitemia.Inlines.Clear()
+        let total, infected = state.GlobalParasitemia
+        txtGlobalParasitemia.Inlines.Add(Documents.Run(Utils.percentText (total, infected), FontWeight = FontWeights.Bold))
+        if total > 0 && total < warningBelowNumberOfRBC
+        then
+            txtGlobalParasitemia.Inlines.Add(
+                Documents.Run(
+                    sprintf " Warning: the number of erytrocytes should be above %d" warningBelowNumberOfRBC,
+                    FontWeight = FontWeights.Bold,
+                    Foreground = Brushes.Red))
 
     let updateViewportPreview () =
         for preview in stackPreviews.Children |> Seq.cast<Views.ImageSourcePreview> do
@@ -425,6 +443,26 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
         state.Reset()
         updateGUI()
 
+    let exportResults () =
+        let extension = ".txt"
+        let dialog = SaveFileDialog(AddExtension = true, DefaultExt = extension)
+
+        if state.FilePath <> ""
+        then
+            dialog.FileName <- Path.GetFileNameWithoutExtension(state.FilePath) + extension
+        elif state.PatientID <> ""
+        then
+            dialog.FileName <- state.PatientID + extension
+
+        let res = dialog.ShowDialog()
+        if res.HasValue && res.Value then
+            try
+                Export.exportResults state dialog.FileName
+            with
+            | :? IOException as ex ->
+                Log.Error(ex.ToString())
+                MessageBox.Show(sprintf "The results cannot be exported in '%s'" state.FilePath, "Error exporting the files", MessageBoxButton.OK, MessageBoxImage.Error) |> ignore
+
     txtPatient.TextChanged.AddHandler(fun obj args -> state.PatientID <- txtPatient.Text)
 
     menuExit.Click.AddHandler(fun obj args -> mainWindow.Root.Close())
@@ -432,6 +470,7 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
     menuSaveAsFile.Click.AddHandler(fun obj args -> saveCurrentDocumentAsNewFile ())
     menuLoadFile.Click.AddHandler(fun obj args -> askLoadFile ())
     menuNewFile.Click.AddHandler(fun obj args -> newFile ())
+    menuExportResults.Click.AddHandler(fun obj args -> exportResults ())
 
     menuAddSourceImage.Click.AddHandler(fun obj args ->
         let dialog = OpenFileDialog(Filter = "Image Files|*.png;*.jpg;*.tif;*.tiff", Multiselect = true)
@@ -579,10 +618,17 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
             FSharp.ViewModule.FunCommand((fun obj -> newFile ()), (fun obj -> true)),
             Input.KeyGesture(Input.Key.N, Input.ModifierKeys.Control))) |> ignore
 
+    // Export results.
+    mainWindow.Root.InputBindings.Add(
+        Input.KeyBinding(
+            FSharp.ViewModule.FunCommand((fun obj -> exportResults ()), (fun obj -> true)),
+            Input.KeyGesture(Input.Key.E, Input.ModifierKeys.Control))) |> ignore
+
     // Viewport preview.
     scrollViewCurrentImage.ScrollChanged.AddHandler(fun obj args -> updateViewportPreview ())
 
     updateDocumentStatus ()
+    gridImageInformation.Visibility <- Visibility.Hidden
 
     mainWindow.Root.Show()