Force the user to input a DPI value for new image.
authorGreg Burri <greg.burri@gmail.com>
Wed, 20 Jan 2016 09:40:15 +0000 (10:40 +0100)
committerGreg Burri <greg.burri@gmail.com>
Wed, 20 Jan 2016 09:40:15 +0000 (10:40 +0100)
Parasitemia/ParasitemiaUI/Analysis.fs
Parasitemia/ParasitemiaUI/XAML/AnalysisWindow.xaml
Parasitemia/ParasitemiaUI/XAML/ImageSourceSelection.xaml

index 40fd303..24f9adb 100644 (file)
@@ -29,7 +29,7 @@ let showWindow (parent: Window) (state: State.State) : bool =
     let butClose: Button = ctrl "butClose"
     let butStart: Button = ctrl "butStart"
 
-    let stackImagesSourceSelection: StackPanel = ctrl "stackImagesSourceSelection"
+    let stackSourceImagesSelection: StackPanel = ctrl "stackSourceImagesSelection"
     let progressBar: ProgressBar = ctrl "progress"
     let textLog: TextBlock = ctrl "textLog"
     let scrollLog: ScrollViewer = ctrl "scrollLog"
@@ -58,15 +58,11 @@ let showWindow (parent: Window) (state: State.State) : bool =
     let mutable analysisCancelled = false
 
     let updateSourceImages () =
-        stackImagesSourceSelection.Children.Clear()
-        let width = int stackImagesSourceSelection.ActualWidth
+        stackSourceImagesSelection.Children.Clear()
+        let width = int stackSourceImagesSelection.ActualWidth
         for srcImg in state.SourceImages do
             let imageSourceSelection = Views.ImageSourceSelection(Tag = srcImg, Margin = Thickness(3.))
-
-            let updateResolution () =
-                match parseAndValidatePPI imageSourceSelection.txtResolution.Text with
-                | Some resolution -> srcImg.config.Parameters <- { srcImg.config.Parameters with resolution = resolution * 1.<ppi> }
-                | None -> ()
+            imageSourceSelection.Tag <- srcImg
 
             imageSourceSelection.txtImageNumber.Text <- srcImg.num.ToString()
             let height = srcImg.img.Height * width / srcImg.img.Width
@@ -74,9 +70,9 @@ let showWindow (parent: Window) (state: State.State) : bool =
             imageSourceSelection.chkSelection.IsChecked <- Nullable<bool>(srcImg.dateLastAnalysis.Ticks = 0L)
             imageSourceSelection.lblDateLastAnalysis.Content <- if srcImg.dateLastAnalysis.Ticks = 0L then "<Never>" else srcImg.dateLastAnalysis.ToString()
 
-            imageSourceSelection.txtResolution.Text <- srcImg.config.Parameters.resolution.ToString()
-            imageSourceSelection.menuZoom50X.Click.AddHandler(fun obj args -> imageSourceSelection.txtResolution.Text <- "230000"; updateResolution ())
-            imageSourceSelection.menuZoom100X.Click.AddHandler(fun obj args -> imageSourceSelection.txtResolution.Text <- "460000"; updateResolution ())
+            imageSourceSelection.txtResolution.Text <- if srcImg.dateLastAnalysis.Ticks = 0L then "" else srcImg.config.Parameters.resolution.ToString()
+            imageSourceSelection.menuZoom50X.Click.AddHandler(fun obj args -> imageSourceSelection.txtResolution.Text <- "230000")
+            imageSourceSelection.menuZoom100X.Click.AddHandler(fun obj args -> imageSourceSelection.txtResolution.Text <- "460000")
 
             imageSourceSelection.txtResolution.PreviewTextInput.AddHandler(fun obj args ->
                 let text = imageSourceSelection.txtResolution.Text + args.Text
@@ -86,50 +82,67 @@ let showWindow (parent: Window) (state: State.State) : bool =
                 let checkbox = imageSourceSelection.chkSelection
                 checkbox.IsChecked <- Nullable<bool>(not (checkbox.IsChecked.HasValue && checkbox.IsChecked.Value)))
 
