mirror of
https://github.com/ShareX/ShareX.git
synced 2024-08-24 06:32:13 +12:00
479 lines
No EOL
16 KiB
C#
479 lines
No EOL
16 KiB
C#
#region License Information (GPL v3)
|
|
|
|
/*
|
|
ShareX - A program that allows you to take screenshots and share any file type
|
|
Copyright (c) 2007-2024 ShareX Team
|
|
|
|
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)
|
|
|
|
using ShareX.HelpersLib;
|
|
using ShareX.ScreenCaptureLib.Properties;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
|
|
namespace ShareX.ScreenCaptureLib
|
|
{
|
|
public partial class ScreenRecordForm : Form
|
|
{
|
|
public event Action StopRequested;
|
|
|
|
private ScreenRecordingStatus status;
|
|
|
|
public ScreenRecordingStatus Status
|
|
{
|
|
get
|
|
{
|
|
return status;
|
|
}
|
|
private set
|
|
{
|
|
status = value;
|
|
}
|
|
}
|
|
|
|
public TimeSpan Countdown { get; set; }
|
|
public bool IsCountdown { get; private set; }
|
|
public Stopwatch Timer { get; private set; }
|
|
public ManualResetEvent RecordResetEvent { get; set; }
|
|
|
|
public bool ActivateWindow { get; set; } = true;
|
|
public float Duration { get; set; } = 0;
|
|
public bool AskConfirmationOnAbort { get; set; } = false;
|
|
|
|
public Rectangle RecordingRegion
|
|
{
|
|
get
|
|
{
|
|
return GetRecordingRegion(Location);
|
|
}
|
|
}
|
|
|
|
protected override bool ShowWithoutActivation
|
|
{
|
|
get
|
|
{
|
|
return !ActivateWindow;
|
|
}
|
|
}
|
|
|
|
protected override CreateParams CreateParams
|
|
{
|
|
get
|
|
{
|
|
CreateParams createParams = base.CreateParams;
|
|
createParams.ExStyle |= (int)(WindowStyles.WS_EX_TOPMOST | WindowStyles.WS_EX_TOOLWINDOW);
|
|
return createParams;
|
|
}
|
|
}
|
|
|
|
private Color borderColor = Color.Red;
|
|
private Rectangle borderRectangle;
|
|
private Rectangle borderRectangle0Based;
|
|
private bool dragging;
|
|
private Point initialLocation;
|
|
private static int lastIconStatus = -1;
|
|
private const int panelOffset = 3;
|
|
|
|
public ScreenRecordForm(Rectangle regionRectangle)
|
|
{
|
|
InitializeComponent();
|
|
ShareXResources.ApplyTheme(this);
|
|
niTray.Icon = ShareXResources.Icon;
|
|
|
|
borderRectangle = regionRectangle.Offset(1);
|
|
borderRectangle0Based = new Rectangle(0, 0, borderRectangle.Width, borderRectangle.Height);
|
|
|
|
Location = borderRectangle.Location;
|
|
int windowWidth = Math.Max(borderRectangle.Width, pInfo.Width);
|
|
Size = new Size(windowWidth, borderRectangle.Height + panelOffset + pInfo.Height);
|
|
pInfo.Location = new Point(0, borderRectangle.Height + panelOffset);
|
|
|
|
Region region = new Region(ClientRectangle);
|
|
region.Exclude(borderRectangle0Based.Offset(-1));
|
|
region.Exclude(new Rectangle(0, borderRectangle.Height, windowWidth, panelOffset));
|
|
if (borderRectangle.Width < pInfo.Width)
|
|
{
|
|
region.Exclude(new Rectangle(borderRectangle.Width, 0, pInfo.Width - borderRectangle.Width, borderRectangle.Height));
|
|
}
|
|
else if (borderRectangle.Width > pInfo.Width)
|
|
{
|
|
region.Exclude(new Rectangle(pInfo.Width, borderRectangle.Height + panelOffset, borderRectangle.Width - pInfo.Width, pInfo.Height));
|
|
}
|
|
Region = region;
|
|
|
|
Timer = new Stopwatch();
|
|
UpdateTimer();
|
|
|
|
RecordResetEvent = new ManualResetEvent(false);
|
|
|
|
ChangeState(ScreenRecordState.Waiting);
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (components != null)
|
|
{
|
|
components.Dispose();
|
|
}
|
|
|
|
if (RecordResetEvent != null)
|
|
{
|
|
RecordResetEvent.Dispose();
|
|
}
|
|
}
|
|
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
private Rectangle GetRecordingRegion(Point windowLocation)
|
|
{
|
|
return new Rectangle(windowLocation.X + 1, windowLocation.Y + 1, borderRectangle.Width - 2, borderRectangle.Height - 2);
|
|
}
|
|
|
|
public void StartStopRecording()
|
|
{
|
|
if (Status == ScreenRecordingStatus.Working)
|
|
{
|
|
AbortRecording();
|
|
}
|
|
else if (Status == ScreenRecordingStatus.Recording)
|
|
{
|
|
Status = ScreenRecordingStatus.Stopped;
|
|
OnStopRequested();
|
|
}
|
|
else if (Status == ScreenRecordingStatus.Paused)
|
|
{
|
|
Status = ScreenRecordingStatus.Stopped;
|
|
RecordResetEvent?.Set();
|
|
}
|
|
else
|
|
{
|
|
RecordResetEvent?.Set();
|
|
}
|
|
}
|
|
|
|
public void PauseResumeRecording()
|
|
{
|
|
if (Status == ScreenRecordingStatus.Recording)
|
|
{
|
|
Status = ScreenRecordingStatus.Paused;
|
|
RecordResetEvent?.Reset();
|
|
OnStopRequested();
|
|
}
|
|
else
|
|
{
|
|
RecordResetEvent?.Set();
|
|
}
|
|
}
|
|
|
|
public void AbortRecording()
|
|
{
|
|
Status = ScreenRecordingStatus.Aborted;
|
|
OnStopRequested();
|
|
RecordResetEvent?.Set();
|
|
}
|
|
|
|
protected void OnStopRequested()
|
|
{
|
|
StopRequested?.Invoke();
|
|
}
|
|
|
|
public void StartCountdown(int milliseconds)
|
|
{
|
|
IsCountdown = true;
|
|
Countdown = TimeSpan.FromMilliseconds(milliseconds);
|
|
|
|
Timer.Start();
|
|
timerRefresh.Start();
|
|
UpdateTimer();
|
|
}
|
|
|
|
public void StartRecordingTimer()
|
|
{
|
|
if (IsCountdown)
|
|
{
|
|
Timer.Reset();
|
|
IsCountdown = false;
|
|
}
|
|
|
|
if (Duration > 0)
|
|
{
|
|
IsCountdown = true;
|
|
Countdown = TimeSpan.FromSeconds(Duration);
|
|
}
|
|
|
|
borderColor = Color.Lime;
|
|
Refresh();
|
|
|
|
Timer.Start();
|
|
timerRefresh.Start();
|
|
UpdateTimer();
|
|
}
|
|
|
|
public void StopRecordingTimer()
|
|
{
|
|
Timer.Stop();
|
|
timerRefresh.Stop();
|
|
UpdateTimer();
|
|
}
|
|
|
|
private void UpdateTimer()
|
|
{
|
|
if (!IsDisposed)
|
|
{
|
|
TimeSpan timer;
|
|
|
|
if (IsCountdown)
|
|
{
|
|
timer = Countdown - Timer.Elapsed;
|
|
if (timer.Ticks < 0) timer = TimeSpan.Zero;
|
|
}
|
|
else
|
|
{
|
|
timer = Timer.Elapsed;
|
|
}
|
|
|
|
lblTimer.Text = timer.ToString("mm\\:ss\\:ff");
|
|
}
|
|
}
|
|
|
|
private void UpdateUI()
|
|
{
|
|
switch (Status)
|
|
{
|
|
case ScreenRecordingStatus.Working:
|
|
string trayTextWorking = "ShareX - " + Resources.ScreenRecordForm_StartRecording_Click_tray_icon_to_stop_recording_;
|
|
niTray.Text = trayTextWorking.Truncate(63);
|
|
niTray.Icon = Resources.control_record.ToIcon();
|
|
btnStart.Text = Resources.ScreenRecordForm_Stop;
|
|
tsmiStart.Text = Resources.ScreenRecordForm_Stop;
|
|
tsmiStart.Image = Resources.tick;
|
|
break;
|
|
case ScreenRecordingStatus.Waiting:
|
|
case ScreenRecordingStatus.Paused:
|
|
if (Status == ScreenRecordingStatus.Paused)
|
|
{
|
|
string trayTextWaiting = "ShareX - " + Resources.ScreenRecordForm_StartRecording_Click_tray_icon_to_stop_recording_;
|
|
niTray.Text = trayTextWaiting.Truncate(63);
|
|
}
|
|
else
|
|
{
|
|
string trayTextBeforeStart = "ShareX - " + Resources.ScreenRecordForm_StartRecording_Click_tray_icon_to_start_recording_;
|
|
niTray.Text = trayTextBeforeStart.Truncate(63);
|
|
}
|
|
niTray.Icon = Resources.control_record_yellow.ToIcon();
|
|
btnPause.Text = Resources.Resume;
|
|
tsmiPause.Text = Resources.Resume;
|
|
tsmiPause.Image = Resources.control;
|
|
lblTimer.Cursor = Cursors.SizeAll;
|
|
borderColor = Color.FromArgb(241, 196, 27);
|
|
Refresh();
|
|
break;
|
|
case ScreenRecordingStatus.Recording:
|
|
niTray.Icon = Resources.control_record.ToIcon();
|
|
btnPause.Text = Resources.Pause;
|
|
tsmiPause.Text = Resources.Pause;
|
|
tsmiPause.Image = Resources.control_pause;
|
|
lblTimer.Cursor = Cursors.Default;
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void ChangeState(ScreenRecordState state)
|
|
{
|
|
this.InvokeSafe(() =>
|
|
{
|
|
switch (state)
|
|
{
|
|
case ScreenRecordState.Waiting:
|
|
string trayTextWaiting = "ShareX - " + Resources.ScreenRecordForm_StartRecording_Waiting___;
|
|
niTray.Text = trayTextWaiting.Truncate(63);
|
|
niTray.Icon = Resources.control_record_yellow.ToIcon();
|
|
cmsMain.Enabled = false;
|
|
niTray.Visible = true;
|
|
break;
|
|
case ScreenRecordState.BeforeStart:
|
|
cmsMain.Enabled = true;
|
|
UpdateUI();
|
|
break;
|
|
case ScreenRecordState.AfterStart:
|
|
dragging = false;
|
|
Status = ScreenRecordingStatus.Working;
|
|
UpdateUI();
|
|
break;
|
|
case ScreenRecordState.AfterRecordingStart:
|
|
Status = ScreenRecordingStatus.Recording;
|
|
StartRecordingTimer();
|
|
UpdateUI();
|
|
break;
|
|
case ScreenRecordState.RecordingEnd:
|
|
StopRecordingTimer();
|
|
UpdateUI();
|
|
break;
|
|
case ScreenRecordState.Encoding:
|
|
Hide();
|
|
cmsMain.Enabled = false;
|
|
string trayTextAfterStop = "ShareX - " + Resources.ScreenRecordForm_StartRecording_Encoding___;
|
|
niTray.Text = trayTextAfterStop.Truncate(63);
|
|
niTray.Icon = Resources.camcorder__pencil.ToIcon();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
public void ChangeStateProgress(int progress)
|
|
{
|
|
niTray.Text = $"ShareX - {Resources.ScreenRecordForm_StartRecording_Encoding___} {progress}%";
|
|
|
|
if (niTray.Visible && lastIconStatus != progress)
|
|
{
|
|
Icon icon;
|
|
|
|
if (progress >= 0)
|
|
{
|
|
try
|
|
{
|
|
icon = Helpers.GetProgressIcon(progress, Color.FromArgb(140, 0, 36));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
DebugHelper.WriteException(e);
|
|
progress = -1;
|
|
if (lastIconStatus == progress) return;
|
|
icon = Resources.camcorder__pencil.ToIcon();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
icon = Resources.camcorder__pencil.ToIcon();
|
|
}
|
|
|
|
using (Icon oldIcon = niTray.Icon)
|
|
{
|
|
niTray.Icon = icon;
|
|
oldIcon.DisposeHandle();
|
|
}
|
|
|
|
lastIconStatus = progress;
|
|
}
|
|
}
|
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
{
|
|
using (Pen pen1 = new Pen(ShareXResources.UseCustomTheme ? ShareXResources.Theme.BorderColor : Color.Black) { DashPattern = new float[] { 5, 5 } })
|
|
using (Pen pen2 = new Pen(borderColor) { DashPattern = new float[] { 5, 5 }, DashOffset = 5 })
|
|
{
|
|
e.Graphics.DrawRectangleProper(pen1, borderRectangle0Based);
|
|
e.Graphics.DrawRectangleProper(pen2, borderRectangle0Based);
|
|
}
|
|
|
|
base.OnPaint(e);
|
|
}
|
|
|
|
private void ScreenRegionForm_Shown(object sender, EventArgs e)
|
|
{
|
|
if (ActivateWindow)
|
|
{
|
|
this.ForceActivate();
|
|
}
|
|
}
|
|
|
|
private void ScreenRecordForm_FormClosed(object sender, FormClosedEventArgs e)
|
|
{
|
|
if (Status != ScreenRecordingStatus.Stopped)
|
|
{
|
|
AbortRecording();
|
|
}
|
|
}
|
|
|
|
private void timerRefresh_Tick(object sender, EventArgs e)
|
|
{
|
|
UpdateTimer();
|
|
}
|
|
|
|
private void btnStart_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
StartStopRecording();
|
|
}
|
|
}
|
|
|
|
private void btnPause_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
PauseResumeRecording();
|
|
}
|
|
}
|
|
|
|
private void btnAbort_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
if (!AskConfirmationOnAbort || MessageBox.Show(Resources.ScreenRecordForm_ConfirmCancel, "ShareX", MessageBoxButtons.YesNo,
|
|
MessageBoxIcon.Warning) == DialogResult.Yes)
|
|
{
|
|
AbortRecording();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void lblTimer_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left && (Status == ScreenRecordingStatus.Waiting || Status == ScreenRecordingStatus.Paused))
|
|
{
|
|
dragging = true;
|
|
initialLocation = e.Location;
|
|
}
|
|
}
|
|
|
|
private void lblTimer_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
if (dragging)
|
|
{
|
|
Point newLocation = new Point(Location.X + e.X - initialLocation.X, Location.Y + e.Y - initialLocation.Y);
|
|
Rectangle recordingRegion = GetRecordingRegion(newLocation);
|
|
if (CaptureHelpers.GetScreenBounds().Contains(recordingRegion))
|
|
{
|
|
Location = newLocation;
|
|
Update();
|
|
}
|
|
else
|
|
{
|
|
initialLocation = e.Location;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void lblTimer_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
dragging = false;
|
|
}
|
|
}
|
|
}
|
|
} |