From 46e9ea0e5970badf2a8470823994b1d9d356d1a3 Mon Sep 17 00:00:00 2001 From: RKrom Date: Sun, 25 Nov 2012 08:48:10 +0000 Subject: [PATCH] Mainly code cleanup, added a lot of comments. Also making sure the element which was selected while being removed is re-selected again when undo is used. Not really happy with the solution as the the container should handle this somehow itself without work-around, for now it should be enough. git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@2311 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4 --- Greenshot/Drawing/Surface.cs | 267 +++++++++++++++--- Greenshot/Forms/ImageEditorForm.cs | 14 +- Greenshot/Memento/AddElementMemento.cs | 5 +- Greenshot/Memento/ChangeFieldHolderMemento.cs | 2 +- Greenshot/Memento/DeleteElementMemento.cs | 6 +- .../DrawableContainerBoundsChangeMemento.cs | 2 +- Greenshot/Memento/IMemento.cs | 2 +- .../Memento/SurfaceBackgroundChangeMemento.cs | 2 +- Greenshot/Memento/TextChangeMemento.cs | 2 +- GreenshotPlugin/Interfaces/Generic.cs | 4 +- 10 files changed, 246 insertions(+), 60 deletions(-) diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index c9944ef84..5c0ecdac8 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -181,7 +181,7 @@ namespace Greenshot.Drawing { /// the brush which is used for transparent backgrounds, set by the editor, do not serialize /// [NonSerialized] - private TextureBrush transparencyBackgroundBrush; + private Brush transparencyBackgroundBrush; /// /// The buffer is only for drawing on it when using filters (to supply access) @@ -225,7 +225,6 @@ namespace Greenshot.Drawing { /// The image is the actual captured image, needed with serialization /// private Image image = null; - public Image Image { get { return image; @@ -235,6 +234,10 @@ namespace Greenshot.Drawing { } } + /// + /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements. + /// e.g. used to decided if and which line thickness is shown when multiple elements are selected. + /// public FieldAggregator FieldAggregator { get { return fieldAggregator; @@ -244,24 +247,36 @@ namespace Greenshot.Drawing { } } + /// + /// The cursor container has it's own accessor so we can find and remove this (when needed) + /// public IDrawableContainer CursorContainer { get { return cursorContainer; } } + /// + /// A simple getter to ask if this surface has a cursor + /// public bool HasCursor { get { return cursorContainer != null; } } + /// + /// A simple helper method to remove the cursor from the surface + /// public void RemoveCursor() { RemoveElement(cursorContainer, true); cursorContainer = null; } - public TextureBrush TransparencyBackgroundBrush { + /// + /// The brush which is used to draw the transparent background + /// + public Brush TransparencyBackgroundBrush { get { return transparencyBackgroundBrush; } @@ -270,6 +285,9 @@ namespace Greenshot.Drawing { } } + /// + /// Are the keys on this surface locked? + /// public bool KeysLocked { get { return keysLocked; @@ -279,6 +297,9 @@ namespace Greenshot.Drawing { } } + /// + /// Is this surface modified? This is only true if the surface has not been exported. + /// public bool Modified { get { return modified; @@ -288,6 +309,9 @@ namespace Greenshot.Drawing { } } + /// + /// The DrawingMode property specifies the mode for drawing, more or less the element type. + /// public DrawingModes DrawingMode { get {return drawingMode;} set { @@ -299,7 +323,10 @@ namespace Greenshot.Drawing { CreateUndrawnElement(); } } - + + /// + /// Property for accessing the last save "full" path + /// public string LastSaveFullPath { get { return lastSaveFullPath; @@ -309,11 +336,17 @@ namespace Greenshot.Drawing { } } + /// + /// Property for accessing the URL to which the surface was recently uploaded + /// public string UploadURL { get; set; } + /// + /// Property for accessing the capture details + /// public ICaptureDetails CaptureDetails { get { return captureDetails; @@ -322,7 +355,10 @@ namespace Greenshot.Drawing { captureDetails = value; } } - + + /// + /// Base Surface constructor + /// public Surface() : base(){ LOG.Debug("Creating a surface!"); this.MouseDown += new MouseEventHandler(SurfaceMouseDown); @@ -362,11 +398,19 @@ namespace Greenshot.Drawing { modified = true; } + /// + /// Surface constructor with an image + /// + /// public Surface(Image newImage) : this() { LOG.Debug("Got image with dimensions " + newImage.Width + "," + newImage.Height + " bpp: " + newImage.PixelFormat); SetImage(newImage, true); } - + + /// + /// Surface contructor with a capture + /// + /// public Surface(ICapture capture) : this(capture.Image) { // Make sure the image is NOT disposed, we took the reference directly into ourselves ((Capture)capture).NullImage(); @@ -378,10 +422,10 @@ namespace Greenshot.Drawing { captureDetails = capture.CaptureDetails; } - /** - * The public accessible Dispose - * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice - */ + /// + /// The public accessible Dispose + /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + /// public new void Dispose() { LOG.Debug("Disposing a surface!"); if (buffer != null) { @@ -428,31 +472,44 @@ namespace Greenshot.Drawing { } } + /// + /// Returns if the surface can do a undo + /// public bool CanUndo { get { return undoStack.Count > 0; } } + + /// + /// Returns if the surface can do a redo + /// public bool CanRedo { get { return redoStack.Count > 0; } } - - public LangKey UndoActionKey { + + /// + /// Get the language key for the undo action + /// + public LangKey UndoActionLanguageKey { get { if (CanUndo) { - return undoStack.Peek().ActionKey; + return undoStack.Peek().ActionLanguageKey; } else { return LangKey.none; } } } - public LangKey RedoActionKey { + /// + /// Get the language key for redo action + /// + public LangKey RedoActionLanguageKey { get { if (CanRedo) { - return redoStack.Peek().ActionKey; + return redoStack.Peek().ActionLanguageKey; } else { return LangKey.none; } @@ -482,7 +539,13 @@ namespace Greenshot.Drawing { } } } - + + /// + /// This saves the elements of this surface to a stream. + /// Is used to save a template of the complete surface + /// + /// + /// public long SaveElementsToStream(Stream streamWrite) { long bytesWritten = 0; try { @@ -495,7 +558,11 @@ namespace Greenshot.Drawing { } return bytesWritten; } - + + /// + /// This loads elements from a stream, among others this is used to load a surface. + /// + /// public void LoadElementsFromStream(Stream streamRead) { try { BinaryFormatter binaryRead = new BinaryFormatter(); @@ -512,6 +579,11 @@ namespace Greenshot.Drawing { } } + /// + /// This is called from the DrawingMode setter, which is not very correct... + /// But here an element is created which is not yet draw, thus "undrawnElement". + /// The element is than used while drawing on the surface. + /// private void CreateUndrawnElement() { if(undrawnElement != null) { FieldAggregator.UnbindElement(undrawnElement); @@ -878,11 +950,18 @@ namespace Greenshot.Drawing { /// true if this is possible public bool isCropPossible(ref Rectangle cropRectangle) { cropRectangle = Helpers.GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); - if (cropRectangle.Left < 0) cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); - if (cropRectangle.Top < 0) cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); - if (cropRectangle.Left + cropRectangle.Width > Width) cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Width - cropRectangle.Left, cropRectangle.Height); - if (cropRectangle.Top + cropRectangle.Height > Height) cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Height - cropRectangle.Top); - + if (cropRectangle.Left < 0) { + cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); + } + if (cropRectangle.Top < 0) { + cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); + } + if (cropRectangle.Left + cropRectangle.Width > Width) { + cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Width - cropRectangle.Left, cropRectangle.Height); + } + if (cropRectangle.Top + cropRectangle.Height > Height) { + cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Height - cropRectangle.Top); + } if (cropRectangle.Height > 0 && cropRectangle.Width > 0) { return true; } @@ -931,6 +1010,12 @@ namespace Greenshot.Drawing { return false; } + /// + /// The background here is the captured image. + /// This is called from the SurfaceBackgroundChangeMemento. + /// + /// + /// public void UndoBackgroundChange(Image previous, Point offset) { SetImage(previous, false); elements.MoveBy(offset.X, offset.Y); @@ -939,7 +1024,12 @@ namespace Greenshot.Drawing { } Invalidate(); } - + + /// + /// This event handler is called when someone presses the mouse on a surface. + /// + /// + /// void SurfaceMouseDown(object sender, MouseEventArgs e) { mouseStart = e.Location; @@ -1002,7 +1092,12 @@ namespace Greenshot.Drawing { } } } - + + /// + /// This event handle is called when the mouse button is unpressed + /// + /// + /// void SurfaceMouseUp(object sender, MouseEventArgs e) { Point currentMouse = new Point(e.X, e.Y); @@ -1058,7 +1153,12 @@ namespace Greenshot.Drawing { drawingElement = null; } } - + + /// + /// This event handler is called when the mouse moves over the surface + /// + /// + /// void SurfaceMouseMove(object sender, MouseEventArgs e) { Point currentMouse = e.Location; @@ -1100,11 +1200,21 @@ namespace Greenshot.Drawing { } } + /// + /// This event handler is called when the surface is double clicked. + /// + /// + /// void SurfaceDoubleClick(object sender, MouseEventArgs e) { selectedElements.OnDoubleClick(); selectedElements.Invalidate(); } + /// + /// Privately used to get the rendered image with all the elements on it. + /// + /// + /// private Image GetImage(RenderMode renderMode) { // Generate a copy of the original image with a dpi equal to the default... Bitmap clone = ImageHelper.Clone(image); @@ -1119,7 +1229,11 @@ namespace Greenshot.Drawing { } return clone; } - + + /// + /// This returns the image "result" of this surface, with all the elements rendered on it. + /// + /// public Image GetImageForExport() { return GetImage(RenderMode.EXPORT); } @@ -1166,7 +1280,10 @@ namespace Greenshot.Drawing { } } - // Draw a checkboard when capturing with transparency + /// + /// Draw a checkboard when capturing with transparency + /// + /// PaintEventArgs protected override void OnPaintBackground(PaintEventArgs e) { // check if we need to draw the checkerboard if (Image.IsAlphaPixelFormat(Image.PixelFormat) && transparencyBackgroundBrush != null) { @@ -1210,6 +1327,11 @@ namespace Greenshot.Drawing { modified = true; } + /// + /// Remove an element of the elements list + /// + /// Element to remove + /// flag specifying if the remove needs to be undoable public void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable) { DeselectElement(elementToRemove); elements.Remove(elementToRemove); @@ -1225,19 +1347,32 @@ namespace Greenshot.Drawing { } modified = true; } - + + /// + /// Add the supplied elements to the surface + /// + /// public void AddElements(DrawableContainerList elementsToAdd) { foreach(IDrawableContainer element in elementsToAdd) { AddElement(element, true); } } - - public bool HasSelectedElements() { - return (selectedElements != null && selectedElements.Count > 0); + + /// + /// Returns if this surface has selected elements + /// + /// + public bool HasSelectedElements { + get { + return (selectedElements != null && selectedElements.Count > 0); + } } - + + /// + /// Remove all the selected elements + /// public void RemoveSelectedElements() { - if (HasSelectedElements()) { + if (HasSelectedElements) { // As RemoveElement will remove the element from the selectedElements list we need to copy the element // to another list. List elementsToRemove = new List(); @@ -1255,20 +1390,31 @@ namespace Greenshot.Drawing { } } } - + + /// + /// Cut the selected elements from the surface to the clipboard + /// public void CutSelectedElements() { - if (HasSelectedElements()) { + if (HasSelectedElements) { ClipboardHelper.SetClipboardData(typeof(DrawableContainerList), selectedElements); RemoveSelectedElements(); } } - + + /// + /// Copy the selected elements to the clipboard + /// public void CopySelectedElements() { - if (HasSelectedElements()) { + if (HasSelectedElements) { ClipboardHelper.SetClipboardData(typeof(DrawableContainerList), selectedElements); } } - + + /// + /// This method is called to confirm/cancel "confirmable" elements, like the crop-container. + /// Called when pressing enter or using the "check" in the editor. + /// + /// public void ConfirmSelectedConfirmableElements(bool confirm){ // create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel) List selectedDCs = new List(selectedElements); @@ -1284,7 +1430,10 @@ namespace Greenshot.Drawing { } } } - + + /// + /// Paste all the elements that are on the clipboard + /// public void PasteElementFromClipboard() { List formats = ClipboardHelper.GetFormats(); if (formats == null || formats.Count == 0) { @@ -1326,8 +1475,11 @@ namespace Greenshot.Drawing { } } + /// + /// Duplicate all the selecteded elements + /// public void DuplicateSelectedElements() { - if(LOG.IsDebugEnabled) LOG.Debug("Duplicating "+selectedElements.Count+" selected elements"); + LOG.DebugFormat("Duplicating {0} selected elements", selectedElements.Count); DrawableContainerList dcs = selectedElements.Clone(); dcs.Parent = this; dcs.MoveBy(10,10); @@ -1336,6 +1488,10 @@ namespace Greenshot.Drawing { SelectElements(dcs); } + /// + /// Deselect the specified element + /// + /// public void DeselectElement(IDrawableContainer container) { container.HideGrippers(); container.Selected = false; @@ -1346,8 +1502,11 @@ namespace Greenshot.Drawing { } } + /// + /// Deselect all the selected elements + /// public void DeselectAllElements() { - if (HasSelectedElements()) { + if (HasSelectedElements) { while(selectedElements.Count > 0) { IDrawableContainer element = selectedElements[0]; element.Invalidate(); @@ -1361,7 +1520,11 @@ namespace Greenshot.Drawing { } } } - + + /// + /// Select the supplied element + /// + /// public void SelectElement(IDrawableContainer container) { if (!selectedElements.Contains(container)) { selectedElements.Add(container); @@ -1374,17 +1537,28 @@ namespace Greenshot.Drawing { container.Invalidate(); } } - + + /// + /// Select all elements, this is called when Ctrl+A is pressed + /// public void SelectAllElements() { SelectElements(elements); } - + + /// + /// Select the supplied elements + /// + /// public void SelectElements(DrawableContainerList elements) { foreach(DrawableContainer element in elements) { SelectElement(element); } } + /// + /// Process key + /// + /// public void ProcessCmdKey(Keys k) { if (selectedElements.Count > 0) { bool shiftModifier = (Control.ModifierKeys & Keys.Shift) == Keys.Shift; @@ -1438,7 +1612,10 @@ namespace Greenshot.Drawing { } } } - + + /// + /// Property for accessing the elements on the surface + /// public DrawableContainerList Elements { get { return elements; diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index 0f24f883e..fce9d2b8c 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -811,8 +811,8 @@ namespace Greenshot { this.undoToolStripMenuItem.Enabled = canUndo; string undoAction = ""; if (canUndo) { - if (surface.UndoActionKey != LangKey.none) { - undoAction = Language.GetString(surface.UndoActionKey); + if (surface.UndoActionLanguageKey != LangKey.none) { + undoAction = Language.GetString(surface.UndoActionLanguageKey); } } string undoText = Language.GetFormattedString(LangKey.editor_undo, undoAction); @@ -824,8 +824,8 @@ namespace Greenshot { this.redoToolStripMenuItem.Enabled = canRedo; string redoAction = ""; if (canRedo) { - if (surface.RedoActionKey != LangKey.none) { - redoAction = Language.GetString(surface.RedoActionKey); + if (surface.RedoActionLanguageKey != LangKey.none) { + redoAction = Language.GetString(surface.RedoActionLanguageKey); } } string redoText = Language.GetFormattedString(LangKey.editor_redo, redoAction); @@ -839,7 +839,7 @@ namespace Greenshot { return; } // check dependencies for the Surface - bool hasItems = surface.HasSelectedElements(); + bool hasItems = surface.HasSelectedElements; bool actionAllowedForSelection = hasItems && !controlsDisabledDueToConfirmable; // buttons @@ -918,7 +918,7 @@ namespace Greenshot { /// private void refreshFieldControls() { propertiesToolStrip.SuspendLayout(); - if(surface.HasSelectedElements() || surface.DrawingMode != DrawingModes.None) { + if(surface.HasSelectedElements || surface.DrawingMode != DrawingModes.None) { FieldAggregator props = surface.FieldAggregator; btnFillColor.Visible = props.HasFieldValue(FieldType.FILL_COLOR); btnLineColor.Visible = props.HasFieldValue(FieldType.LINE_COLOR); @@ -983,7 +983,7 @@ namespace Greenshot { updateUndoRedoSurfaceDependencies(); // en/disablearrage controls depending on hierarchy of selected elements - bool actionAllowedForSelection = surface.HasSelectedElements() && !controlsDisabledDueToConfirmable; + bool actionAllowedForSelection = surface.HasSelectedElements && !controlsDisabledDueToConfirmable; bool push = actionAllowedForSelection && surface.CanPushSelectionDown(); bool pull = actionAllowedForSelection && surface.CanPullSelectionUp(); this.arrangeToolStripMenuItem.Enabled = (push || pull); diff --git a/Greenshot/Memento/AddElementMemento.cs b/Greenshot/Memento/AddElementMemento.cs index 6fe178664..ae822458e 100644 --- a/Greenshot/Memento/AddElementMemento.cs +++ b/Greenshot/Memento/AddElementMemento.cs @@ -39,7 +39,7 @@ namespace Greenshot.Memento { public void Dispose() { } - public LangKey ActionKey { + public LangKey ActionLanguageKey { get { return LangKey.none; } @@ -52,9 +52,12 @@ namespace Greenshot.Memento { public IMemento Restore() { // Before drawableContainer.Invalidate(); + // Store the selected state, as it's overwritten by the RemoveElement + bool selected = drawableContainer.Selected; DeleteElementMemento oldState = new DeleteElementMemento(surface, drawableContainer); surface.RemoveElement(drawableContainer, false); + drawableContainer.Selected = true; // After drawableContainer.Invalidate(); diff --git a/Greenshot/Memento/ChangeFieldHolderMemento.cs b/Greenshot/Memento/ChangeFieldHolderMemento.cs index 4e986810d..184176c58 100644 --- a/Greenshot/Memento/ChangeFieldHolderMemento.cs +++ b/Greenshot/Memento/ChangeFieldHolderMemento.cs @@ -42,7 +42,7 @@ namespace Greenshot.Memento { public void Dispose() { } - public LangKey ActionKey { + public LangKey ActionLanguageKey { get { return LangKey.none; } diff --git a/Greenshot/Memento/DeleteElementMemento.cs b/Greenshot/Memento/DeleteElementMemento.cs index 126fd0841..13cb19942 100644 --- a/Greenshot/Memento/DeleteElementMemento.cs +++ b/Greenshot/Memento/DeleteElementMemento.cs @@ -43,7 +43,7 @@ namespace Greenshot.Memento { } } - public LangKey ActionKey { + public LangKey ActionLanguageKey { get { //return LangKey.editor_deleteelement; return LangKey.none; @@ -60,6 +60,10 @@ namespace Greenshot.Memento { AddElementMemento oldState = new AddElementMemento(surface, drawableContainer); surface.AddElement(drawableContainer, false); + // The container has a selected flag which represents the state at the moment it was deleted. + if (drawableContainer.Selected) { + surface.SelectElement(drawableContainer); + } // After drawableContainer.Invalidate(); diff --git a/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs b/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs index 987618a65..be8d9cefa 100644 --- a/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs +++ b/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs @@ -56,7 +56,7 @@ namespace Greenshot.Memento { public void Dispose() { } - public LangKey ActionKey { + public LangKey ActionLanguageKey { get { return LangKey.none; } diff --git a/Greenshot/Memento/IMemento.cs b/Greenshot/Memento/IMemento.cs index 9ce0ac9fc..1561a1bff 100644 --- a/Greenshot/Memento/IMemento.cs +++ b/Greenshot/Memento/IMemento.cs @@ -44,7 +44,7 @@ namespace Greenshot.Memento { /// /// Returns the language key for the action which is performed /// - LangKey ActionKey { + LangKey ActionLanguageKey { get; } } diff --git a/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs b/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs index b029924dd..90ef081ee 100644 --- a/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs +++ b/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs @@ -50,7 +50,7 @@ namespace Greenshot.Memento { return false; } - public LangKey ActionKey { + public LangKey ActionLanguageKey { get { //return LangKey.editor_crop; return LangKey.none; diff --git a/Greenshot/Memento/TextChangeMemento.cs b/Greenshot/Memento/TextChangeMemento.cs index b53b50704..3748f9d8b 100644 --- a/Greenshot/Memento/TextChangeMemento.cs +++ b/Greenshot/Memento/TextChangeMemento.cs @@ -38,7 +38,7 @@ namespace Greenshot.Memento { public void Dispose() { } - public LangKey ActionKey { + public LangKey ActionLanguageKey { get { return LangKey.none; } diff --git a/GreenshotPlugin/Interfaces/Generic.cs b/GreenshotPlugin/Interfaces/Generic.cs index 2aed38908..00efc7dd5 100644 --- a/GreenshotPlugin/Interfaces/Generic.cs +++ b/GreenshotPlugin/Interfaces/Generic.cs @@ -121,7 +121,9 @@ namespace Greenshot.Plugin { long SaveElementsToStream(Stream stream); void LoadElementsFromStream(Stream stream); - bool HasSelectedElements(); + bool HasSelectedElements { + get; + } void RemoveSelectedElements(); void CutSelectedElements(); void CopySelectedElements();