-            imageSourceSelection.txtResolution.LostFocus.AddHandler(fun obj args -> updateResolution ())
-
-            stackImagesSourceSelection.Children.Add(imageSourceSelection) |> ignore
+            stackSourceImagesSelection.Children.Add(imageSourceSelection) |> ignore
+
+    // Get the new parameters for each image. If an error occurs then 'None' is returned and a message box is displayed.
+    // The boolean is 'true' if the image is selected (checked).
+    let getInputImagesParameters () : (SourceImage * bool * Parameters) list option =
+        let sourceImagesControls = stackSourceImagesSelection.Children |> Seq.cast<Views.ImageSourceSelection>
+        let parameters = seq {
+            for srcImgCtrl in sourceImagesControls do
+                let srcImg = srcImgCtrl.Tag :?> SourceImage
+                let isChecked = srcImgCtrl.chkSelection.IsChecked
+                match parseAndValidatePPI srcImgCtrl.txtResolution.Text with
+                    | Some resolution ->
+                        yield Some (srcImg, isChecked.HasValue && isChecked.Value, { srcImg.config.Parameters with resolution = resolution * 1.<ppi> })
+                    | None ->
+                        MessageBox.Show(sprintf "No resolution defined for the image number %d" srcImg.num, "No resolution defined", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
+                        yield None } |> Seq.takeWhile (fun e -> e.IsSome) |> Seq.map (fun e -> e.Value) |> List.ofSeq
+        if parameters.Count() <> sourceImagesControls.Count()
+        then None
+        else Some parameters
 
     butClose.Click.AddHandler(fun obj args -> window.Root.Close())
 
     butStart.Click.AddHandler(fun obj args ->
-        let imagesToProcess = [
-            for imageSelection in stackImagesSourceSelection.Children |> Seq.cast<Views.ImageSourceSelection> do
-                let chk = imageSelection.chkSelection.IsChecked
-                if chk.HasValue && chk.Value
-                then
-                    let srcImg = imageSelection.Tag :?> SourceImage
-                    yield srcImg.num.ToString(), srcImg.config, srcImg.img ]
-
-        if imagesToProcess.IsEmpty
-        then
-            MessageBox.Show("No image selected", "Cannot start analysis", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
-        else
-            analysisPerformed <- false
-            butStart.IsEnabled <- false
-            butClose.Content <- "Abort"
-            async {
-                let results =
-                    ParasitemiaCore.Analysis.doMultipleAnalysis
-                        imagesToProcess
-                        (Some (fun progress -> window.Root.Dispatcher.Invoke(fun () -> progressBar.Value <- float progress)))
-
-                lock monitor (
-                    fun() ->
-                        if not analysisCancelled
-                        then
-                            for id, cells in results do
-                                state.SetResult (int id) cells
-
-                            window.Root.Dispatcher.Invoke(fun () ->
-                                butStart.IsEnabled <- true
-                                butClose.Content <- "Close"
-                                updateSourceImages ())
-
-                            Logger.Log.User("All analyses terminated successfully")
-                            atLeastOneAnalysisPerformed <- true
-                            analysisPerformed <- true)
-            } |> Async.Start)
+        match getInputImagesParameters () with
+        | Some imagesParameters ->
+            let imagesToProcess = [
+                for srcImg, selected, parameters in imagesParameters do
+                    srcImg.config.Parameters <- parameters // Save parameters.
+                    if selected
+                    then yield srcImg.num.ToString(), srcImg.config, srcImg.img ]
+
+            if imagesToProcess.IsEmpty
+            then
+                MessageBox.Show("No image selected", "Cannot start analysis", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
+            else
+                analysisPerformed <- false
+                butStart.IsEnabled <- false
+                butClose.Content <- "Abort"
+                async {
+                    let results =
+                        ParasitemiaCore.Analysis.doMultipleAnalysis
+                            imagesToProcess
+                            (Some (fun progress -> window.Root.Dispatcher.Invoke(fun () -> progressBar.Value <- float progress)))
+
+                    lock monitor (
+                        fun() ->
+                            if not analysisCancelled
+                            then
+                                for id, cells in results do
+                                    state.SetResult (int id) cells
+
+                                window.Root.Dispatcher.Invoke(fun () ->
+                                    butStart.IsEnabled <- true
+                                    butClose.Content <- "Close"
+                                    updateSourceImages ())
+
+                                Logger.Log.User("All analyses terminated successfully")
+                                atLeastOneAnalysisPerformed <- true
+                                analysisPerformed <- true)
+                } |> Async.Start
+        | _ -> ())
 
     window.Root.Loaded.AddHandler(fun obj args -> updateSourceImages ())
 
index 599d581..3f3686e 100644 (file)
@@ -12,7 +12,7 @@
          <RowDefinition Height="Auto"/>
       </Grid.RowDefinitions>
       <ScrollViewer x:Name="scrollImagesSourceSelection" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Hidden" Grid.Row="0" Margin="3" >
-         <StackPanel x:Name="stackImagesSourceSelection" />
+         <StackPanel x:Name="stackSourceImagesSelection" />
       </ScrollViewer>
       <ProgressBar x:Name="progress" Grid.Row="1" Margin="3" Minimum="0" Maximum="100" />
       <ScrollViewer x:Name="scrollLog" Grid.Row="2" Margin="3" HorizontalScrollBarVisibility="Auto">
index 62a97f5..7958818 100644 (file)
@@ -4,7 +4,7 @@
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
       xmlns:fsxaml="clr-namespace:FsXaml;assembly=FsXaml.Wpf"
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-      mc:Ignorable="d" d:DesignWidth="349.723" d:DesignHeight="118.911"
+      mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="120"
                >
    <UserControl.Background>
       <SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ControlColorKey}}"/>
                <ColumnDefinition Width="Auto"/>
             </Grid.ColumnDefinitions>
             <TextBox x:Name="txtResolution" Margin="3" Text="" Grid.Column="0" />
-            <Button x:Name="butDefaultResolutions" Content="Defaults" Grid.Column="1" Margin="3">
+            <Button x:Name="butDefaultResolutions" Content="Predefined values" Grid.Column="1" Margin="3">
                <Button.ContextMenu>
                   <ContextMenu>
-                     <MenuItem x:Name="menuZoom50X" Header="_230'000 PPI (50X)"  />
-                     <MenuItem x:Name="menuZoom100X" Header="_460'000 PPI (100X)" />
+                     <MenuItem x:Name="menuZoom50X" Header="50X: 230'000 PPI" />
+                     <MenuItem x:Name="menuZoom100X" Header="100X: 460'000 PPI" />
                   </ContextMenu>
                </Button.ContextMenu>
                <Button.Style>