/// <summary> /// This method will create and show the destination picker menu /// </summary> /// <param name="addDynamics">Boolean if the dynamic values also need to be added</param> /// <param name="surface">The surface which can be exported</param> /// <param name="captureDetails">Details for the surface</param> /// <param name="destinations">The list of destinations to show</param> /// <returns></returns> public ExportInformation ShowPickerMenu(bool addDynamics, ISurface surface, ICaptureDetails captureDetails, IEnumerable<IDestination> destinations) { // Generate an empty ExportInformation object, for when nothing was selected. ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker")); ContextMenuStrip menu = new ContextMenuStrip(); menu.ImageScalingSize = configuration.IconSize; menu.Tag = null; menu.Closing += delegate(object source, ToolStripDropDownClosingEventArgs eventArgs) { LOG.DebugFormat("Close reason: {0}", eventArgs.CloseReason); switch (eventArgs.CloseReason) { case ToolStripDropDownCloseReason.AppFocusChange: if (menu.Tag == null) { // Do not allow the close if the tag is not set, this means the user clicked somewhere else. eventArgs.Cancel = true; } else { LOG.DebugFormat("Letting the menu 'close' as the tag is set to '{0}'", menu.Tag); } break; case ToolStripDropDownCloseReason.ItemClicked: case ToolStripDropDownCloseReason.CloseCalled: // The ContextMenuStrip can be "closed" for these reasons. break; case ToolStripDropDownCloseReason.Keyboard: // Dispose as the close is clicked if (!captureDetails.HasDestination("Editor")) { surface.Dispose(); surface = null; } break; default: eventArgs.Cancel = true; break; } }; menu.MouseEnter += delegate(object source, EventArgs eventArgs) { // in case the menu has been unfocused, focus again so that dropdown menus will still open on mouseenter if(!menu.ContainsFocus) menu.Focus(); }; foreach (IDestination destination in destinations) { // Fix foreach loop variable for the delegate ToolStripMenuItem item = destination.GetMenuItem(addDynamics, menu, delegate(object sender, EventArgs e) { ToolStripMenuItem toolStripMenuItem = sender as ToolStripMenuItem; if (toolStripMenuItem == null) { return; } IDestination clickedDestination = (IDestination)toolStripMenuItem.Tag; if (clickedDestination == null) { return; } menu.Tag = clickedDestination.Designation; // Export exportInformation = clickedDestination.ExportCapture(true, surface, captureDetails); if (exportInformation != null && exportInformation.ExportMade) { LOG.InfoFormat("Export to {0} success, closing menu", exportInformation.DestinationDescription); // close menu if the destination wasn't the editor menu.Close(); // Cleanup surface, only if there is no editor in the destinations and we didn't export to the editor if (!captureDetails.HasDestination("Editor") && !"Editor".Equals(clickedDestination.Designation)) { surface.Dispose(); surface = null; } } else { LOG.Info("Export cancelled or failed, showing menu again"); // Make sure a click besides the menu don't close it. menu.Tag = null; // This prevents the problem that the context menu shows in the task-bar ShowMenuAtCursor(menu); } } ); if (item != null) { menu.Items.Add(item); } } // Close menu.Items.Add(new ToolStripSeparator()); ToolStripMenuItem closeItem = new ToolStripMenuItem(Language.GetString("editor_close")); closeItem.Image = GreenshotResources.getImage("Close.Image"); closeItem.Click += delegate { // This menu entry is the close itself, we can dispose the surface menu.Close(); if (!captureDetails.HasDestination("Editor")) { surface.Dispose(); surface = null; } }; menu.Items.Add(closeItem); ShowMenuAtCursor(menu); return exportInformation; }
/// <summary> /// This method will create and show the destination picker menu /// </summary> /// <param name="addDynamics">Boolean if the dynamic values also need to be added</param> /// <param name="surface">The surface which can be exported</param> /// <param name="captureDetails">Details for the surface</param> /// <param name="destinations">The list of destinations to show</param> /// <returns></returns> public ExportInformation ShowPickerMenu(bool addDynamics, ISurface surface, ICaptureDetails captureDetails, IEnumerable <IDestination> destinations) { // Generate an empty ExportInformation object, for when nothing was selected. ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker")); var menu = new ContextMenuStrip { ImageScalingSize = CoreConfig.IconSize, Tag = null, TopLevel = true }; menu.Closing += delegate(object source, ToolStripDropDownClosingEventArgs eventArgs) { Log.DebugFormat("Close reason: {0}", eventArgs.CloseReason); switch (eventArgs.CloseReason) { case ToolStripDropDownCloseReason.AppFocusChange: if (menu.Tag == null) { // Do not allow the close if the tag is not set, this means the user clicked somewhere else. eventArgs.Cancel = true; } else { Log.DebugFormat("Letting the menu 'close' as the tag is set to '{0}'", menu.Tag); } break; case ToolStripDropDownCloseReason.ItemClicked: case ToolStripDropDownCloseReason.CloseCalled: // The ContextMenuStrip can be "closed" for these reasons. break; case ToolStripDropDownCloseReason.Keyboard: // Dispose as the close is clicked if (!captureDetails.HasDestination("Editor")) { surface.Dispose(); surface = null; } break; default: eventArgs.Cancel = true; break; } }; menu.MouseEnter += delegate { // in case the menu has been unfocused, focus again so that dropdown menus will still open on mouseenter if (!menu.ContainsFocus) { menu.Focus(); } }; foreach (IDestination destination in destinations) { // Fix foreach loop variable for the delegate ToolStripMenuItem item = destination.GetMenuItem(addDynamics, menu, delegate(object sender, EventArgs e) { ToolStripMenuItem toolStripMenuItem = sender as ToolStripMenuItem; IDestination clickedDestination = (IDestination)toolStripMenuItem?.Tag; if (clickedDestination == null) { return; } menu.Tag = clickedDestination.Designation; // Export exportInformation = clickedDestination.ExportCapture(true, surface, captureDetails); if (exportInformation != null && exportInformation.ExportMade) { Log.InfoFormat("Export to {0} success, closing menu", exportInformation.DestinationDescription); // close menu if the destination wasn't the editor menu.Close(); // Cleanup surface, only if there is no editor in the destinations and we didn't export to the editor if (!captureDetails.HasDestination("Editor") && !"Editor".Equals(clickedDestination.Designation)) { surface.Dispose(); surface = null; } } else { Log.Info("Export cancelled or failed, showing menu again"); // Make sure a click besides the menu don't close it. menu.Tag = null; // This prevents the problem that the context menu shows in the task-bar ShowMenuAtCursor(menu); } } ); if (item != null) { menu.Items.Add(item); } } // Close menu.Items.Add(new ToolStripSeparator()); ToolStripMenuItem closeItem = new ToolStripMenuItem(Language.GetString("editor_close")) { Image = GreenshotResources.getImage("Close.Image") }; closeItem.Click += delegate { // This menu entry is the close itself, we can dispose the surface menu.Close(); if (!captureDetails.HasDestination("Editor")) { surface.Dispose(); surface = null; } }; menu.Items.Add(closeItem); ShowMenuAtCursor(menu); return(exportInformation); }
private void HandleCapture() { // Flag to see if the image was "exported" so the FileEditor doesn't // ask to save the file as long as nothing is done. bool outputMade = false; // Make sure the user sees that the capture is made if (capture.CaptureDetails.CaptureMode == CaptureMode.File || capture.CaptureDetails.CaptureMode == CaptureMode.Clipboard) { // Maybe not "made" but the original is still there... somehow outputMade = true; } else { DoCaptureFeedback(); } LOG.Debug("A capture of: " + capture.CaptureDetails.Title); // check if someone has passed a destination if (capture.CaptureDetails.CaptureDestinations == null || capture.CaptureDetails.CaptureDestinations.Count == 0) { AddConfiguredDestination(); } // Create Surface with capture, this way elements can be added automatically (like the mouse cursor) Surface surface = new Surface(capture); surface.Modified = !outputMade; // Let the processors do their job foreach (IProcessor processor in ProcessorHelper.GetAllProcessors()) { if (processor.isActive) { LOG.InfoFormat("Calling processor {0}", processor.Description); processor.ProcessCapture(surface, capture.CaptureDetails); } } // As the surfaces copies the reference to the image, make sure the image is not being disposed (a trick to save memory) capture.Image = null; // Get CaptureDetails as we need it even after the capture is disposed ICaptureDetails captureDetails = capture.CaptureDetails; bool canDisposeSurface = true; if (captureDetails.HasDestination(Destinations.PickerDestination.DESIGNATION)) { DestinationHelper.ExportCapture(false, Destinations.PickerDestination.DESIGNATION, surface, captureDetails); captureDetails.CaptureDestinations.Clear(); canDisposeSurface = false; } // Disable capturing captureMode = CaptureMode.None; // Dispose the capture, we don't need it anymore (the surface copied all information and we got the title (if any)). capture.Dispose(); capture = null; int destinationCount = captureDetails.CaptureDestinations.Count; if (destinationCount > 0) { // Flag to detect if we need to create a temp file for the email // or use the file that was written foreach (IDestination destination in captureDetails.CaptureDestinations) { if (PickerDestination.DESIGNATION.Equals(destination.Designation)) { continue; } LOG.InfoFormat("Calling destination {0}", destination.Description); bool destinationOk = destination.ExportCapture(false, surface, captureDetails); if (Destinations.EditorDestination.DESIGNATION.Equals(destination.Designation) && destinationOk) { canDisposeSurface = false; } } } if (canDisposeSurface) { surface.Dispose(); } }
/// <summary> /// This method will create and show the destination picker menu /// </summary> /// <param name="addDynamics">Boolean if the dynamic values also need to be added</param> /// <param name="surface">The surface which can be exported</param> /// <param name="captureDetails">Details for the surface</param> /// <param name="destinations">The list of destinations to show</param> /// <returns></returns> protected ExportInformation ShowPickerMenu(bool addDynamics, ISurface surface, ICaptureDetails captureDetails, IEnumerable <IDestination> destinations) { var menu = new ContextMenuStrip { Tag = null, TopLevel = true }; var dpiHandler = menu.AttachDpiHandler(); var bitmapScaleHandler = BitmapScaleHandler.Create <IDestination>( dpiHandler, (destination, dpi) => destination.GetDisplayIcon(dpi), (bitmap, d) => bitmap.ScaleIconForDisplaying(d)); dpiHandler.OnDpiChanged.Subscribe(dpi => { var width = DpiHandler.ScaleWithDpi(CoreConfiguration.IconSize.Width, dpi); var size = new Size(width, width); menu.ImageScalingSize = size; }); // Generate an empty ExportInformation object, for when nothing was selected. var exportInformation = new ExportInformation("", GreenshotLanguage.SettingsDestinationPicker); menu.Closing += (source, eventArgs) => { Log.Debug().WriteLine("Close reason: {0}", eventArgs.CloseReason); switch (eventArgs.CloseReason) { case ToolStripDropDownCloseReason.AppFocusChange: if (menu.Tag == null) { // Do not allow the close if the tag is not set, this means the user clicked somewhere else. eventArgs.Cancel = true; } else { Log.Debug().WriteLine("Letting the menu 'close' as the tag is set to '{0}'", menu.Tag); } break; case ToolStripDropDownCloseReason.ItemClicked: case ToolStripDropDownCloseReason.CloseCalled: // The ContextMenuStrip can be "closed" for these reasons. break; case ToolStripDropDownCloseReason.Keyboard: // Dispose as the close is clicked if (!captureDetails.HasDestination("Editor")) { surface.Dispose(); surface = null; } break; default: eventArgs.Cancel = true; break; } }; menu.MouseEnter += (sender, args) => { // in case the menu has been unfocused, focus again so that dropdown menus will still open on mouseenter if (!menu.ContainsFocus) { menu.Focus(); } }; foreach (var destination in destinations) { // Fix foreach loop variable for the delegate var item = destination.GetMenuItem(addDynamics, menu, async(sender, e) => { var toolStripMenuItem = sender as ToolStripMenuItem; var clickedDestination = (IDestination)toolStripMenuItem?.Tag; if (clickedDestination == null) { return; } menu.Tag = clickedDestination.Designation; // Export exportInformation = await clickedDestination.ExportCaptureAsync(true, surface, captureDetails); if (exportInformation != null && exportInformation.ExportMade) { Log.Info().WriteLine("Export to {0} success, closing menu", exportInformation.DestinationDescription); // close menu menu.Close(); menu.Dispose(); // Cleanup surface, only if there is no editor in the destinations and we didn't export to the editor if (!captureDetails.HasDestination("Editor") && !"Editor".Equals(clickedDestination.Designation)) { surface.Dispose(); surface = null; } } else { Log.Info().WriteLine("Export cancelled or failed, showing menu again"); // Make sure a click besides the menu don't close it. menu.Tag = null; // This prevents the problem that the context menu shows in the task-bar ShowMenuAtCursor(menu); } }, bitmapScaleHandler ); if (item != null) { menu.Items.Add(item); } } // Close menu.Items.Add(new ToolStripSeparator()); var closeItem = new ToolStripMenuItem(GreenshotLanguage.Close) { Image = GreenshotResources.GetBitmap("Close.Image") }; closeItem.Click += (sender, args) => { // This menu entry is the close itself, we can dispose the surface menu.Close(); menu.Dispose(); // Only dispose if there is a destination which keeps the capture if (captureDetails.HasDestination("Editor")) { return; } surface.Dispose(); surface = null; }; menu.Items.Add(closeItem); ShowMenuAtCursor(menu); return(exportInformation); }
private void HandleCapture() { // Flag to see if the image was "exported" so the FileEditor doesn't // ask to save the file as long as nothing is done. bool outputMade = false; // Make sure the user sees that the capture is made if (_capture.CaptureDetails.CaptureMode == CaptureMode.File || _capture.CaptureDetails.CaptureMode == CaptureMode.Clipboard) { // Maybe not "made" but the original is still there... somehow outputMade = true; } else { // Make sure the resolution is set correctly! if (_capture.CaptureDetails != null) { ((Bitmap)_capture.Image)?.SetResolution(_capture.CaptureDetails.DpiX, _capture.CaptureDetails.DpiY); } DoCaptureFeedback(); } Log.Debug("A capture of: " + _capture.CaptureDetails.Title); // check if someone has passed a destination if (_capture.CaptureDetails.CaptureDestinations == null || _capture.CaptureDetails.CaptureDestinations.Count == 0) { AddConfiguredDestination(); } // Create Surface with capture, this way elements can be added automatically (like the mouse cursor) Surface surface = new Surface(_capture) { Modified = !outputMade }; // Register notify events if this is wanted if (CoreConfig.ShowTrayNotification && !CoreConfig.HideTrayicon) { surface.SurfaceMessage += SurfaceMessageReceived; } // Let the processors do their job foreach (IProcessor processor in ProcessorHelper.GetAllProcessors()) { if (processor.isActive) { Log.InfoFormat("Calling processor {0}", processor.Description); processor.ProcessCapture(surface, _capture.CaptureDetails); } } // As the surfaces copies the reference to the image, make sure the image is not being disposed (a trick to save memory) _capture.Image = null; // Get CaptureDetails as we need it even after the capture is disposed ICaptureDetails captureDetails = _capture.CaptureDetails; bool canDisposeSurface = true; if (captureDetails.HasDestination(PickerDestination.DESIGNATION)) { DestinationHelper.ExportCapture(false, PickerDestination.DESIGNATION, surface, captureDetails); captureDetails.CaptureDestinations.Clear(); canDisposeSurface = false; } // Disable capturing _captureMode = CaptureMode.None; // Dispose the capture, we don't need it anymore (the surface copied all information and we got the title (if any)). _capture.Dispose(); _capture = null; int destinationCount = captureDetails.CaptureDestinations.Count; if (destinationCount > 0) { // Flag to detect if we need to create a temp file for the email // or use the file that was written foreach (IDestination destination in captureDetails.CaptureDestinations) { if (PickerDestination.DESIGNATION.Equals(destination.Designation)) { continue; } Log.InfoFormat("Calling destination {0}", destination.Description); ExportInformation exportInformation = destination.ExportCapture(false, surface, captureDetails); if (EditorDestination.DESIGNATION.Equals(destination.Designation) && exportInformation.ExportMade) { canDisposeSurface = false; } } } if (canDisposeSurface) { surface.Dispose(); } }