diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index a6673d091..3557bcf52 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -32,12 +32,14 @@ using System.Drawing.Text; using System.Runtime.Serialization; using System.Windows.Forms; -namespace Greenshot.Drawing { +namespace Greenshot.Drawing +{ /// /// Represents a textbox (extends RectangleContainer for border/background support /// - [Serializable] - public class TextContainer : RectangleContainer, ITextContainer { + [Serializable] + public class TextContainer : RectangleContainer, ITextContainer + { // If makeUndoable is true the next text-change will make the change undoable. // This is set to true AFTER the first change is made, as there is already a "add element" on the undo stack // Although the name is wrong, we can't change it due to file serialization @@ -61,29 +63,36 @@ namespace Greenshot.Drawing { // ReSharper disable once InconsistentNaming private string text; // there is a binding on the following property! - public string Text { + public string Text + { get { return text; } - set { + set + { ChangeText(value, true); } } - - internal void ChangeText(string newText, bool allowUndoable) { - if ((text == null && newText != null) || !string.Equals(text, newText)) { - if (makeUndoable && allowUndoable) { + + internal void ChangeText(string newText, bool allowUndoable) + { + if ((text == null && newText != null) || !string.Equals(text, newText)) + { + if (makeUndoable && allowUndoable) + { makeUndoable = false; _parent.MakeUndoable(new TextChangeMemento(this), false); } - text = newText; - OnPropertyChanged("Text"); + text = newText; + OnPropertyChanged("Text"); } } - - public TextContainer(Surface parent) : base(parent) { + + public TextContainer(Surface parent) : base(parent) + { Init(); } - protected override void InitializeFields() { + protected override void InitializeFields() + { AddField(GetType(), FieldType.LINE_THICKNESS, 2); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); AddField(GetType(), FieldType.SHADOW, true); @@ -100,30 +109,37 @@ namespace Greenshot.Drawing { /// Do some logic to make sure all field are initiated correctly /// /// StreamingContext - protected override void OnDeserialized(StreamingContext streamingContext) { + protected override void OnDeserialized(StreamingContext streamingContext) + { base.OnDeserialized(streamingContext); Init(); } - protected override void Dispose(bool disposing) { - if (disposing) { - if (_font != null) { + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_font != null) + { _font.Dispose(); _font = null; } - if (_stringFormat != null) { + if (_stringFormat != null) + { _stringFormat.Dispose(); _stringFormat = null; } - if (_textBox != null) { + if (_textBox != null) + { _textBox.Dispose(); _textBox = null; } } base.Dispose(disposing); } - - private void Init() { + + private void Init() + { _stringFormat = new StringFormat { Trimming = StringTrimming.EllipsisWord @@ -139,69 +155,89 @@ namespace Greenshot.Drawing { } - public override void Invalidate() { + public override void Invalidate() + { base.Invalidate(); - if (_textBox != null && _textBox.Visible) { + if (_textBox != null && _textBox.Visible) + { _textBox.Invalidate(); } } - - public void FitToText() { + + public void FitToText() + { Size textSize = TextRenderer.MeasureText(text, _font); int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); Width = textSize.Width + lineThickness; Height = textSize.Height + lineThickness; } - void TextContainer_PropertyChanged(object sender, PropertyChangedEventArgs e) { - if (_textBox.Visible) { + void TextContainer_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (_textBox.Visible) + { _textBox.Invalidate(); } UpdateTextBoxPosition(); UpdateTextBoxFormat(); - if (e.PropertyName.Equals("Selected")) { - if (!Selected && _textBox.Visible) { + if (e.PropertyName.Equals("Selected")) + { + if (!Selected && _textBox.Visible) + { HideTextBox(); - } else if (Selected && Status == EditStatus.DRAWING) { + } + else if (Selected && Status == EditStatus.DRAWING) + { ShowTextBox(); - } else if (_parent != null && Selected && Status == EditStatus.IDLE && _textBox.Visible) { + } + else if (_parent != null && Selected && Status == EditStatus.IDLE && _textBox.Visible) + { // Fix (workaround) for BUG-1698 _parent.KeysLocked = true; } } - if (_textBox.Visible) { + if (_textBox.Visible) + { _textBox.Invalidate(); } } - - void TextContainer_FieldChanged(object sender, FieldChangedEventArgs e) { - if (_textBox.Visible) { + + void TextContainer_FieldChanged(object sender, FieldChangedEventArgs e) + { + if (_textBox.Visible) + { _textBox.Invalidate(); } // Only dispose the font, and re-create it, when a font field has changed. - if (e.Field.FieldType.Name.StartsWith("FONT")) { + if (e.Field.FieldType.Name.StartsWith("FONT")) + { if (_font != null) { _font.Dispose(); _font = null; } UpdateFormat(); - } else { + } + else + { UpdateAlignment(); } UpdateTextBoxFormat(); - - if (_textBox != null && _textBox.Visible) { + + if (_textBox != null && _textBox.Visible) + { _textBox.Invalidate(); } } - - public override void OnDoubleClick() { + + public override void OnDoubleClick() + { ShowTextBox(); } - - private void CreateTextBox() { + + private void CreateTextBox() + { _textBox = new TextBox { ImeMode = ImeMode.On, @@ -217,7 +253,8 @@ namespace Greenshot.Drawing { _textBox.KeyDown += textBox_KeyDown; } - private void ShowTextBox() { + private void ShowTextBox() + { if (_parent != null) { _parent.KeysLocked = true; @@ -231,16 +268,21 @@ namespace Greenshot.Drawing { /// /// Makes textbox background dark if text color is very bright /// - private void EnsureTextBoxContrast() { + private void EnsureTextBoxContrast() + { Color lc = GetFieldValueAsColor(FieldType.LINE_COLOR); - if (lc.R > 203 && lc.G > 203 && lc.B > 203) { + if (lc.R > 203 && lc.G > 203 && lc.B > 203) + { _textBox.BackColor = Color.FromArgb(51, 51, 51); - } else { + } + else + { _textBox.BackColor = Color.White; } } - - private void HideTextBox() { + + private void HideTextBox() + { _parent.Focus(); _textBox.Hide(); _parent.KeysLocked = false; @@ -251,7 +293,8 @@ namespace Greenshot.Drawing { /// Make sure the size of the font is scaled /// /// - public override void Transform(Matrix matrix) { + public override void Transform(Matrix matrix) + { Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); int pixelsBefore = rect.Width * rect.Height; @@ -268,59 +311,94 @@ namespace Greenshot.Drawing { UpdateFormat(); } + private Font CreateFont(string fontFamily, bool fontBold, bool fontItalic, float fontSize) + { + FontStyle fs = FontStyle.Regular; + + bool hasStyle = false; + using (FontFamily fam = new FontFamily(fontFamily)) + { + bool boldAvailable = fam.IsStyleAvailable(FontStyle.Bold); + if (fontBold && boldAvailable) + { + fs |= FontStyle.Bold; + hasStyle = true; + } + + bool italicAvailable = fam.IsStyleAvailable(FontStyle.Italic); + if (fontItalic && italicAvailable) + { + fs |= FontStyle.Italic; + hasStyle = true; + } + + if (!hasStyle) + { + bool regularAvailable = fam.IsStyleAvailable(FontStyle.Regular); + if (regularAvailable) + { + fs = FontStyle.Regular; + } + else + { + if (boldAvailable) + { + fs = FontStyle.Bold; + } + else if (italicAvailable) + { + fs = FontStyle.Italic; + } + } + } + return new Font(fam, fontSize, fs, GraphicsUnit.Pixel); + } + } + /// /// Generate the Font-Formal so we can draw correctly /// - protected void UpdateFormat() { + protected void UpdateFormat() + { string fontFamily = GetFieldValueAsString(FieldType.FONT_FAMILY); bool fontBold = GetFieldValueAsBool(FieldType.FONT_BOLD); bool fontItalic = GetFieldValueAsBool(FieldType.FONT_ITALIC); float fontSize = GetFieldValueAsFloat(FieldType.FONT_SIZE); - try { - FontStyle fs = FontStyle.Regular; - - bool hasStyle = false; - using(FontFamily fam = new FontFamily(fontFamily)) { - bool boldAvailable = fam.IsStyleAvailable(FontStyle.Bold); - if (fontBold && boldAvailable) { - fs |= FontStyle.Bold; - hasStyle = true; - } - - bool italicAvailable = fam.IsStyleAvailable(FontStyle.Italic); - if (fontItalic && italicAvailable) { - fs |= FontStyle.Italic; - hasStyle = true; - } - - if (!hasStyle) { - bool regularAvailable = fam.IsStyleAvailable(FontStyle.Regular); - if (regularAvailable) { - fs = FontStyle.Regular; - } else { - if (boldAvailable) { - fs = FontStyle.Bold; - } else if(italicAvailable) { - fs = FontStyle.Italic; - } - } - } + try + { + var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize); + _font?.Dispose(); + _font = newFont; + _textBox.Font = _font; + } + catch (Exception ex) + { + // Problem, try again with the default + try + { + fontFamily = FontFamily.GenericSansSerif.Name; + SetFieldValue(FieldType.FONT_FAMILY, fontFamily); + var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize); _font?.Dispose(); - _font = new Font(fam, fontSize, fs, GraphicsUnit.Pixel); + _font = newFont; _textBox.Font = _font; } - } catch (Exception ex) { - ex.Data.Add("fontFamily", fontFamily); - ex.Data.Add("fontBold", fontBold); - ex.Data.Add("fontItalic", fontItalic); - ex.Data.Add("fontSize", fontSize); - throw; + catch (Exception ex2) + { + // When this happens... the PC is broken + ex.Data.Add("fontFamily", fontFamily); + ex.Data.Add("fontBold", fontBold); + ex.Data.Add("fontItalic", fontItalic); + ex.Data.Add("fontSize", fontSize); + throw ex; + } } - + UpdateAlignment(); } - private void UpdateAlignment() { + private void UpdateAlignment() + { _stringFormat.Alignment = (StringAlignment)GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); _stringFormat.LineAlignment = (StringAlignment)GetFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT); } @@ -329,36 +407,43 @@ namespace Greenshot.Drawing { /// This will create the textbox exactly to the inner size of the element /// is a bit of a hack, but for now it seems to work... /// - private void UpdateTextBoxPosition() { + private void UpdateTextBoxPosition() + { int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); int lineWidth = (int)Math.Floor(lineThickness / 2d); - int correction = (lineThickness +1 ) % 2; - if (lineThickness <= 1) { + int correction = (lineThickness + 1) % 2; + if (lineThickness <= 1) + { lineWidth = 1; correction = -1; } Rectangle absRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); _textBox.Left = absRectangle.Left + lineWidth; _textBox.Top = absRectangle.Top + lineWidth; - if (lineThickness <= 1) { + if (lineThickness <= 1) + { lineWidth = 0; } _textBox.Width = absRectangle.Width - 2 * lineWidth + correction; _textBox.Height = absRectangle.Height - 2 * lineWidth + correction; } - public override void ApplyBounds(RectangleF newBounds) { + public override void ApplyBounds(RectangleF newBounds) + { base.ApplyBounds(newBounds); UpdateTextBoxPosition(); } - private void UpdateTextBoxFormat() { - if (_textBox == null) { + private void UpdateTextBoxFormat() + { + if (_textBox == null) + { return; } StringAlignment alignment = (StringAlignment)GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); - switch (alignment) { + switch (alignment) + { case StringAlignment.Near: _textBox.TextAlign = HorizontalAlignment.Left; break; @@ -373,22 +458,26 @@ namespace Greenshot.Drawing { Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); _textBox.ForeColor = lineColor; } - - void textBox_KeyDown(object sender, KeyEventArgs e) { + + void textBox_KeyDown(object sender, KeyEventArgs e) + { // ESC and Enter/Return (w/o Shift) hide text editor - if(e.KeyCode == Keys.Escape || ((e.KeyCode == Keys.Return || e.KeyCode == Keys.Enter) && e.Modifiers == Keys.None)) { + if (e.KeyCode == Keys.Escape || ((e.KeyCode == Keys.Return || e.KeyCode == Keys.Enter) && e.Modifiers == Keys.None)) + { HideTextBox(); e.SuppressKeyPress = true; } } - void textBox_LostFocus(object sender, EventArgs e) { + void textBox_LostFocus(object sender, EventArgs e) + { // next change will be made undoable makeUndoable = true; HideTextBox(); } - - public override void Draw(Graphics graphics, RenderMode rm) { + + public override void Draw(Graphics graphics, RenderMode rm) + { base.Draw(graphics, rm); graphics.SmoothingMode = SmoothingMode.HighQuality; @@ -398,11 +487,13 @@ namespace Greenshot.Drawing { graphics.TextRenderingHint = TextRenderingHint.SystemDefault; Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - if (Selected && rm == RenderMode.EDIT) { + if (Selected && rm == RenderMode.EDIT) + { DrawSelectionBorder(graphics, rect); } - - if (string.IsNullOrEmpty(text) ) { + + if (string.IsNullOrEmpty(text)) + { return; } @@ -427,21 +518,26 @@ namespace Greenshot.Drawing { /// /// /// - public static void DrawText(Graphics graphics, Rectangle drawingRectange, int lineThickness, Color fontColor, bool drawShadow, StringFormat stringFormat, string text, Font font) { + public static void DrawText(Graphics graphics, Rectangle drawingRectange, int lineThickness, Color fontColor, bool drawShadow, StringFormat stringFormat, string text, Font font) + { int textOffset = lineThickness > 0 ? (int)Math.Ceiling(lineThickness / 2d) : 0; // draw shadow before anything else - if (drawShadow) { + if (drawShadow) + { int basealpha = 100; int alpha = basealpha; int steps = 5; int currentStep = 1; - while (currentStep <= steps) { + while (currentStep <= steps) + { int offset = currentStep; Rectangle shadowRect = GuiRectangle.GetGuiRectangle(drawingRectange.Left + offset, drawingRectange.Top + offset, drawingRectange.Width, drawingRectange.Height); - if (lineThickness > 0) { + if (lineThickness > 0) + { shadowRect.Inflate(-textOffset, -textOffset); } - using (Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100))) { + using (Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100))) + { graphics.DrawString(text, font, fontBrush, shadowRect, stringFormat); currentStep++; alpha = alpha - basealpha / steps; @@ -449,19 +545,25 @@ namespace Greenshot.Drawing { } } - if (lineThickness > 0) { + if (lineThickness > 0) + { drawingRectange.Inflate(-textOffset, -textOffset); } - using (Brush fontBrush = new SolidBrush(fontColor)) { - if (stringFormat != null) { + using (Brush fontBrush = new SolidBrush(fontColor)) + { + if (stringFormat != null) + { graphics.DrawString(text, font, fontBrush, drawingRectange, stringFormat); - } else { + } + else + { graphics.DrawString(text, font, fontBrush, drawingRectange); } } } - public override bool ClickableAt(int x, int y) { + public override bool ClickableAt(int x, int y) + { Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); r.Inflate(5, 5); return r.Contains(x, y); diff --git a/Greenshot/releases/additional_files/readme.txt.template b/Greenshot/releases/additional_files/readme.txt.template index 699607d51..7d6b75922 100644 --- a/Greenshot/releases/additional_files/readme.txt.template +++ b/Greenshot/releases/additional_files/readme.txt.template @@ -26,6 +26,7 @@ Fixed: * BUG-1949: Can't delete Imgur upload * BUG-1965: Activation border around window is visible in the capture * BUG-1991: Greenshot portable (PAF) uses wrong log configuration +* BUG-2011: Editor issues when the font is gone or broken * FEATURE-916: Added ico file format * FEATURE-919: Allow adding of space around screenshot (use Ctrl + / Ctrl -) * FEATURE-945: Added environment variables resolving to the external command