protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.Viewer != null)
                {
                    this.Viewer.Close();
                    this.Viewer = null;
                }

                if (_canvas != null && _highlight != null)
                {
                    _canvas.Children.Remove(_highlight);
                    _highlight = null;
                }

                if (_camera != null)
                {
                    _camera.Changed -= new EventHandler(Camera_Changed);
                }

                if (this.Item != null)
                {
                    this.Item.PhysicsBody.BodyMoved -= new EventHandler(Item_BodyMoved);
                }

                if (_viewportContainer != null)
                {
                    _viewportContainer.SizeChanged -= new SizeChangedEventHandler(ViewportContainer_SizeChanged);
                }
            }

            base.Dispose(disposing);
        }
        public SelectedItemSwimbots(IMapObject item, Vector3D offset, ShipViewerWindow shipViewer, FrameworkElement viewportContainer, Viewport3D viewport, Canvas canvas, PerspectiveCamera camera, bool shouldMoveWidthSpring, bool shouldSpringCauseTorque, Color? springColor)
            : base(item, offset, shouldMoveWidthSpring, shouldSpringCauseTorque, true, viewport, springColor)
        {
            this.Viewer = shipViewer;
            _viewportContainer = viewportContainer;
            _canvas = canvas;
            _camera = camera;

            if (this.Viewer != null)
            {
                this.Viewer.Closed += new EventHandler(Viewer_Closed);
            }

            item.PhysicsBody.BodyMoved += new EventHandler(Item_BodyMoved);
            _camera.Changed += new EventHandler(Camera_Changed);
            _viewportContainer.SizeChanged += new SizeChangedEventHandler(ViewportContainer_SizeChanged);

            UpdateHightlight();
        }
        private ShipViewerWindow ShowShipViewer(Swimbot bot, Point clickPoint)
        {
            // Make the camera follow this bean
            //TODO: Place a 2D graphic behind the selected ship
            //TODO: Zoom in on it
            #region Create Viewer

            ShipViewerWindow retVal = new ShipViewerWindow(bot);
            retVal.Owner = this;		// the other settings like topmost, showintaskbar, etc are already set in the window's xaml
            retVal.PopupBorder = new SolidColorBrush(UtilityWPF.ColorFromHex("60000000"));
            retVal.PopupBackground = new SolidColorBrush(UtilityWPF.ColorFromHex("30000000"));
            retVal.ViewportBorder = new SolidColorBrush(UtilityWPF.ColorFromHex("E0000000"));

            LinearGradientBrush brush = new LinearGradientBrush();
            brush.StartPoint = new Point(0, 0);
            brush.EndPoint = new Point(1, 1);

            GradientStopCollection gradients = new GradientStopCollection();
            gradients.Add(new GradientStop(UtilityWPF.ColorFromHex("E0EBEDE4"), 0d));
            gradients.Add(new GradientStop(UtilityWPF.ColorFromHex("E0DFE0DA"), .1d));
            gradients.Add(new GradientStop(UtilityWPF.ColorFromHex("E0E0E0E0"), .6d));
            gradients.Add(new GradientStop(UtilityWPF.ColorFromHex("E0DADBD5"), .9d));
            gradients.Add(new GradientStop(UtilityWPF.ColorFromHex("E0D7DBCC"), 1d));
            brush.GradientStops = gradients;

            retVal.ViewportBackground = brush;

            retVal.PanelBorder = new SolidColorBrush(UtilityWPF.ColorFromHex("8068736B"));
            retVal.PanelBackground = new SolidColorBrush(UtilityWPF.ColorFromHex("80424F45"));
            retVal.Foreground = new SolidColorBrush(UtilityWPF.ColorFromHex("F0F0F0"));

            #endregion

            // Place Viewer
            Point screenClickPoint = UtilityWPF.TransformToScreen(clickPoint, grdViewPort);
            ShipViewerWindow.PlaceViewerInCorner(retVal, screenClickPoint);

            // This places the viewer to the right of where they clicked - which is fine if they can't drag the item
            // around, but it's in the way if they try to move the object
            //Point popupPoint = new Point(windowClickPoint.X + 50, windowClickPoint.Y - (viewer.Height / 3d));
            //popupPoint = UtilityWPF.EnsureWindowIsOnScreen(popupPoint, new Size(viewer.Width, viewer.Height));		// don't let the popup straddle monitors
            //viewer.Left = popupPoint.X;
            //viewer.Top = popupPoint.Y;

            retVal.Show();      // it needs to be shown first to get the size

            return retVal;
        }
        private void RemoveBot()
        {
            // Viewer
            if (_viewer != null)
            {
                _viewer.Close();
                _viewer = null;
            }

            // Brain Viewer
            panelCustom.Content = null;
            _brainViewer = null;

            //Progress Bars
            _progressBars = null;
            pnlProgressBars.Visibility = Visibility.Collapsed;

            // Bot
            if (_bot != null)
            {
                _map.RemoveItem(_bot);

                _bot.Dispose();
                _bot = null;
            }
        }
        private void BotViewer_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (_bot == null)
                {
                    MessageBox.Show("Create a bot first", this.Title, MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }

                if (_viewer != null)
                {
                    _viewer.Close();
                    _viewer = null;
                }

                _viewer = new ShipViewerWindow(_bot)
                {
                    Owner = this,		// the other settings like topmost, showintaskbar, etc are already set in the window's xaml

                    PopupBorder = new SolidColorBrush(UtilityWPF.ColorFromHex("60000000")),
                    PopupBackground = new SolidColorBrush(UtilityWPF.ColorFromHex("30000000")),
                    ViewportBorder = new SolidColorBrush(UtilityWPF.ColorFromHex("E0000000")),
                    ViewportBackground = new SolidColorBrush(UtilityWPF.ColorFromHex("E0E0E0E0")),
                    PanelBorder = new SolidColorBrush(UtilityWPF.ColorFromHex("8068736B")),
                    PanelBackground = new SolidColorBrush(UtilityWPF.ColorFromHex("80424F45")),
                    Foreground = new SolidColorBrush(UtilityWPF.ColorFromHex("F0F0F0")),
                };

                _viewer.Show();      // it needs to be shown first to get the size
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        private void Window_Closed(object sender, EventArgs e)
        {
            try
            {
                _world.Pause();

                if (_viewer != null)
                {
                    _viewer.Close();
                    _viewer = null;
                }

                _updateManager.Dispose();

                // Explosions
                //foreach (ExplodingBot explosion in _explosions.ToArray())
                //{
                //    DisposeExplosion(explosion);
                //}

                _map.Dispose();		// this will dispose the physics bodies
                _map = null;

                if (_cameraPool != null)
                {
                    _cameraPool.Dispose();
                    _cameraPool = null;
                }

                _world.Dispose();
                _world = null;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
 private void Viewer_Closed(object sender, EventArgs e)
 {
     this.Viewer = null;
 }
            public SelectedBean(Bean bean, ShipViewerWindow viewer, Vector3D cameraOffset)
            {
                this.Bean = bean;
                this.Viewer = viewer;
                this.CameraOffset = cameraOffset;

                this.Viewer.Closed += new EventHandler(Viewer_Closed);
            }
        private void grdViewPort_MouseDown(object sender, MouseButtonEventArgs e)
        {
            try
            {
                if (e.ChangedButton != MouseButton.Left)
                {
                    // All the special logic in this method is for the left button
                    return;
                }

                #region Tab Buttons

                if (_pressedButton != null)
                {
                    // Hide the currently showing options panel
                    pnlSettings.Children.Clear();
                    _pressedButton = null;
                    ColorPanelButtons();
                }

                #endregion
                #region Select Bean

                var clickedBean = GetMouseOverBean(e);

                if (_selectedBean != null && clickedBean != null && _selectedBean.Bean.Equals(clickedBean.Item1))
                {
                    // This is already selected, don't do anything
                }
                else
                {
                    // Close any existing viewer
                    if (_selectedBean != null && _selectedBean.Viewer != null)
                    {
                        _selectedBean.Viewer.Close();
                    }
                    _selectedBean = null;

                    // Make the camera follow this bean
                    //TODO: Place a 2D graphic behind the selected ship
                    //TODO: Zoom in on the bean
                    if (clickedBean != null)
                    {
                        #region Show Viewer

                        ShipViewerWindow viewer = new ShipViewerWindow(clickedBean.Item1);
                        viewer.Owner = this;		// the other settings like topmost, showintaskbar, etc are already set in the window's xaml
                        viewer.PopupBorder = new SolidColorBrush(UtilityWPF.ColorFromHex("60000000"));
                        viewer.PopupBackground = new SolidColorBrush(UtilityWPF.ColorFromHex("30000000"));
                        viewer.ViewportBorder = new SolidColorBrush(UtilityWPF.ColorFromHex("E0000000"));

                        LinearGradientBrush brush = new LinearGradientBrush();
                        brush.StartPoint = new Point(0, 0);
                        brush.EndPoint = new Point(1, 1);

                        GradientStopCollection gradients = new GradientStopCollection();
                        gradients.Add(new GradientStop(UtilityWPF.ColorFromHex("E0EBEDE4"), 0d));
                        gradients.Add(new GradientStop(UtilityWPF.ColorFromHex("E0DFE0DA"), .1d));
                        gradients.Add(new GradientStop(UtilityWPF.ColorFromHex("E0E0E0E0"), .6d));
                        gradients.Add(new GradientStop(UtilityWPF.ColorFromHex("E0DADBD5"), .9d));
                        gradients.Add(new GradientStop(UtilityWPF.ColorFromHex("E0D7DBCC"), 1d));
                        brush.GradientStops = gradients;

                        viewer.ViewportBackground = brush;

                        viewer.PanelBorder = new SolidColorBrush(UtilityWPF.ColorFromHex("8068736B"));
                        viewer.PanelBackground = new SolidColorBrush(UtilityWPF.ColorFromHex("80424F45"));
                        viewer.Foreground = new SolidColorBrush(UtilityWPF.ColorFromHex("F0F0F0"));

                        Point windowClickPoint = UtilityWPF.TransformToScreen(clickedBean.Item3, grdViewPort);
                        Point popupPoint = new Point(windowClickPoint.X + 50, windowClickPoint.Y - (viewer.Height / 3d));
                        popupPoint = UtilityWPF.EnsureWindowIsOnScreen(popupPoint, new Size(viewer.Width, viewer.Height));		// don't let the popup straddle monitors
                        viewer.Left = popupPoint.X;
                        viewer.Top = popupPoint.Y;

                        viewer.Show();

                        #endregion

                        _selectedBean = new SelectedBean(clickedBean.Item1, viewer, _camera.Position - clickedBean.Item1.PositionWorld);
                    }
                }

                #endregion
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        /// <summary>
        /// This places the viewer in the corner of the screen that is farthest from the point passed in
        /// NOTE: Current monitor, not just the form
        /// </summary>
        public static void PlaceViewerInCorner(ShipViewerWindow viewer, Point screenPoint)
        {
            const double OFFSET = 50;

            Rect screenRect = UtilityWPF.GetCurrentScreen(screenPoint);

            //Size viewerSize = new Size(viewer.ActualWidth, viewer.ActualHeight);      // sometimes it's not shown yet, so actual size will be zero
            Size viewerSize = new Size(viewer.Width, viewer.Height);

            #region Get candidate locations

            List<Tuple<Rect, double>> positions = new List<Tuple<Rect, double>>();

            // TopLeft
            Rect rect = new Rect(screenRect.TopLeft, viewerSize);

            if (!rect.Contains(screenPoint))
            {
                //positions.Add(Tuple.Create(rect, (rect.BottomRight - screenPoint).Length));       // first attempt was to do the nearest corner, but that gave counterintuitive results
                positions.Add(Tuple.Create(rect, (rect.TopLeft - screenPoint).Length));
            }

            // TopRight
            rect = new Rect(new Point(screenRect.Right - viewerSize.Width, screenRect.Top), viewerSize);

            if (!rect.Contains(screenPoint))
            {
                //positions.Add(Tuple.Create(rect, (rect.BottomLeft - screenPoint).Length));
                positions.Add(Tuple.Create(rect, (rect.TopRight - screenPoint).Length));
            }

            // BottomLeft
            rect = new Rect(new Point(screenRect.Left, screenRect.Bottom - viewerSize.Height), viewerSize);

            if (!rect.Contains(screenPoint))
            {
                //positions.Add(Tuple.Create(rect, (rect.TopRight - screenPoint).Length));
                positions.Add(Tuple.Create(rect, (rect.BottomLeft - screenPoint).Length));
            }

            // BottomRight
            rect = new Rect(new Point(screenRect.Right - viewerSize.Width, screenRect.Bottom - viewerSize.Height), viewerSize);

            if (!rect.Contains(screenPoint))
            {
                //positions.Add(Tuple.Create(rect, (rect.TopLeft - screenPoint).Length));
                positions.Add(Tuple.Create(rect, (rect.BottomRight - screenPoint).Length));
            }

            #endregion

            if (positions.Count > 0)
            {
                // Find the position that places the viewer the farthest away from the point passed in
                var farthest = positions.OrderByDescending(o => o.Item2).First();

                viewer.Left = farthest.Item1.Left;
                viewer.Top = farthest.Item1.Top;

                return;
            }

            #region Overlap

            // There is overlap, push it left or right of the point
            double leftDistance = screenPoint.X - screenRect.Left;
            double rightDistance = screenRect.Right - screenPoint.X;

            double x;

            if (rightDistance < leftDistance)
            {
                // Place it to the left of the point
                x = screenPoint.X - OFFSET - viewerSize.Width;
            }
            else
            {
                // Place it to the right of the point
                x = screenPoint.X + OFFSET;
            }

            Point popupPoint = new Point(x, screenPoint.Y - (viewer.Height / 3d));
            popupPoint = UtilityWPF.EnsureWindowIsOnScreen(popupPoint, viewerSize);		// don't let the popup straddle monitors

            viewer.Left = x;        // Ignore what the straddle method tried to do to x
            viewer.Top = popupPoint.Y;      // Honor what the straddle method tried to do to y

            #endregion
        }