internal static string ExpandParameters(string p, ExtendedScreenshot ss) { if (string.IsNullOrEmpty(p)) { return(string.Empty); } return(Regex.Replace(p, @":[a-z]+", new MatchEvaluator(m => { try { switch (m.Value) { case ":w": return ss.WindowTitle; case ":url": return ss.Remote.ImageLink; case ":delete": return ss.Remote.DeleteLink; case ":file": return string.IsNullOrEmpty(ss.SavedFileName) ? ss.InternalFileName : ss.SavedFileName; case ":image": return ""; default: return ss.Date.ToString(m.Value.TrimStart(':')); } } catch (FormatException fe) { return m.Value; } }), RegexOptions.IgnoreCase)); }
internal static string ExpandParameters(string p, ExtendedScreenshot ss) { if (string.IsNullOrEmpty(p)) return string.Empty; return Regex.Replace(p, @":[a-z]+", new MatchEvaluator(m => { try { switch (m.Value) { case ":w": return ss.WindowTitle; case ":url": return ss.Remote.ImageLink; case ":delete": return ss.Remote.DeleteLink; case ":file": return string.IsNullOrEmpty(ss.SavedFileName) ? ss.InternalFileName : ss.SavedFileName; case ":image": return ""; default: return ss.Date.ToString(m.Value.TrimStart(':')); } } catch (FormatException fe) { return m.Value; } }), RegexOptions.IgnoreCase); }
private static void DoActionItem(ShortcutItem ActiveShortcutItem, int itemIndex, ExtendedScreenshot ActionItemScreenshot) { if (ActiveShortcutItem == null || itemIndex >= ActiveShortcutItem.ActionChain.ActionItems.Count) { Trace.WriteLine("No more action items to execute", string.Format("Program.DoActionItem [{0}]", System.Threading.Thread.CurrentThread.Name)); //todo: Why can't the hook be reinstated on the action thread? Preview.BeginInvoke(new MethodInvoker(() => KeyboardHook.isPaused = false)); IconAnimation.CancelAsync(); return; } IActionItem CurrentActionItem = ActiveShortcutItem.ActionChain.ActionItems[itemIndex]; //don't try and invoke the scrolling screenshot actions if they're the first type in the action chain (eg, solo items for their shortcuts) and there's no active scrolling screenshot happening //at least this solves flashing the icon whenever 'End' key is pressed during normal computer use if (!Program.isTakingScrollingScreenshot && (CurrentActionItem.ActionType == ActionTypes.ContinueScrollingScreenshot || CurrentActionItem.ActionType == ActionTypes.EndScrollingScreenshot) && itemIndex == 0) return; KeyboardHook.isPaused = true; Trace.WriteLine(CurrentActionItem.ActionType, string.Format("Program.DoActionItem [{0}]", System.Threading.Thread.CurrentThread.Name)); //todo: figure out a better way to do these exclusions rather than harcoding behavior for scrolling screenshots if (!IconAnimation.IsBusy) if ((new[] { ActionTypes.ContinueScrollingScreenshot, ActionTypes.EndScrollingScreenshot }.Contains(CurrentActionItem.ActionType) && isTakingScrollingScreenshot) || !new[] { ActionTypes.ContinueScrollingScreenshot, ActionTypes.EndScrollingScreenshot }.Contains(CurrentActionItem.ActionType)) IconAnimation.RunWorkerAsync(); Task.Factory.StartNew<ExtendedScreenshot>(() => CurrentActionItem.Invoke(ActionItemScreenshot)) .ContinueWith(t => DoActionItem(ActiveShortcutItem, itemIndex + 1, t.Result)); }
public UploadedFileDetails(ExtendedScreenshot metadata) { InitializeComponent(); this.BackColor = Color.Black; this.Paint += new PaintEventHandler(UploadedFileDetails_Paint); this.Load += new EventHandler(UploadedFileDetails_Load); this.Metadata = metadata; //Much more reliable than MouseLeave for the form MousePositionCheck.Tick += (s, e) => { Rectangle b = this.Bounds; b.Inflate(10, 10); if (!b.Contains(MousePosition)) { MousePositionCheck.Enabled = false; FadeClose(1500); } //else // Opacity = MaxOpacity; }; MousePositionCheck.Interval = 100; MousePositionCheck.Enabled = true; }
private void LoadScreenshot(ExtendedScreenshot targetWindow) { Trace.WriteLine("Loading image...", string.Format("PeekPreview.LoadScreenshot [{0}]", System.Threading.Thread.CurrentThread.Name)); pbPreview.Image = null; tsmiRoundCorners.Checked = targetWindow.withBorderRounding; tsmiWindowShadow.Checked = targetWindow.withBorderShadow; tsmiMouseCursor.Checked = targetWindow.withCursor; CurrentScreenshot = targetWindow; ReloadPreviewImage(); ResetFadeCloseCountdown(); GroomBackForwardIcons(); GroomHeartIcon(); pnUpload.BackgroundImage = CurrentScreenshot == null || string.IsNullOrEmpty(CurrentScreenshot.Remote.ImageLink) ? Resources.cloud_upload_32x32_black : Resources.cloud_upload_link_black_32x32; if (Configuration.PreviewDelayTime > 0) { FadeCloseCountdown.Interval = Configuration.PreviewDelayTime * 1000; } Opacity = 1; Trace.WriteLine("Done.", string.Format("PeekPreview.LoadScreenshot [{0}]", System.Threading.Thread.CurrentThread.Name)); }
public UploadedFileDetails(ExtendedScreenshot metadata) { InitializeComponent(); this.BackColor = Color.Black; this.Paint += new PaintEventHandler(UploadedFileDetails_Paint); this.Load += new EventHandler(UploadedFileDetails_Load); this.Metadata = metadata; //Much more reliable than MouseLeave for the form MousePositionCheck.Tick += (s, e) => { Rectangle b = this.Bounds; b.Inflate(10,10); if (!b.Contains(MousePosition)) { MousePositionCheck.Enabled = false; FadeClose(1500); } //else // Opacity = MaxOpacity; }; MousePositionCheck.Interval = 100; MousePositionCheck.Enabled = true; }
public void Show(ExtendedScreenshot targetWindow = null) { Trace.WriteLine("Showing preview...", string.Format("PeekPreview.Show [{0}]", System.Threading.Thread.CurrentThread.Name)); if (this.InvokeRequired) { Trace.WriteLine("Self invoking...", string.Format("PeekPreview.Show [{0}]", System.Threading.Thread.CurrentThread.Name)); this.BeginInvoke(new MethodInvoker(() => this.Show(targetWindow))); return; } targetWindow = targetWindow ?? this.CurrentScreenshot ?? Program.History.LastOrDefault(); if (targetWindow == null) { Trace.WriteLine("No screenshot to show", string.Format("PeekPreview.Show [{0}]", System.Threading.Thread.CurrentThread.Name)); return; } this.LoadScreenshot(targetWindow); base.Show(); }
internal static string ExpandParameters(string p, ExtendedScreenshot ss) { if (string.IsNullOrEmpty(p)) return string.Empty; p = p.Replace(":yyyy", ss.Date.ToString("yyyy")); p = p.Replace(":yy", ss.Date.ToString("yy")); p = p.Replace(":MMMM", ss.Date.ToString("MMMM")); p = p.Replace(":MMM", ss.Date.ToString("MMM")); p = p.Replace(":MM", ss.Date.ToString("MM")); p = p.Replace(":M", ss.Date.ToString("M")); p = p.Replace(":dddd", ss.Date.ToString("dddd")); p = p.Replace(":ddd", ss.Date.ToString("ddd")); p = p.Replace(":dd", ss.Date.ToString("dd")); p = p.Replace(":d", ss.Date.ToString("d")); p = p.Replace(":hh", ss.Date.ToString("hh")); p = p.Replace(":HH", ss.Date.ToString("HH")); p = p.Replace(":mm", ss.Date.ToString("mm")); p = p.Replace(":m", ss.Date.ToString("m")); p = p.Replace(":ss", ss.Date.ToString("ss")); p = p.Replace(":s", ss.Date.ToString("s")); p = p.Replace(":tt", ss.Date.ToString("tt")); p = p.Replace(":t", ss.Date.ToString("t")); p = p.Replace(":zzz", ss.Date.ToString("zzz")); p = p.Replace(":zz", ss.Date.ToString("zz")); p = p.Replace(":w", ss.WindowTitle); return p; }
private void LoadScreenshot(ExtendedScreenshot targetWindow) { Trace.WriteLine("Loading image...", string.Format("PeekPreview.LoadScreenshot [{0}]", System.Threading.Thread.CurrentThread.Name)); pbPreview.Image = null; tsmiRoundCorners.Checked = targetWindow.withBorderRounding; tsmiWindowShadow.Checked = targetWindow.withBorderShadow; tsmiMouseCursor.Checked = targetWindow.withCursor; CurrentScreenshot = targetWindow; ReloadPreviewImage(); ResetFadeCloseCountdown(); GroomBackForwardIcons(); GroomHeartIcon(); pnUpload.BackgroundImage = CurrentScreenshot == null || string.IsNullOrEmpty(CurrentScreenshot.Remote.ImageLink) ? Resources.cloud_upload_32x32_black : Resources.cloud_upload_link_black_32x32; if (Configuration.PreviewDelayTime > 0) FadeCloseCountdown.Interval = Configuration.PreviewDelayTime * 1000; Opacity = 1; Trace.WriteLine("Done.", string.Format("PeekPreview.LoadScreenshot [{0}]", System.Threading.Thread.CurrentThread.Name)); }
private static void DoActionItem(ShortcutItem ActiveShortcutItem, int itemIndex, ExtendedScreenshot ActionItemScreenshot) { if (ActiveShortcutItem == null || itemIndex >= ActiveShortcutItem.ActionChain.ActionItems.Count) { Trace.WriteLine("No more action items to execute", string.Format("Program.DoActionItem [{0}]", System.Threading.Thread.CurrentThread.Name)); //todo: Why can't the hook be reinstated on the action thread? Preview.BeginInvoke(new MethodInvoker(() => KeyboardHook.isPaused = false)); IconAnimation.CancelAsync(); return; } IActionItem CurrentActionItem = ActiveShortcutItem.ActionChain.ActionItems[itemIndex]; //don't try and invoke the scrolling screenshot actions if they're the first type in the action chain (eg, solo items for their shortcuts) and there's no active scrolling screenshot happening //at least this solves flashing the icon whenever 'End' key is pressed during normal computer use if (!Program.isTakingScrollingScreenshot && (CurrentActionItem.ActionType == ActionTypes.ContinueScrollingScreenshot || CurrentActionItem.ActionType == ActionTypes.EndScrollingScreenshot) && itemIndex == 0) { return; } KeyboardHook.isPaused = true; Trace.WriteLine(CurrentActionItem.ActionType, string.Format("Program.DoActionItem [{0}]", System.Threading.Thread.CurrentThread.Name)); //todo: figure out a better way to do these exclusions rather than harcoding behavior for scrolling screenshots if (!IconAnimation.IsBusy) { if ((new[] { ActionTypes.ContinueScrollingScreenshot, ActionTypes.EndScrollingScreenshot }.Contains(CurrentActionItem.ActionType) && isTakingScrollingScreenshot) || !new[] { ActionTypes.ContinueScrollingScreenshot, ActionTypes.EndScrollingScreenshot }.Contains(CurrentActionItem.ActionType)) { IconAnimation.RunWorkerAsync(); } } Task.Factory.StartNew <ExtendedScreenshot>(() => CurrentActionItem.Invoke(ActionItemScreenshot)) .ContinueWith(t => DoActionItem(ActiveShortcutItem, itemIndex + 1, t.Result)); }
private static void DoActionItem(ShortcutItem ActiveShortcutItem, int itemIndex) { if (ActiveShortcutItem == null || itemIndex >= ActiveShortcutItem.ActionChain.ActionItems.Count) { Trace.WriteLine("No more action items to execute", string.Format("Program.DoActionItem [{0}]", Thread.CurrentThread.Name)); //todo: Why can't the hook be reinstated on the action thread? Preview.BeginInvoke(new MethodInvoker(() => KeyboardHook.isPaused = false)); IconAnimation.CancelAsync(); return; } KeyboardHook.isPaused = true; IActionItem CurrentActionItem = ActiveShortcutItem.ActionChain.ActionItems[itemIndex]; Trace.WriteLine(CurrentActionItem.ActionType, string.Format("Program.DoActionItem [{0}]", Thread.CurrentThread.Name)); //todo: figure out a better way to do these exclusions rather than harcoding behavior for scrolling screenshots if (!IconAnimation.IsBusy) if ((new[] { ActionTypes.ContinueScrollingScreenshot, ActionTypes.EndScrollingScreenshot }.Contains(CurrentActionItem.ActionType) && isTakingScrollingScreenshot) || !new[] { ActionTypes.ContinueScrollingScreenshot, ActionTypes.EndScrollingScreenshot }.Contains(CurrentActionItem.ActionType)) IconAnimation.RunWorkerAsync(); switch (CurrentActionItem.ActionType) { case ActionTypes.TakeForegroundScreenshot: { var CurrentActionConfig = CurrentActionItem as TakeForegroundScreenshotAction; try { var ForegroundWindowScreenshot = new ExtendedScreenshot(CurrentActionConfig.Method, CurrentActionConfig.SolidGlass); History.Add(ForegroundWindowScreenshot); } catch (Exception e) { Trace.WriteLine(string.Format("Exception in TakeForegroundScreenshot: {0}", e.GetBaseException()), string.Format("Program.DoActionItem [{0}]", Thread.CurrentThread.Name)); ReportListener reporter = Trace.Listeners.Cast<TraceListener>().Where(tl => tl is ReportListener).FirstOrDefault() as ReportListener; File.WriteAllText(Path.Combine(Configuration.LocalPath, "report.txt"), string.Join("\n", reporter.Messages.Select(m => string.Format("{0} {1}: {2}", m.Timestamp, m.Category, m.Message)).ToArray())); } DoActionItem(ActiveShortcutItem, itemIndex + 1); } break; case ActionTypes.TakeRegionScreenshot: { var CurrentActionConfig = CurrentActionItem as TakeRegionScreenshotAction; Rectangle SelectedRegion = CurrentActionConfig.Region; try { if (CurrentActionConfig.UseRegionSelector) { lock (_actionlock) { var e = new PreviewEventArgs() { ActionItem = CurrentActionItem }; ShowPreviewEvent(null, e); Monitor.Wait(_actionlock); SelectedRegion = (Rectangle)e.Result; } } if (!SelectedRegion.IsEmpty) { var RegionScreenshot = new ExtendedScreenshot(SelectedRegion); History.Add(RegionScreenshot); DoActionItem(ActiveShortcutItem, itemIndex + 1); } else { DoActionItem(null, itemIndex + 1); } } catch (Exception e) { Trace.WriteLine(string.Format("Exception in TakeRegionScreenshot: {0}", e.GetBaseException()), string.Format("Program.DoActionItem [{0}]", Thread.CurrentThread.Name)); ReportListener reporter = Trace.Listeners.Cast<TraceListener>().Where(tl => tl is ReportListener).FirstOrDefault() as ReportListener; File.WriteAllText(Path.Combine(Configuration.LocalPath, "report.txt"), string.Join("\n", reporter.Messages.Select(m => string.Format("{0} {1}: {2}", m.Timestamp, m.Category, m.Message)).ToArray())); DoActionItem(null, itemIndex + 1); } } break; case ActionTypes.ShowPreview: { if (Configuration.PreviewDelayTime != 0 && History.Count > 0) ShowPreviewEvent(History.Last(), new PreviewEventArgs()); DoActionItem(ActiveShortcutItem, itemIndex + 1); } break; case ActionTypes.Heart: { var LatestScreenshot = History.LastOrDefault(); if (LatestScreenshot != null) { lock (_actionlock) { ShowPreviewEvent(LatestScreenshot, new PreviewEventArgs() { ActionItem = CurrentActionItem }); Monitor.Wait(_actionlock); DoActionItem(ActiveShortcutItem, itemIndex + 1); } } } break; case ActionTypes.Save: { var LatestScreenshot = History.LastOrDefault(); if (LatestScreenshot != null) { var Save = CurrentActionItem as SaveAction; Trace.WriteLine(string.Format("Prompting for save: {0}", Save.Prompt), string.Format("Program.DoActionItem Save [{0}]", Thread.CurrentThread.Name)); if (Save.Prompt) { lock (_actionlock) { ShowPreviewEvent(LatestScreenshot, new PreviewEventArgs() { ActionItem = CurrentActionItem }); Monitor.Wait(_actionlock); DoActionItem(ActiveShortcutItem, itemIndex + 1); } } else { string FileName = Environment.ExpandEnvironmentVariables(Helper.ExpandParameters(Save.FilePath, LatestScreenshot)); if (!string.IsNullOrEmpty(FileName)) { try { var dir = Path.GetDirectoryName(FileName); if (!Directory.Exists(dir)) { Trace.WriteLine("Attempting to create directory...", string.Format("Program.DoActionItem Save [{0}]", Thread.CurrentThread.Name)); Directory.CreateDirectory(dir); } LatestScreenshot.ComposedScreenshotImage.Save(FileName, Helper.ExtToImageFormat(Path.GetExtension(FileName))); LatestScreenshot.SavedFileName = FileName; } catch (Exception e) { MessageBox.Show(string.Format("There was a problem saving your screenshot:\r\n\r\n{0}", e.GetBaseException().Message), "ProSnap", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } } else { MessageBox.Show(string.Format("There was a problem saving your screenshot:\r\n\r\n{0}", "No file name has been provided."), "ProSnap", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } DoActionItem(ActiveShortcutItem, itemIndex + 1); } } } break; case ActionTypes.Upload: { var LatestScreenshot = History.LastOrDefault(); if (LatestScreenshot != null) { lock (_actionlock) { ShowPreviewEvent(LatestScreenshot, new PreviewEventArgs() { ActionItem = CurrentActionItem }); Monitor.Wait(_actionlock); DoActionItem(ActiveShortcutItem, itemIndex + 1); } } } break; case ActionTypes.ApplyEdits: { var LatestScreenshot = History.LastOrDefault(); if (LatestScreenshot != null) { var CurrentActionConfig = CurrentActionItem as ApplyEditsAction; switch (CurrentActionConfig.DefaultBorderRounding) { case ApplyEditsAction.ApplicationMode.Automatic: LatestScreenshot.withBorderRounding = !LatestScreenshot.isMaximized && LatestScreenshot.isRounded && !(FMUtils.WinApi.Helper.OperatingSystem == FMUtils.WinApi.Helper.OperatingSystems.Win8); break; case ApplyEditsAction.ApplicationMode.On: LatestScreenshot.withBorderRounding = true; break; case ApplyEditsAction.ApplicationMode.Off: LatestScreenshot.withBorderRounding = false; break; } switch (CurrentActionConfig.DefaultBorderShadow) { case ApplyEditsAction.ApplicationMode.Automatic: LatestScreenshot.withBorderShadow = !LatestScreenshot.isMaximized; break; case ApplyEditsAction.ApplicationMode.On: LatestScreenshot.withBorderShadow = true; break; case ApplyEditsAction.ApplicationMode.Off: LatestScreenshot.withBorderShadow = false; break; } switch (CurrentActionConfig.ShowMouseCursor) { case ApplyEditsAction.ApplicationMode.Automatic: LatestScreenshot.withCursor = LatestScreenshot.CompositionRect.Contains(LatestScreenshot.CursorLocation); break; case ApplyEditsAction.ApplicationMode.On: LatestScreenshot.withCursor = true; break; case ApplyEditsAction.ApplicationMode.Off: LatestScreenshot.withCursor = false; break; } } DoActionItem(ActiveShortcutItem, itemIndex + 1); } break; case ActionTypes.Run: { var LatestScreenshot = History.LastOrDefault(); if (LatestScreenshot != null) { var Run = CurrentActionItem as RunAction; if (!File.Exists(LatestScreenshot.InternalFileName)) { Directory.CreateDirectory(Path.GetDirectoryName(LatestScreenshot.InternalFileName)); LatestScreenshot.ComposedScreenshotImage.Save(LatestScreenshot.InternalFileName, ImageFormat.Png); } var parameters = Helper.ExpandParameters(Run.Parameters, LatestScreenshot).Replace(":file", LatestScreenshot.InternalFileName); var working = Environment.ExpandEnvironmentVariables(Helper.ExpandParameters(Run.WorkingDirectory, LatestScreenshot)); switch (Run.Mode) { case RunAction.Modes.ShellVerb: { Windowing.ShellExecute(IntPtr.Zero, Run.ShellVerb, LatestScreenshot.InternalFileName, parameters, working, Windowing.ShowCommands.SW_NORMAL); } break; case RunAction.Modes.FilePath: { var psi = new ProcessStartInfo(Environment.ExpandEnvironmentVariables(Helper.ExpandParameters(Run.ApplicationPath, LatestScreenshot)), parameters) { UseShellExecute = false }; if (!string.IsNullOrEmpty(working)) psi.WorkingDirectory = working; Process.Start(psi); } break; } } DoActionItem(ActiveShortcutItem, itemIndex + 1); } break; case ActionTypes.Delete: { var LatestScreenshot = History.LastOrDefault(); if (LatestScreenshot != null) { lock (_actionlock) { ShowPreviewEvent(LatestScreenshot, new PreviewEventArgs() { ActionItem = CurrentActionItem }); Monitor.Wait(_actionlock); DoActionItem(ActiveShortcutItem, itemIndex + 1); } } } break; case ActionTypes.HidePreview: { lock (_actionlock) { ShowPreviewEvent(null, new PreviewEventArgs() { ActionItem = CurrentActionItem }); Monitor.Wait(_actionlock); DoActionItem(ActiveShortcutItem, itemIndex + 1); } } break; case ActionTypes.BeginScrollingScreenshot: { isTakingScrollingScreenshot = true; timelapse.Clear(); timelapse.Add(new ExtendedScreenshot()); DoActionItem(ActiveShortcutItem, itemIndex + 1); } break; case ActionTypes.ContinueScrollingScreenshot: { if (isTakingScrollingScreenshot) timelapse.Add(new ExtendedScreenshot()); DoActionItem(ActiveShortcutItem, itemIndex + 1); } break; case ActionTypes.EndScrollingScreenshot: { if (isTakingScrollingScreenshot) { isTakingScrollingScreenshot = false; Bitmap final = null; Bitmap b = new Bitmap(timelapse.First().BaseScreenshotImage.Width, timelapse.First().BaseScreenshotImage.Height * timelapse.Count); Graphics g = Graphics.FromImage(b); int yoffset = 0; int working_height = 0; int ignore_header = 100; int ignore_footer = 10; var offsets = new Dictionary<int, int>(); //foreach (var ss in timelapse) for (int c = 0; c < timelapse.Count; c++) { var debug = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), @"prosnap-debug"); if (Directory.Exists(debug)) { timelapse[c].BaseScreenshotImage.Save(Path.Combine(debug, @"ss-" + c + ".png"), ImageFormat.Png); } if (c == 0) { g.DrawImageUnscaled(timelapse[c].BaseScreenshotImage, new Point(0, 0)); working_height = timelapse[c].BaseScreenshotImage.Height; offsets.Add(c, timelapse[c].BaseScreenshotImage.Height); } else { int old_yoffset = yoffset; yoffset = GetYOffset(timelapse[c - 1].BaseScreenshotImage, timelapse[c].BaseScreenshotImage, ignore_header, ignore_footer, old_yoffset, working_height, c); offsets.Add(c, yoffset); int sum = 0; if (offsets.Count > 0) for (int k = offsets.First().Key; k <= offsets.Last().Key; k++) sum += offsets[k]; working_height = sum; g.DrawImage(timelapse[c].BaseScreenshotImage, new RectangleF(0, working_height - (timelapse[c].BaseScreenshotImage.Height - ignore_header), timelapse[c].BaseScreenshotImage.Width, timelapse[c].BaseScreenshotImage.Height - ignore_header), new RectangleF(0, ignore_header, timelapse[c].BaseScreenshotImage.Width, timelapse[c].BaseScreenshotImage.Height - ignore_header), GraphicsUnit.Pixel); } g.Flush(); g.Save(); final = new Bitmap(b.Width, working_height); Graphics gfinal = Graphics.FromImage(final); gfinal.DrawImage(b, new Rectangle(0, 0, final.Width, final.Height), new Rectangle(0, 0, b.Width, working_height), GraphicsUnit.Pixel); gfinal.Flush(); gfinal.Save(); if (Directory.Exists(debug)) { final.Save(Path.Combine(debug, @"final-" + c + ".png"), System.Drawing.Imaging.ImageFormat.Png); } } timelapse.First().ReplaceWithBitmap(final); History.Add(timelapse.First()); DoActionItem(ActiveShortcutItem, itemIndex + 1); } else { //Must call, so that the action chain is properly ended DoActionItem(null, 0); } } break; } }
private static void Program_ShowPreviewEvent(ExtendedScreenshot s, PreviewEventArgs e) { if (Preview.InvokeRequired) { Trace.WriteLine("Self invoking...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); Preview.BeginInvoke(new MethodInvoker(() => Program_ShowPreviewEvent(s, e))); return; } //It is much easier to simply invoke onto the preview thread for actions which have UI ramification, rather than managing cross thread status updates //Currently there are only a couple actions this really makes sense for: Heart, Save, Upload, Delete (because it potentially also hides the form) //Save doesn't really have a UI change, but doing it on the UI thread means the SFD is positioned correctly //The locking scheme is so that dispatched operations block the action thread until complete //So for example, an action chain with Upload followed by Run can use the uploaded image url as a parameter for itself if (s != null) { Trace.WriteLine("Loading preview screenshot...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); Preview.LoadScreenshot(s); } if (e.ActionItem == null) { Trace.WriteLine("Showing preview...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); Preview.Show(); } if (e.ActionItem is HeartAction) { Trace.WriteLine("Applying HeartAction...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); lock (_actionlock) { switch ((e.ActionItem as HeartAction).HeartMode) { case HeartAction.Modes.Toggle: s.isFlagged = !s.isFlagged; break; case HeartAction.Modes.On: s.isFlagged = true; break; case HeartAction.Modes.Off: s.isFlagged = false; break; } Preview.UpdateHeart(); Monitor.Pulse(_actionlock); } } if (e.ActionItem is SaveAction) { Trace.WriteLine("Applying SaveAction...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); Preview.SaveComplete += (ss, se) => { lock (_actionlock) Monitor.Pulse(_actionlock); }; lock (_actionlock) Preview.Save(); } if (e.ActionItem is UploadAction) { Trace.WriteLine("Applying UploadAction...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); Preview.UploadComplete += (us, ue) => { lock (_actionlock) Monitor.Pulse(_actionlock); }; lock (_actionlock) Preview.Upload(); } if (e.ActionItem is DeleteAction) { Trace.WriteLine("Applying DeleteAction...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); lock (_actionlock) { Preview.Delete(); Monitor.Pulse(_actionlock); } } if (e.ActionItem is HidePreviewAction) { Trace.WriteLine("Applying HidePreviewAction...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); lock (_actionlock) { Preview.FadeClose(); Monitor.Pulse(_actionlock); } } if (e.ActionItem is TakeRegionScreenshotAction) { Trace.WriteLine("Opening region selector...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); var rs = new RegionSelector(); rs.FormClosed += (ss, se) => { Trace.WriteLine("Closed region selector.", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); lock (_actionlock) { e.Result = rs.DialogResult == DialogResult.OK ? rs.SnapshotRectangle : Rectangle.Empty; Monitor.Pulse(_actionlock); } }; lock (_actionlock) rs.Show(); } Trace.WriteLine("Done.", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); }