ShareX/ShareX.ScreenCaptureLib/RegionHelpers/AreaManager.cs

609 lines
18 KiB
C#
Raw Normal View History

2013-11-03 23:53:49 +13:00
#region License Information (GPL v3)
/*
ShareX - A program that allows you to take screenshots and share any file type
2016-01-04 04:16:01 +13:00
Copyright (c) 2007-2016 ShareX Team
2013-11-03 23:53:49 +13:00
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Optionally you can also view the license at <http://www.gnu.org/licenses/>.
*/
#endregion License Information (GPL v3)
2014-12-11 09:25:20 +13:00
using ShareX.HelpersLib;
using System;
2013-11-03 23:53:49 +13:00
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
2014-12-11 09:25:20 +13:00
namespace ShareX.ScreenCaptureLib
2013-11-03 23:53:49 +13:00
{
public class AreaManager
{
public List<BaseShape> Shapes { get; private set; }
2013-11-03 23:53:49 +13:00
public BaseRegionShape[] Regions
2013-11-03 23:53:49 +13:00
{
get
{
return Shapes.OfType<BaseRegionShape>().ToArray();
}
}
public BaseRegionShape[] ValidRegionAreas
{
get
{
return Regions.Where(x => IsAreaValid(x.Rectangle)).ToArray();
2013-11-03 23:53:49 +13:00
}
}
2015-07-17 03:21:02 +12:00
public int SelectedAreaIndex { get; private set; }
public BaseRegionShape CurrentRegionInfo
{
get
{
if (SelectedAreaIndex > -1)
{
return Regions[SelectedAreaIndex];
}
return null;
}
}
2013-11-03 23:53:49 +13:00
public Rectangle CurrentArea
{
get
{
if (SelectedAreaIndex > -1)
{
return Regions[SelectedAreaIndex].Rectangle;
2013-11-03 23:53:49 +13:00
}
return Rectangle.Empty;
}
set
{
if (SelectedAreaIndex > -1)
{
Regions[SelectedAreaIndex].Rectangle = value;
2013-11-03 23:53:49 +13:00
}
}
}
public bool IsCurrentAreaValid
{
get
{
return IsAreaValid(CurrentArea);
}
}
public Rectangle CurrentHoverArea { get; private set; }
public bool IsCurrentHoverAreaValid
{
get
{
return !CurrentHoverArea.IsEmpty;
2013-11-03 23:53:49 +13:00
}
}
public float RoundedRectangleRadius { get; set; }
public int RoundedRectangleRadiusIncrement { get; set; }
public TriangleAngle TriangleAngle { get; set; }
public Point CurrentPosition { get; private set; }
public Point PositionOnClick { get; private set; }
2013-11-03 23:53:49 +13:00
public ResizeManager ResizeManager { get; private set; }
public bool IsCreating { get; private set; }
public bool IsMoving { get; private set; }
public bool IsResizing
{
get
{
return ResizeManager.IsResizing;
}
}
public bool IsProportionalResizing { get; private set; }
public bool IsSnapResizing { get; private set; }
public List<SimpleWindowInfo> Windows { get; set; }
2013-11-03 23:53:49 +13:00
public bool WindowCaptureMode { get; set; }
2014-07-10 09:44:08 +12:00
public bool IncludeControls { get; set; }
2013-11-03 23:53:49 +13:00
public int MinimumSize { get; set; }
private RectangleRegion surface;
public AreaManager(RectangleRegion surface)
{
this.surface = surface;
ResizeManager = new ResizeManager(surface, this);
Shapes = new List<BaseShape>();
2013-11-03 23:53:49 +13:00
SelectedAreaIndex = -1;
RoundedRectangleRadius = 25;
RoundedRectangleRadiusIncrement = 3;
TriangleAngle = TriangleAngle.Top;
2016-03-02 01:05:26 +13:00
MinimumSize = 3;
2013-11-03 23:53:49 +13:00
surface.MouseDown += surface_MouseDown;
surface.MouseUp += surface_MouseUp;
surface.KeyDown += surface_KeyDown;
surface.KeyUp += surface_KeyUp;
}
private void surface_KeyDown(object sender, KeyEventArgs e)
{
2015-08-05 00:40:25 +12:00
switch (e.KeyCode)
2013-11-03 23:53:49 +13:00
{
case Keys.Insert:
if (IsCreating)
{
EndRegionSelection();
}
else
{
2015-08-21 04:29:10 +12:00
int areaIndex = SelectedAreaIndex;
if (ResizeManager.Visible)
{
DeselectArea();
}
if (0 > areaIndex || areaIndex != AreaIntersect())
{
RegionSelection(InputManager.MousePosition);
}
}
break;
case Keys.ShiftKey:
IsProportionalResizing = true;
break;
case Keys.Menu:
IsSnapResizing = true;
break;
case Keys.NumPad1:
//ChangeCurrentShape(RegionShape.Rectangle);
break;
case Keys.NumPad2:
//ChangeCurrentShape(RegionShape.RoundedRectangle);
break;
case Keys.NumPad3:
//ChangeCurrentShape(RegionShape.Ellipse);
break;
case Keys.NumPad4:
//ChangeCurrentShape(RegionShape.Triangle);
break;
case Keys.NumPad5:
//ChangeCurrentShape(RegionShape.Diamond);
break;
/*case Keys.Add:
switch (surface.Config.CurrentRegionShape)
{
case RegionShape.RoundedRectangle:
RoundedRectangleRadius += RoundedRectangleRadiusIncrement;
break;
case RegionShape.Triangle:
if (TriangleAngle == TriangleAngle.Left)
{
TriangleAngle = TriangleAngle.Top;
}
else
{
TriangleAngle++;
}
break;
}
UpdateCurrentRegionInfo();
break;
case Keys.Subtract:
switch (surface.Config.CurrentRegionShape)
{
case RegionShape.RoundedRectangle:
RoundedRectangleRadius = Math.Max(0, RoundedRectangleRadius - RoundedRectangleRadiusIncrement);
break;
case RegionShape.Triangle:
if (TriangleAngle == TriangleAngle.Top)
{
TriangleAngle = TriangleAngle.Left;
}
else
{
TriangleAngle--;
}
break;
}
UpdateCurrentRegionInfo();
break;*/
2013-11-03 23:53:49 +13:00
}
}
private void surface_KeyUp(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
2013-11-03 23:53:49 +13:00
{
case Keys.ShiftKey:
IsProportionalResizing = false;
break;
case Keys.Menu:
IsSnapResizing = false;
break;
case Keys.Delete:
RemoveCurrentArea();
2015-08-21 04:29:10 +12:00
if (IsCreating)
{
EndRegionSelection();
}
break;
2013-11-03 23:53:49 +13:00
}
}
public void Update()
{
if (IsMoving)
{
Rectangle rect = CurrentArea;
rect.X += InputManager.MouseVelocity.X;
rect.Y += InputManager.MouseVelocity.Y;
CurrentArea = rect;
}
if (IsCreating && !CurrentArea.IsEmpty)
{
CurrentPosition = InputManager.MousePosition0Based;
2013-11-03 23:53:49 +13:00
Point newPosition = CurrentPosition;
2013-11-03 23:53:49 +13:00
if (IsProportionalResizing)
2013-11-03 23:53:49 +13:00
{
newPosition = CaptureHelpers.ProportionalPosition(PositionOnClick, CurrentPosition);
2013-11-03 23:53:49 +13:00
}
if (IsSnapResizing)
{
newPosition = SnapPosition(PositionOnClick, newPosition);
}
CurrentArea = CaptureHelpers.CreateRectangle(PositionOnClick, newPosition);
2013-11-03 23:53:49 +13:00
}
CheckHover();
ResizeManager.Update();
}
private Point SnapPosition(Point posOnClick, Point posCurrent)
{
Rectangle currentRect = CaptureHelpers.CreateRectangle(posOnClick, posCurrent);
Point newPosition = posCurrent;
foreach (SnapSize size in surface.Config.SnapSizes)
{
if (currentRect.Width.IsBetween(size.Width - surface.Config.SnapDistance, size.Width + surface.Config.SnapDistance) ||
currentRect.Height.IsBetween(size.Height - surface.Config.SnapDistance, size.Height + surface.Config.SnapDistance))
{
newPosition = CaptureHelpers.CalculateNewPosition(posOnClick, posCurrent, size);
break;
}
}
Rectangle newRect = CaptureHelpers.CreateRectangle(posOnClick, newPosition);
if (surface.ScreenRectangle0Based.Contains(newRect))
{
return newPosition;
}
return posCurrent;
}
2013-11-03 23:53:49 +13:00
private void CheckHover()
{
CurrentHoverArea = Rectangle.Empty;
if (!ResizeManager.IsCursorOnNode() && !IsCreating && !IsMoving && !IsResizing)
{
Rectangle hoverArea = GetAreaIntersectWithMouse();
if (!hoverArea.IsEmpty)
{
CurrentHoverArea = hoverArea;
}
else
2013-11-03 23:53:49 +13:00
{
SimpleWindowInfo window = FindSelectedWindow();
2013-11-03 23:53:49 +13:00
if (window != null && !window.Rectangle.IsEmpty)
2013-11-03 23:53:49 +13:00
{
hoverArea = CaptureHelpers.ScreenToClient(window.Rectangle);
2013-11-03 23:53:49 +13:00
CurrentHoverArea = Rectangle.Intersect(surface.ScreenRectangle0Based, hoverArea);
}
}
}
}
public SimpleWindowInfo FindSelectedWindow()
{
if (Windows != null)
{
return Windows.FirstOrDefault(x => x.Rectangle.Contains(InputManager.MousePosition));
}
return null;
}
public WindowInfo FindSelectedWindowInfo(Point mousePosition)
{
if (Windows != null)
{
SimpleWindowInfo windowInfo = Windows.FirstOrDefault(x => x.IsWindow && x.Rectangle.Contains(mousePosition));
if (windowInfo != null)
{
return windowInfo.WindowInfo;
}
}
return null;
}
2013-11-03 23:53:49 +13:00
private void surface_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
2015-08-21 04:29:10 +12:00
if (!IsCreating)
{
RegionSelection(e.Location);
}
}
}
private void surface_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
2015-08-28 02:32:30 +12:00
if (IsMoving || IsCreating)
{
EndRegionSelection();
}
}
else if (e.Button == MouseButtons.Right)
{
CancelRegionSelection();
2015-08-28 02:32:30 +12:00
if (IsCreating)
{
EndRegionSelection();
}
}
}
private void RegionSelection(Point location)
{
if (ResizeManager.IsCursorOnNode())
{
return;
}
2013-11-03 23:53:49 +13:00
int areaIndex = AreaIntersect(InputManager.MousePosition0Based);
PositionOnClick = InputManager.MousePosition0Based;
2013-11-03 23:53:49 +13:00
if (areaIndex > -1) // Select area
{
IsMoving = true;
SelectedAreaIndex = areaIndex;
SelectArea();
}
else if (!IsCreating) // Create new area
2013-11-03 23:53:49 +13:00
{
DeselectArea();
2013-11-03 23:53:49 +13:00
Rectangle rect;
if (surface.Config.IsFixedSize)
2013-11-03 23:53:49 +13:00
{
IsMoving = true;
rect = new Rectangle(new Point(location.X - surface.Config.FixedSize.Width / 2, location.Y - surface.Config.FixedSize.Height / 2), surface.Config.FixedSize);
2013-11-03 23:53:49 +13:00
}
else
2013-11-03 23:53:49 +13:00
{
IsCreating = true;
rect = new Rectangle(location, new Size(1, 1));
2013-11-03 23:53:49 +13:00
}
AddRegionInfo(rect);
2013-11-03 23:53:49 +13:00
}
}
private void EndRegionSelection()
2013-11-03 23:53:49 +13:00
{
IsCreating = false;
IsMoving = false;
2013-11-03 23:53:49 +13:00
if (!CurrentArea.IsEmpty)
{
if (!IsCurrentAreaValid)
2013-11-03 23:53:49 +13:00
{
RemoveCurrentArea();
CheckHover();
2013-11-03 23:53:49 +13:00
}
else if (surface.Config.QuickCrop)
2013-11-03 23:53:49 +13:00
{
surface.UpdateRegionPath();
surface.Close(SurfaceResult.Region);
}
else
{
SelectArea();
2013-11-03 23:53:49 +13:00
}
}
if (!CurrentHoverArea.IsEmpty)
2013-11-03 23:53:49 +13:00
{
AddRegionInfo(CurrentHoverArea);
2013-11-03 23:53:49 +13:00
if (surface.Config.QuickCrop)
2013-11-03 23:53:49 +13:00
{
surface.UpdateRegionPath();
surface.Close(SurfaceResult.Region);
2013-11-03 23:53:49 +13:00
}
else
{
SelectArea();
2013-11-03 23:53:49 +13:00
}
}
}
private void CancelRegionSelection()
{
int areaIndex = AreaIntersect();
if (areaIndex > -1)
{
//Areas.RemoveAt(areaIndex);
DeselectArea();
}
else
{
surface.Close(SurfaceResult.Close);
}
}
private void ChangeCurrentShape(BaseShape shape)
{
2015-07-17 07:51:19 +12:00
surface.Config.CurrentRegionShape = shape;
UpdateCurrentRegionInfo();
}
private void AddRegionInfo(Rectangle rect)
{
Shapes.Add(GetRegionInfo(rect));
SelectedAreaIndex = Regions.Length - 1;
}
public BaseRegionShape GetRegionInfo(Rectangle rect)
{
BaseRegionShape regionInfo = new RectangleRegionShape()
{
Rectangle = rect
};
//surface.Config.CurrentRegionShape
//regionInfo.RoundedRectangleRadius = RoundedRectangleRadius;
//regionInfo.TriangleAngle = TriangleAngle;
return regionInfo;
}
private void UpdateCurrentRegionInfo()
{
BaseShape regionInfo = CurrentRegionInfo;
2015-07-17 07:51:19 +12:00
if (regionInfo != null)
{
/*regionInfo.Shape = surface.Config.CurrentRegionShape;
2015-07-17 07:51:19 +12:00
regionInfo.RoundedRectangleRadius = RoundedRectangleRadius;
regionInfo.TriangleAngle = TriangleAngle;*/
2015-07-17 07:51:19 +12:00
}
}
2013-11-03 23:53:49 +13:00
private void SelectArea()
{
if (!CurrentArea.IsEmpty && !surface.Config.IsFixedSize)
{
ResizeManager.Show();
}
}
private void DeselectArea()
{
SelectedAreaIndex = -1;
ResizeManager.Hide();
}
private void RemoveCurrentArea()
{
BaseShape shape = CurrentRegionInfo;
if (shape != null)
2013-11-03 23:53:49 +13:00
{
Shapes.Remove(shape);
2013-11-03 23:53:49 +13:00
DeselectArea();
}
}
private bool IsAreaValid(Rectangle rect)
{
return !rect.IsEmpty && rect.Width >= MinimumSize && rect.Height >= MinimumSize;
}
public int AreaIntersect(Point mousePosition)
{
for (int i = Regions.Length - 1; i >= 0; i--)
2013-11-03 23:53:49 +13:00
{
if (Regions[i].Rectangle.Contains(mousePosition))
2013-11-03 23:53:49 +13:00
{
return i;
}
}
return -1;
}
public int AreaIntersect()
{
return AreaIntersect(InputManager.MousePosition0Based);
}
public Rectangle GetAreaIntersectWithMouse()
{
int areaIndex = AreaIntersect();
if (areaIndex > -1)
{
return Regions[areaIndex].Rectangle;
2013-11-03 23:53:49 +13:00
}
return Rectangle.Empty;
}
public bool IsAreaIntersect()
{
return AreaIntersect() > -1;
}
public Rectangle CombineAreas()
{
BaseShape[] areas = ValidRegionAreas;
2013-11-03 23:53:49 +13:00
2015-07-17 03:21:02 +12:00
if (areas.Length > 0)
2013-11-03 23:53:49 +13:00
{
Rectangle rect = areas[0].Rectangle;
2013-11-03 23:53:49 +13:00
2015-07-17 03:21:02 +12:00
for (int i = 1; i < areas.Length; i++)
2013-11-03 23:53:49 +13:00
{
rect = Rectangle.Union(rect, areas[i].Rectangle);
2013-11-03 23:53:49 +13:00
}
return rect;
}
return Rectangle.Empty;
}
}
2015-09-01 22:43:03 +12:00
}