Example #1
0
        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;
            }
        }
Example #2
0
        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));
        }