Exemplo n.º 1
0
        /// <summary>
        ///     Paint the actual visible parts
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnPaint(object sender, PaintEventArgs e)
        {
            var graphics      = e.Graphics;
            var clipRectangle = e.ClipRectangle;

            graphics.DrawImageUnscaled(_capture.Bitmap, Point.Empty);
            // Only draw Cursor if it's (partly) visible
            if (_capture.Cursor != null && _capture.CursorVisible && clipRectangle.IntersectsWith(new Rectangle(_capture.CursorLocation, _capture.Cursor.Size)))
            {
                graphics.DrawIcon(_capture.Cursor, _capture.CursorLocation.X, _capture.CursorLocation.Y);
            }

            if (_mouseDown || UsedCaptureMode == CaptureMode.Window || IsAnimating(_windowAnimator))
            {
                _captureRect = _captureRect.Intersect(new Rectangle(Point.Empty, _capture.ScreenBounds.Size)); // crop what is outside the screen

                var fixedRect = IsAnimating(_windowAnimator) ? _windowAnimator.Current : _captureRect;

                // If the _windowScroller != null, we can (most likely) capture the window with a scrolling technique
                if (WindowScroller != null && Equals(WindowScroller.ScrollBarWindow, SelectedCaptureWindow))
                {
                    graphics.FillRectangle(ScrollingOverlayBrush, fixedRect);
                }
                else
                {
                    graphics.FillRectangle(GreenOverlayBrush, fixedRect);
                }
                graphics.DrawRectangle(OverlayPen, fixedRect);

                // rulers
                const int dist = 8;

                string captureWidth;
                string captureHeight;
                // The following fixes the very old incorrect size information bug
                if (UsedCaptureMode == CaptureMode.Window)
                {
                    captureWidth  = _captureRect.Width.ToString(CultureInfo.InvariantCulture);
                    captureHeight = _captureRect.Height.ToString(CultureInfo.InvariantCulture);
                }
                else
                {
                    captureWidth  = (_captureRect.Width + 1).ToString(CultureInfo.InvariantCulture);
                    captureHeight = (_captureRect.Height + 1).ToString(CultureInfo.InvariantCulture);
                }
                using (var rulerFont = new Font(FontFamily.GenericSansSerif, 8))
                {
                    var   measureWidth  = TextRenderer.MeasureText(captureWidth, rulerFont);
                    var   measureHeight = TextRenderer.MeasureText(captureHeight, rulerFont);
                    var   hSpace        = measureWidth.Width + 3;
                    var   vSpace        = measureHeight.Height + 3;
                    Brush bgBrush       = new SolidBrush(Color.FromArgb(200, 217, 240, 227));
                    var   rulerPen      = new Pen(Color.SeaGreen);

                    // horizontal ruler
                    if (fixedRect.Width > hSpace + 3)
                    {
                        using (var p = RoundedRectangle.Create2(
                                   fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3,
                                   fixedRect.Y - dist - 7,
                                   measureWidth.Width - 3,
                                   measureWidth.Height,
                                   3))
                        {
                            graphics.FillPath(bgBrush, p);
                            graphics.DrawPath(rulerPen, p);
                            graphics.DrawString(captureWidth, rulerFont, rulerPen.Brush, fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, fixedRect.Y - dist - 7);
                            graphics.DrawLine(rulerPen, fixedRect.X, fixedRect.Y - dist, fixedRect.X + (fixedRect.Width / 2 - hSpace / 2), fixedRect.Y - dist);
                            graphics.DrawLine(rulerPen, fixedRect.X + fixedRect.Width / 2 + hSpace / 2, fixedRect.Y - dist, fixedRect.X + fixedRect.Width, fixedRect.Y - dist);
                            graphics.DrawLine(rulerPen, fixedRect.X, fixedRect.Y - dist - 3, fixedRect.X, fixedRect.Y - dist + 3);
                            graphics.DrawLine(rulerPen, fixedRect.X + fixedRect.Width, fixedRect.Y - dist - 3, fixedRect.X + fixedRect.Width, fixedRect.Y - dist + 3);
                        }
                    }

                    // vertical ruler
                    if (fixedRect.Height > vSpace + 3)
                    {
                        using (var p = RoundedRectangle.Create2(
                                   fixedRect.X - measureHeight.Width + 1,
                                   fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2,
                                   measureHeight.Width - 3,
                                   measureHeight.Height - 1,
                                   3))
                        {
                            graphics.FillPath(bgBrush, p);
                            graphics.DrawPath(rulerPen, p);
                            graphics.DrawString(captureHeight, rulerFont, rulerPen.Brush, fixedRect.X - measureHeight.Width + 1, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2);
                            graphics.DrawLine(rulerPen, fixedRect.X - dist, fixedRect.Y, fixedRect.X - dist, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2));
                            graphics.DrawLine(rulerPen, fixedRect.X - dist, fixedRect.Y + fixedRect.Height / 2 + vSpace / 2, fixedRect.X - dist, fixedRect.Y + fixedRect.Height);
                            graphics.DrawLine(rulerPen, fixedRect.X - dist - 3, fixedRect.Y, fixedRect.X - dist + 3, fixedRect.Y);
                            graphics.DrawLine(rulerPen, fixedRect.X - dist - 3, fixedRect.Y + fixedRect.Height, fixedRect.X - dist + 3, fixedRect.Y + fixedRect.Height);
                        }
                    }

                    rulerPen.Dispose();
                    bgBrush.Dispose();
                }

                // Display size of selected rectangle
                // Prepare the font and text.
                using (var sizeFont = new Font(FontFamily.GenericSansSerif, 12))
                {
                    // When capturing a Region we need to add 1 to the height/width for correction
                    string sizeText;
                    if (UsedCaptureMode == CaptureMode.Region)
                    {
                        // correct the GUI width to real width for the shown size
                        sizeText = _captureRect.Width + 1 + " x " + (_captureRect.Height + 1);
                    }
                    else
                    {
                        sizeText = _captureRect.Width + " x " + _captureRect.Height;
                    }

                    // Calculate the scaled font size.
                    var extent  = graphics.MeasureString(sizeText, sizeFont);
                    var hRatio  = _captureRect.Height / (extent.Height * 2);
                    var wRatio  = _captureRect.Width / (extent.Width * 2);
                    var ratio   = hRatio < wRatio ? hRatio : wRatio;
                    var newSize = sizeFont.Size * ratio;

                    if (newSize >= 4)
                    {
                        // Only show if 4pt or larger.
                        if (newSize > 20)
                        {
                            newSize = 20;
                        }
                        // Draw the size.
                        using (var newSizeFont = new Font(FontFamily.GenericSansSerif, newSize, FontStyle.Bold))
                        {
                            var sizeLocation = new PointF(fixedRect.X + _captureRect.Width / 2 - extent.Width / 2, fixedRect.Y + _captureRect.Height / 2 - newSizeFont.GetHeight() / 2);
                            graphics.DrawString(sizeText, newSizeFont, Brushes.LightSeaGreen, sizeLocation);

                            if (_showDebugInfo && SelectedCaptureWindow != null)
                            {
                                using (var process = Process.GetProcessById(SelectedCaptureWindow.GetProcessId()))
                                {
                                    string title         = $"#{SelectedCaptureWindow.Handle.ToInt64():X} - {(SelectedCaptureWindow.Text.Length > 0 ? SelectedCaptureWindow.Text : process.ProcessName)}";
                                    var    debugLocation = new PointF(fixedRect.X, fixedRect.Y);
                                    graphics.DrawString(title, sizeFont, Brushes.DarkOrange, debugLocation);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                using (var pen = new Pen(Color.LightSeaGreen))
                {
                    pen.DashStyle = DashStyle.Dot;
                    var screenBounds = _capture.ScreenBounds;
                    graphics.DrawLine(pen, _cursorPos.X, screenBounds.Y, _cursorPos.X, screenBounds.Height);
                    graphics.DrawLine(pen, screenBounds.X, _cursorPos.Y, screenBounds.Width, _cursorPos.Y);
                }

                var xy = _cursorPos.X + " x " + _cursorPos.Y;
                using (var f = new Font(FontFamily.GenericSansSerif, 8))
                {
                    var xySize = TextRenderer.MeasureText(xy, f);
                    using (var gp = RoundedRectangle.Create2(_cursorPos.X + 5, _cursorPos.Y + 5, xySize.Width - 3, xySize.Height, 3))
                    {
                        using (Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227)))
                        {
                            graphics.FillPath(bgBrush, gp);
                        }
                        using (var pen = new Pen(Color.SeaGreen))
                        {
                            graphics.DrawPath(pen, gp);
                            var coordinatePosition = new Point(_cursorPos.X + 5, _cursorPos.Y + 5);
                            graphics.DrawString(xy, f, pen.Brush, coordinatePosition);
                        }
                    }
                }
            }

            // Zoom
            if (_zoomAnimator == null || (!IsAnimating(_zoomAnimator) && UsedCaptureMode == CaptureMode.Window))
            {
                return;
            }
            const int zoomSourceWidth  = 25;
            const int zoomSourceHeight = 25;

            var sourceRectangle = new NativeRect(_cursorPos.X - zoomSourceWidth / 2, _cursorPos.Y - zoomSourceHeight / 2, zoomSourceWidth, zoomSourceHeight);

            var destinationRectangle = _zoomAnimator.Current.Offset(_cursorPos);

            DrawZoom(graphics, sourceRectangle, destinationRectangle);
        }
Exemplo n.º 2
0
        /// <summary>
        ///     update the frame, this only invalidates
        /// </summary>
        protected override void Animate()
        {
            var lastPos = _cursorPos;

            _cursorPos = _mouseMovePos;

            if (SelectedCaptureWindow != null && lastPos.Equals(_cursorPos) && !IsAnimating(_zoomAnimator) && !IsAnimating(_windowAnimator))
            {
                return;
            }

            var lastWindow     = SelectedCaptureWindow;
            var horizontalMove = false;
            var verticalMove   = false;

            if (lastPos.X != _cursorPos.X)
            {
                horizontalMove = true;
            }
            if (lastPos.Y != _cursorPos.Y)
            {
                verticalMove = true;
            }

            if (UsedCaptureMode == CaptureMode.Region && _mouseDown)
            {
                _captureRect = new NativeRect(_cursorPos.X, _cursorPos.Y, _mX - _cursorPos.X, _mY - _cursorPos.Y).Normalize();
            }

            // Iterate over the found windows and check if the current location is inside a window
            var cursorPosition = Cursor.Position;

            SelectedCaptureWindow = null;


            // Store the top window
            IInteropWindow selectedTopWindow = null;

            foreach (var window in _windows)
            {
                if (window.Handle == Handle)
                {
                    // Ignore us
                    continue;
                }
                if (!window.GetInfo().Bounds.Contains(cursorPosition))
                {
                    continue;
                }

                selectedTopWindow     = window;
                SelectedCaptureWindow = window;

                // Only go over the children if we are in window mode
                if (CaptureMode.Window != UsedCaptureMode)
                {
                    break;
                }

                // Find the child window which is under the mouse
                // Start with the parent, drill down
                var selectedChildWindow = window;
                // TODO: Limit the levels we go down?
                do
                {
                    // Drill down, via the ZOrder
                    var tmpChildWindow = selectedChildWindow
                                         .GetZOrderedChildren()
                                         .FirstOrDefault(interopWindow => interopWindow.GetInfo().Bounds.Contains(cursorPosition));

                    if (tmpChildWindow == null)
                    {
                        break;
                    }
                    selectedChildWindow = tmpChildWindow;
                } while (true);

                // Assign the found child window
                SelectedCaptureWindow = selectedChildWindow;

                break;
            }

            // Test if something changed
            if (SelectedCaptureWindow != null && !SelectedCaptureWindow.Equals(lastWindow))
            {
                _capture.CaptureDetails.Title = selectedTopWindow.Text;
                _capture.CaptureDetails.AddMetaData("windowtitle", selectedTopWindow.Text);
                if (UsedCaptureMode == CaptureMode.Window)
                {
                    // Recreate the WindowScroller, if this is enabled, so we can detect if we can scroll
                    if (Conf.IsScrollingCaptureEnabled)
                    {
                        WindowScroller = SelectedCaptureWindow.GetWindowScroller(ScrollBarTypes.Vertical);
                        if (WindowScroller == null)
                        {
                            foreach (var interopWindow in SelectedCaptureWindow.GetChildren())
                            {
                                interopWindow.Dump();
                            }

                            WindowScroller = SelectedCaptureWindow.GetChildren().Select(child => child.GetWindowScroller(ScrollBarTypes.Vertical)).FirstOrDefault(scroller => scroller != null);
                        }
                    }

                    // We store the bound of the selected (child) window
                    // If it's maximized we take the client-bounds, otherwise we have parts we should not copy.
                    if (SelectedCaptureWindow.IsMaximized())
                    {
                        _captureRect = SelectedCaptureWindow.GetInfo().ClientBounds;
                    }
                    else
                    {
                        _captureRect = SelectedCaptureWindow.GetInfo().Bounds;
                    }

                    // Make sure the bounds fit to it's parent, some windows are bigger than their parent
                    // But only for non popups
                    if (!SelectedCaptureWindow.GetInfo().Style.HasFlag(WindowStyleFlags.WS_POPUP))
                    {
                        var parent = SelectedCaptureWindow.GetParent();
                        while (parent != IntPtr.Zero)
                        {
                            var parentWindow = InteropWindowFactory.CreateFor(parent);
                            _captureRect = _captureRect.Intersect(parentWindow.GetInfo().Bounds);
                            parent       = parentWindow.GetParent();
                        }
                    }

                    // As the ClientRectangle is in screen coordinates and not in bitmap coordinates, we need to correct.
                    _captureRect = _captureRect.Offset(-_capture.ScreenBounds.Location.X, -_capture.ScreenBounds.Location.Y);
                }
            }

            NativeRectFloat invalidateRectangle;

            if (_mouseDown && UsedCaptureMode != CaptureMode.Window)
            {
                var x1 = Math.Min(_mX, lastPos.X);
                var x2 = Math.Max(_mX, lastPos.X);
                var y1 = Math.Min(_mY, lastPos.Y);
                var y2 = Math.Max(_mY, lastPos.Y);
                x1 = Math.Min(x1, _cursorPos.X);
                x2 = Math.Max(x2, _cursorPos.X);
                y1 = Math.Min(y1, _cursorPos.Y);
                y2 = Math.Max(y2, _cursorPos.Y);

                // Safety correction
                x2 += 2;
                y2 += 2;

                // Here we correct for text-size

                // Calculate the size
                var textForWidth  = Math.Max(Math.Abs(_mX - _cursorPos.X), Math.Abs(_mX - lastPos.X));
                var textForHeight = Math.Max(Math.Abs(_mY - _cursorPos.Y), Math.Abs(_mY - lastPos.Y));

                using (var rulerFont = new Font(FontFamily.GenericSansSerif, 8))
                {
                    var textWidth = TextRenderer.MeasureText(textForWidth.ToString(CultureInfo.InvariantCulture), rulerFont);
                    x1 -= textWidth.Width + 15;

                    var textHeight = TextRenderer.MeasureText(textForHeight.ToString(CultureInfo.InvariantCulture), rulerFont);
                    y1 -= textHeight.Height + 10;
                }
                invalidateRectangle = new Rectangle(x1, y1, x2 - x1, y2 - y1);
                Invalidate(invalidateRectangle);
            }
            else if (UsedCaptureMode != CaptureMode.Window)
            {
                var allScreenBounds = WindowCapture.GetScreenBounds();

                allScreenBounds = allScreenBounds.MoveTo(WindowCapture.GetLocationRelativeToScreenBounds(allScreenBounds.Location));
                if (verticalMove)
                {
                    // Before
                    invalidateRectangle = new NativeRect(allScreenBounds.Left, lastPos.Y - 2, Width + 2, 45).Normalize();
                    Invalidate(invalidateRectangle);
                    // After
                    invalidateRectangle = new NativeRect(allScreenBounds.Left, _cursorPos.Y - 2, Width + 2, 45).Normalize();
                    Invalidate(invalidateRectangle);
                }
                if (horizontalMove)
                {
                    // Before
                    invalidateRectangle = new NativeRect(lastPos.X - 2, allScreenBounds.Top, 75, Height + 2).Normalize();
                    Invalidate(invalidateRectangle);
                    // After
                    invalidateRectangle = new NativeRect(_cursorPos.X - 2, allScreenBounds.Top, 75, Height + 2).Normalize();
                    Invalidate(invalidateRectangle);
                }
            }
            else if (SelectedCaptureWindow != null && !SelectedCaptureWindow.Equals(lastWindow))
            {
                // Window changed, animate from current to newly selected window
                _windowAnimator.ChangeDestination(_captureRect, FramesForMillis(700));
            }
            // always animate the Window area through to the last frame, so we see the fade-in/out untill the end
            // Using a safety "offset" to make sure the text is invalidated too
            const int safetySize = 30;

            // Check if the animation needs to be drawn
            if (IsAnimating(_windowAnimator))
            {
                invalidateRectangle = _windowAnimator.Current.Inflate(safetySize, safetySize);
                Invalidate(invalidateRectangle);
                invalidateRectangle = _windowAnimator.Next().Inflate(safetySize, safetySize);
                Invalidate(invalidateRectangle);
                // Check if this was the last of the windows animations in the normal region capture.
                if (UsedCaptureMode != CaptureMode.Window && !IsAnimating(_windowAnimator))
                {
                    Invalidate();
                }
            }

            if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || UsedCaptureMode != CaptureMode.Window))
            {
                // Make sure we invalidate the old zoom area
                invalidateRectangle = _zoomAnimator.Current.Offset(lastPos);
                Invalidate(invalidateRectangle);
                // Only verify if we are really showing the zoom, not the outgoing animation
                if (Conf.ZoomerEnabled && UsedCaptureMode != CaptureMode.Window)
                {
                    VerifyZoomAnimation(_cursorPos, false);
                }
                // The following logic is not needed, next always returns the current if there are no frames left
                // but it makes more sense if we want to change something in the logic
                invalidateRectangle = IsAnimating(_zoomAnimator) ? _zoomAnimator.Next() : _zoomAnimator.Current;
                Invalidate(invalidateRectangle.Offset(_cursorPos));
            }
            // Force update "now"
            Update();
        }