// Create a new larger zoomable popup so that the user can inspect the image details private void Canvas_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) { int height = 480; if (sender is Canvas canvas && canvas.Tag != null) { Image image = EpisodePopup.CreateImage((ImageRow)canvas.Tag, 0, height); Canvas clone = CreateCanvasWithBoundingBoxesAndImage(image, height, 0, ((ImageRow)canvas.Tag).ID); Zoombox zoombox = CreateZoombox(); zoombox.Content = clone; this.InspectionPopup.Child = zoombox; this.InspectionPopup.Placement = PlacementMode.MousePoint; this.InspectionPopup.IsOpen = true; } }
public void Show(bool isVisible, int maxNumberImagesToDisplay) { ImageRow currentImageRow = timelapseWindow?.DataHandler?.ImageCache?.Current; TimeSpan timeThreshold = timelapseWindow.State.EpisodeTimeThreshold; if (isVisible == false || currentImageRow == null || FileDatabase == null) { // Hide the popup if asked or if basic data isn't available, including deleting the children this.IsOpen = false; this.Child = null; return; } // Images or placeholders will be contained in a horizontal stack panel, which in turn is the popup's child StackPanel sp = new StackPanel { Orientation = Orientation.Horizontal }; this.Child = sp; double width = 0; // Used to calculate the placement offset of the popup relative to the placement target double height; // Add a visual marker to show the position of the label in the image list Label label = EpisodePopup.CreateLabel("^", this.ImageHeight); label.VerticalAlignment = VerticalAlignment.Top; width += label.Width; height = label.Height; sp.Children.Add(label); int margin = 2; FileTable fileTable; // To hold the results of the database selection as a table of ImageRows // We will only consider images whose relative path is the same as the current file string relativePath = currentImageRow.RelativePath; // Calculate the lower and upper extent of the range of dates we should examine // The maximum date range we need to consider would be the current date plus/minus the (time threshold * the number of images we could display), // While this could produce more hits than we need, it should give us a relatively short table of possible candidates DateTime lowerDateTime = currentImageRow.DateTime - TimeSpan.FromTicks(timeThreshold.Ticks * maxNumberImagesToDisplay); DateTime upperDateTime = currentImageRow.DateTime + TimeSpan.FromTicks(timeThreshold.Ticks * maxNumberImagesToDisplay); string slowerDateTime = DateTimeHandler.ToStringDatabaseDateTime(lowerDateTime); string supperDateTime = DateTimeHandler.ToStringDatabaseDateTime(upperDateTime); // Get a table of files (sorted by datetime) with that relative path which falls between the lower and upper date range DataTable dt = this.FileDatabase.GetIDandDateWithRelativePathAndBetweenDates(relativePath, slowerDateTime, supperDateTime); // Find the current image in that table by its ID int rowWithCurrentImageRowID = -1; int availableRows = dt.Rows.Count; for (int i = 0; i < availableRows; i++) { if (Convert.ToInt64(dt.Rows[i][0]) == currentImageRow.ID) { rowWithCurrentImageRowID = i; break; } } // From that current image, alternate between going to the previous/next row. // If the date difference between alternating successive images is less than the time threshold, // display it. int goBackwardsRow = rowWithCurrentImageRowID - 1; int goForwardsRow = rowWithCurrentImageRowID + 1; int imagesLeftToDisplay = maxNumberImagesToDisplay; DateTime lastBackwardsDateTime = currentImageRow.DateTime; DateTime lastForwardsDateTime = currentImageRow.DateTime; while (true && (goBackwardsRow >= 0 || goForwardsRow < availableRows)) { // Abort when there is no more work to do if (imagesLeftToDisplay <= 0) { break; } // Start on the left if (goBackwardsRow >= 0) { // Add a popup image to the left of the caret using (fileTable = this.FileDatabase.SelectFileInDataTableById(dt.Rows[goBackwardsRow][0].ToString())) { if (fileTable.Any()) { if ((lastBackwardsDateTime - fileTable[0].DateTime).Duration() <= timeThreshold) { Image image = EpisodePopup.CreateImage(fileTable[0], margin, this.ImageHeight); width += image.Source.Width; height = Math.Max(height, image.Source.Height); // Create a canvas containing the image and bounding boxes (if detections are on) sp.Children.Insert(0, CreateCanvasWithBoundingBoxesAndImage(image, height, margin, fileTable[0].ID)); imagesLeftToDisplay--; lastBackwardsDateTime = fileTable[0].DateTime; } else { // Stop searching backwards goBackwardsRow = -1; } } } goBackwardsRow--; } // Now try to add a popup image to the right if we still have some more images left to display if (goForwardsRow < availableRows && imagesLeftToDisplay > 0) { using (fileTable = this.FileDatabase.SelectFileInDataTableById(dt.Rows[goForwardsRow][0].ToString())) { if (fileTable.Any()) { if ((lastForwardsDateTime - fileTable[0].DateTime).Duration() <= timeThreshold) { Image image = EpisodePopup.CreateImage(fileTable[0], margin, this.ImageHeight); width += image.Source.Width; height = Math.Max(height, image.Source.Height); // Create a canvas containing the image and bounding box sp.Children.Add(CreateCanvasWithBoundingBoxesAndImage(image, height, margin, fileTable[0].ID)); imagesLeftToDisplay--; lastBackwardsDateTime = fileTable[0].DateTime; } else { // Stop searching forwards goForwardsRow = availableRows; } } } goForwardsRow++; } } label.Height = Math.Max(label.Height, height); // So it extends to the top of the popup // Position and open the popup so it appears horizontallhy centered just above the cursor this.HorizontalOffset = this.markableCanvas.ActualWidth / 2.0 - width / 2.0; this.VerticalOffset = -height - 2 * margin; this.IsOpen = true; // Cleanup dt.Dispose(); }