Fixed the target-gripper logic (needed for the speech bubble) and made the drawing of Rectangles / Ellipses possible without extending the container (making it possible to use different shapes depending on a variable). The new containers (SpeechBubble & StepLabel) are mostly working with this change, default colors/sizes should be decided upon and translations/icons are still missing. There is one bug with the Speechbubble when resizing (right before left, bottom before top), should not be a show-stopper but needs lookin into.

This commit is contained in:
RKrom 2014-05-27 12:44:01 +02:00
parent ff3f898f54
commit aa5893fc77
6 changed files with 240 additions and 124 deletions

View file

@ -46,7 +46,7 @@ namespace Greenshot.Drawing {
public abstract class DrawableContainer : AbstractFieldHolderWithChildren, INotifyPropertyChanged, IDrawableContainer {
private static readonly ILog LOG = LogManager.GetLogger(typeof(DrawableContainer));
protected static readonly EditorConfiguration editorConfig = IniConfig.GetIniSection<EditorConfiguration>();
private bool isMadeUndoable = false;
private bool _isMadeUndoable = false;
protected EditStatus _defaultEditMode = EditStatus.DRAWING;
public EditStatus DefaultEditMode {
@ -141,45 +141,45 @@ namespace Greenshot.Drawing {
}
private int left = 0;
private int _left = 0;
public int Left {
get { return left; }
get { return _left; }
set {
if(value != left) {
left = value;
if(value != _left) {
_left = value;
DoLayout();
}
}
}
private int top = 0;
private int _top = 0;
public int Top {
get { return top; }
get { return _top; }
set {
if(value != top) {
top = value;
if(value != _top) {
_top = value;
DoLayout();
}
}
}
private int width = 0;
private int _width = 0;
public int Width {
get { return width; }
get { return _width; }
set {
if(value != width) {
width = value;
if(value != _width) {
_width = value;
DoLayout();
}
}
}
private int height = 0;
private int _height = 0;
public int Height {
get { return height; }
get { return _height; }
set {
if(value != height) {
height = value;
if(value != _height) {
_height = value;
DoLayout();
}
}
@ -187,13 +187,13 @@ namespace Greenshot.Drawing {
public Point Location {
get {
return new Point(left, top);
return new Point(_left, _top);
}
}
public Size Size {
get {
return new Size(width, height);
return new Size(_width, _height);
}
}
@ -201,13 +201,13 @@ namespace Greenshot.Drawing {
/// <summary>
/// will store current bounds of this DrawableContainer before starting a resize
/// </summary>
private Rectangle boundsBeforeResize = Rectangle.Empty;
private Rectangle _boundsBeforeResize = Rectangle.Empty;
[NonSerialized]
/// <summary>
/// "workbench" rectangle - used for calculatoing bounds during resizing (to be applied to this DrawableContainer afterwards)
/// </summary>
private RectangleF boundsAfterResize = RectangleF.Empty;
private RectangleF _boundsAfterResize = RectangleF.Empty;
public Rectangle Bounds {
get { return GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); }
@ -417,17 +417,25 @@ namespace Greenshot.Drawing {
private void gripperMouseDown(object sender, MouseEventArgs e) {
mx = e.X;
my = e.Y;
Status = EditStatus.RESIZING;
boundsBeforeResize = new Rectangle(left, top, width, height);
boundsAfterResize = new RectangleF(boundsBeforeResize.Left, boundsBeforeResize.Top, boundsBeforeResize.Width, boundsBeforeResize.Height);
isMadeUndoable = false;
Gripper originatingGripper = (Gripper)sender;
if (originatingGripper != _targetGripper) {
Status = EditStatus.RESIZING;
_boundsBeforeResize = new Rectangle(_left, _top, _width, _height);
_boundsAfterResize = new RectangleF(_boundsBeforeResize.Left, _boundsBeforeResize.Top, _boundsBeforeResize.Width, _boundsBeforeResize.Height);
} else {
Status = EditStatus.MOVING;
}
_isMadeUndoable = false;
}
private void gripperMouseUp(object sender, MouseEventArgs e) {
Gripper originatingGripper = (Gripper)sender;
if (originatingGripper != _targetGripper) {
_boundsBeforeResize = Rectangle.Empty;
_boundsAfterResize = RectangleF.Empty;
_isMadeUndoable = false;
}
Status = EditStatus.IDLE;
boundsBeforeResize = Rectangle.Empty;
boundsAfterResize = RectangleF.Empty;
isMadeUndoable = false;
Invalidate();
}
@ -439,9 +447,9 @@ namespace Greenshot.Drawing {
TargetGripperMove(absX, absY);
} else if (Status.Equals(EditStatus.RESIZING)) {
// check if we already made this undoable
if (!isMadeUndoable) {
if (!_isMadeUndoable) {
// don't allow another undo until we are finished with this move
isMadeUndoable = true;
_isMadeUndoable = true;
// Make undo-able
MakeBoundsChangeUndoable(false);
}
@ -450,16 +458,16 @@ namespace Greenshot.Drawing {
SuspendLayout();
// reset "workbench" rectangle to current bounds
boundsAfterResize.X = boundsBeforeResize.X;
boundsAfterResize.Y = boundsBeforeResize.Y;
boundsAfterResize.Width = boundsBeforeResize.Width;
boundsAfterResize.Height = boundsBeforeResize.Height;
_boundsAfterResize.X = _boundsBeforeResize.X;
_boundsAfterResize.Y = _boundsBeforeResize.Y;
_boundsAfterResize.Width = _boundsBeforeResize.Width;
_boundsAfterResize.Height = _boundsBeforeResize.Height;
// calculate scaled rectangle
ScaleHelper.Scale(ref boundsAfterResize, originatingGripper.Position, new PointF(absX, absY), ScaleHelper.GetScaleOptions());
ScaleHelper.Scale(ref _boundsAfterResize, originatingGripper.Position, new PointF(absX, absY), ScaleHelper.GetScaleOptions());
// apply scaled bounds to this DrawableContainer
ApplyBounds(boundsAfterResize);
ApplyBounds(_boundsAfterResize);
ResumeLayout();
Invalidate();
@ -541,6 +549,13 @@ namespace Greenshot.Drawing {
}
}
}
if (_targetGripper != null) {
if (_targetGripper.Enabled) {
_targetGripper.Show();
} else {
_targetGripper.Hide();
}
}
ResumeLayout();
}
@ -551,6 +566,9 @@ namespace Greenshot.Drawing {
_grippers[i].Hide();
}
}
if (_targetGripper != null) {
_targetGripper.Hide();
}
}
public void ResizeTo(int width, int height, int anchorPosition) {
@ -582,8 +600,8 @@ namespace Greenshot.Drawing {
/// <param name="y">current mouse y</param>
/// <returns>true if the event is handled, false if the surface needs to handle it</returns>
public virtual bool HandleMouseDown(int x, int y) {
Left = boundsBeforeResize.X = x;
Top = boundsBeforeResize.Y = y;
Left = _boundsBeforeResize.X = x;
Top = _boundsBeforeResize.Y = y;
return true;
}
@ -598,15 +616,15 @@ namespace Greenshot.Drawing {
SuspendLayout();
// reset "workrbench" rectangle to current bounds
boundsAfterResize.X = boundsBeforeResize.Left;
boundsAfterResize.Y = boundsBeforeResize.Top;
boundsAfterResize.Width = x - boundsAfterResize.Left;
boundsAfterResize.Height = y - boundsAfterResize.Top;
_boundsAfterResize.X = _boundsBeforeResize.Left;
_boundsAfterResize.Y = _boundsBeforeResize.Top;
_boundsAfterResize.Width = x - _boundsAfterResize.Left;
_boundsAfterResize.Height = y - _boundsAfterResize.Top;
ScaleHelper.Scale(boundsBeforeResize, x, y, ref boundsAfterResize, GetAngleRoundProcessor());
ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor());
// apply scaled bounds to this DrawableContainer
ApplyBounds(boundsAfterResize);
ApplyBounds(_boundsAfterResize);
ResumeLayout();
Invalidate();
@ -641,7 +659,7 @@ namespace Greenshot.Drawing {
bool ret = false;
if (obj != null && GetType().Equals(obj.GetType())) {
DrawableContainer other = obj as DrawableContainer;
if (left==other.left && top==other.top && width==other.width && height==other.height) {
if (_left==other._left && _top==other._top && _width==other._width && _height==other._height) {
ret = true;
}
}
@ -649,7 +667,7 @@ namespace Greenshot.Drawing {
}
public override int GetHashCode() {
return left.GetHashCode() ^ top.GetHashCode() ^ width.GetHashCode() ^ height.GetHashCode() ^ GetFields().GetHashCode();
return _left.GetHashCode() ^ _top.GetHashCode() ^ _width.GetHashCode() ^ _height.GetHashCode() ^ GetFields().GetHashCode();
}
protected void OnPropertyChanged(string propertyName) {

View file

@ -52,6 +52,18 @@ namespace Greenshot.Drawing {
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
DrawEllipse(rect, graphics, renderMode, lineThickness, lineColor, fillColor, shadow);
}
/// <summary>
/// This allows another container to draw an ellipse
/// </summary>
/// <param name="caller"></param>
/// <param name="graphics"></param>
/// <param name="renderMode"></param>
public static void DrawEllipse(Rectangle rect, Graphics graphics, RenderMode renderMode, int lineThickness, Color lineColor, Color fillColor, bool shadow) {
bool lineVisible = (lineThickness > 0 && Colors.IsVisible(lineColor));
// draw shadow before anything else
if (shadow && (lineVisible || Colors.IsVisible(fillColor))) {
@ -62,7 +74,7 @@ namespace Greenshot.Drawing {
while (currentStep <= steps) {
using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) {
shadowPen.Width = lineVisible ? lineThickness : 1;
Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + currentStep, Top + currentStep, Width, Height);
Rectangle shadowRect = GuiRectangle.GetGuiRectangle(rect.Left + currentStep, rect.Top + currentStep, rect.Width, rect.Height);
graphics.DrawEllipse(shadowPen, shadowRect);
currentStep++;
alpha = alpha - basealpha / steps;
@ -70,7 +82,6 @@ namespace Greenshot.Drawing {
}
}
//draw the original shape
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
if (Colors.IsVisible(fillColor)) {
using (Brush brush = new SolidBrush(fillColor)) {
graphics.FillEllipse(brush, rect);
@ -84,20 +95,35 @@ namespace Greenshot.Drawing {
}
public override bool Contains(int x, int y) {
double xDistanceFromCenter = x - (Left+Width/2);
double yDistanceFromCenter = y - (Top+Height/2);
// ellipse: x^2/a^2 + y^2/b^2 = 1
return Math.Pow(xDistanceFromCenter,2)/Math.Pow(Width/2,2) + Math.Pow(yDistanceFromCenter,2)/Math.Pow(Height/2,2) < 1;
return EllipseContains(this, x, y);
}
/// <summary>
/// Allow the code to be used externally
/// </summary>
/// <param name="caller"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static bool EllipseContains(DrawableContainer caller, int x, int y) {
double xDistanceFromCenter = x - (caller.Left + caller.Width / 2);
double yDistanceFromCenter = y - (caller.Top + caller.Height / 2);
// ellipse: x^2/a^2 + y^2/b^2 = 1
return Math.Pow(xDistanceFromCenter, 2) / Math.Pow(caller.Width / 2, 2) + Math.Pow(yDistanceFromCenter, 2) / Math.Pow(caller.Height / 2, 2) < 1;
}
public override bool ClickableAt(int x, int y) {
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10;
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
return EllipseClickableAt(rect, lineThickness, fillColor, x, y);
}
public static bool EllipseClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) {
// If we clicked inside the rectangle and it's visible we are clickable at.
if (!Color.Transparent.Equals(fillColor)) {
if (Contains(x,y)) {
if (rect.Contains(x, y)) {
return true;
}
}

View file

@ -30,7 +30,7 @@ namespace Greenshot.Drawing {
/// <summary>
/// Represents a rectangular shape on the Surface
/// </summary>
[Serializable()]
[Serializable]
public class RectangleContainer : DrawableContainer {
private static readonly ILog LOG = LogManager.GetLogger(typeof(RectangleContainer));
@ -45,15 +45,31 @@ namespace Greenshot.Drawing {
}
public override void Draw(Graphics graphics, RenderMode rm) {
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
DrawRectangle(rect, graphics, rm, lineThickness, lineColor, fillColor, shadow);
}
/// <summary>
/// This method can also be used from other containers, if the right values are passed!
/// </summary>
/// <param name="rect"></param>
/// <param name="graphics"></param>
/// <param name="rm"></param>
/// <param name="lineThickness"></param>
/// <param name="lineColor"></param>
/// <param name="fillColor"></param>
/// <param name="shadow"></param>
public static void DrawRectangle(Rectangle rect, Graphics graphics, RenderMode rm, int lineThickness, Color lineColor, Color fillColor, bool shadow) {
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.None;
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
bool lineVisible = (lineThickness > 0 && Colors.IsVisible(lineColor));
if (shadow && (lineVisible || Colors.IsVisible(fillColor))) {
//draw shadow first
@ -65,18 +81,17 @@ namespace Greenshot.Drawing {
using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) {
shadowPen.Width = lineVisible ? lineThickness : 1;
Rectangle shadowRect = GuiRectangle.GetGuiRectangle(
Left + currentStep,
Top + currentStep,
Width,
Height);
rect.Left + currentStep,
rect.Top + currentStep,
rect.Width,
rect.Height);
graphics.DrawRectangle(shadowPen, shadowRect);
currentStep++;
alpha = alpha - (basealpha / steps);
}
}
}
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
if (Colors.IsVisible(fillColor)) {
using (Brush brush = new SolidBrush(fillColor)) {
@ -90,13 +105,19 @@ namespace Greenshot.Drawing {
graphics.DrawRectangle(pen, rect);
}
}
}
public override bool ClickableAt(int x, int y) {
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10;
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
return RectangleClickableAt(rect, lineThickness, fillColor, x, y);
}
public static bool RectangleClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) {
// If we clicked inside the rectangle and it's visible we are clickable at.
if (!Color.Transparent.Equals(fillColor)) {
if (rect.Contains(x,y)) {

View file

@ -42,12 +42,12 @@ namespace Greenshot.Drawing {
/// We set our own field values
/// </summary>
protected override void InitializeFields() {
AddField(GetType(), FieldType.LINE_THICKNESS, 4);
AddField(GetType(), FieldType.LINE_COLOR, Color.Blue);
AddField(GetType(), FieldType.SHADOW, true);
AddField(GetType(), FieldType.LINE_THICKNESS, 0);
AddField(GetType(), FieldType.LINE_COLOR, Color.White);
AddField(GetType(), FieldType.SHADOW, false);
AddField(GetType(), FieldType.FONT_ITALIC, false);
AddField(GetType(), FieldType.FONT_BOLD, false);
AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent);
AddField(GetType(), FieldType.FONT_BOLD, true);
AddField(GetType(), FieldType.FILL_COLOR, Color.LightBlue);
AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name);
AddField(GetType(), FieldType.FONT_SIZE, 20f);
AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, HorizontalAlignment.Center);
@ -58,6 +58,7 @@ namespace Greenshot.Drawing {
base.TargetGripperMove(absX, absY);
Invalidate();
}
/// <summary>
/// Called from Surface (the _parent) when the drawing begins (mouse-down)
/// </summary>
@ -156,15 +157,15 @@ namespace Greenshot.Drawing {
graphics.Restore(state);
}
// Draw the text
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
DrawText(graphics, GuiRectangle.GetGuiRectangle(Left, Top, Width, Height), format);
// cleanup
// cleanup the paths
bubble.Dispose();
tail.Dispose();
// Draw the text
UpdateFormat();
DrawText(graphics, rect, lineThickness, lineColor, false, StringFormat, Text, Font);
}
public override bool Contains(int x, int y) {

View file

@ -33,32 +33,50 @@ namespace Greenshot.Drawing {
/// This is an enumerated label, every single StepLabelContainer shows the number of the order it was created.
/// To make sure that deleting recalculates, we check the location before every draw.
/// </summary>
[Serializable()]
public class StepLabelContainer : TextContainer {
[Serializable]
public class StepLabelContainer : DrawableContainer {
[NonSerialized]
private StringFormat _stringFormat = new StringFormat();
[NonSerialized]
private Font _font;
private bool drawAsRectangle = false;
public StepLabelContainer(Surface parent) : base(parent) {
_defaultEditMode = EditStatus.IDLE;
parent.StepContainers.AddLast(this);
InitContent();
}
public override bool InitContent() {
_defaultEditMode = EditStatus.IDLE;
_stringFormat.Alignment = StringAlignment.Center;
_stringFormat.LineAlignment = StringAlignment.Center;
// Set defaults
Width = 40;
Height = 40;
}
public override void Dispose() {
Parent.StepContainers.Remove(this);
base.Dispose();
using (FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name)) {
_font = new Font(fam, 18, FontStyle.Regular, GraphicsUnit.Pixel);
}
return true;
}
/// <summary>
/// We set our own field values
/// </summary>
protected override void InitializeFields() {
AddField(GetType(), FieldType.LINE_COLOR, Color.White);
AddField(GetType(), FieldType.FILL_COLOR, Color.DarkRed);
AddField(GetType(), FieldType.FONT_SIZE, 21f);
AddField(GetType(), FieldType.LINE_THICKNESS, 0);
base.InitializeFields();
AddField(GetType(), FieldType.LINE_COLOR, Color.White);
}
/// <summary>
/// Make sure this element is no longer referenced from the surface
/// </summary>
public override void Dispose() {
Parent.StepContainers.Remove(this);
base.Dispose();
}
/// <summary>
/// Override the parent, calculate the label number, than draw
/// </summary>
@ -74,8 +92,26 @@ namespace Greenshot.Drawing {
number++;
}
}
this.Text = number.ToString();
base.Draw(graphics, rm);
string text = number.ToString();
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
if (drawAsRectangle) {
RectangleContainer.DrawRectangle(rect, graphics, rm, 0, Color.Transparent, fillColor, false);
} else {
EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false);
}
TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, _font);
}
public override bool ClickableAt(int x, int y) {
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
if (drawAsRectangle) {
return RectangleContainer.RectangleClickableAt(rect, 0, fillColor, x, y);
} else {
return EllipseContainer.EllipseClickableAt(rect, 0, fillColor, x, y);
}
}
}
}

View file

@ -43,13 +43,21 @@ namespace Greenshot.Drawing {
// This is set to true AFTER the first change is made, as there is already a "add element" on the undo stack
private bool makeUndoable;
private Font _font;
public Font Font {
get {
return _font;
}
}
/// <summary>
/// The StringFormat object is not serializable!!
/// </summary>
[NonSerialized]
StringFormat stringFormat = new StringFormat();
StringFormat _stringFormat = new StringFormat();
public StringFormat StringFormat {
get {
return _stringFormat;
}
}
private string _text;
// there is a binding on the following property!
public string Text {
@ -75,8 +83,8 @@ namespace Greenshot.Drawing {
public TextContainer(Surface parent) : base(parent) {
Init();
stringFormat = new StringFormat();
stringFormat.Trimming = StringTrimming.EllipsisWord;
_stringFormat = new StringFormat();
_stringFormat.Trimming = StringTrimming.EllipsisWord;
}
protected override void InitializeFields() {
@ -94,7 +102,7 @@ namespace Greenshot.Drawing {
[OnDeserialized]
private void OnDeserialized(StreamingContext context) {
stringFormat = new StringFormat();
_stringFormat = new StringFormat();
Init();
UpdateFormat();
}
@ -105,9 +113,9 @@ namespace Greenshot.Drawing {
_font.Dispose();
_font = null;
}
if (stringFormat != null) {
stringFormat.Dispose();
stringFormat = null;
if (_stringFormat != null) {
_stringFormat.Dispose();
_stringFormat = null;
}
if (textBox != null) {
textBox.Dispose();
@ -205,7 +213,7 @@ namespace Greenshot.Drawing {
_parent.Controls.Remove(textBox);
}
private void UpdateFormat() {
protected void UpdateFormat() {
string fontFamily = GetFieldValueAsString(FieldType.FONT_FAMILY);
bool fontBold = GetFieldValueAsBool(FieldType.FONT_BOLD);
bool fontItalic = GetFieldValueAsBool(FieldType.FONT_ITALIC);
@ -252,8 +260,8 @@ namespace Greenshot.Drawing {
throw;
}
stringFormat.Alignment = (StringAlignment)GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT);
stringFormat.LineAlignment = (StringAlignment)GetFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT);
_stringFormat.Alignment = (StringAlignment)GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT);
_stringFormat.LineAlignment = (StringAlignment)GetFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT);
}
private void UpdateTextBoxPosition() {
@ -311,47 +319,53 @@ namespace Greenshot.Drawing {
bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
int textOffset = (lineThickness>0) ? (int)Math.Ceiling(lineThickness/2d) : 0;
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
bool drawShadow = shadow && (fillColor == Color.Transparent || fillColor == Color.Empty);
DrawText(graphics, rect, lineThickness, lineColor, drawShadow, _stringFormat, _text, _font);
}
/// <summary>
/// This method can be used from other containers
/// </summary>
/// <param name="graphics"></param>
/// <param name="drawingRectange"></param>
/// <param name="lineThickness"></param>
/// <param name="fontColor"></param>
/// <param name="stringFormat"></param>
/// <param name="text"></param>
/// <param name="font"></param>
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 (shadow && (fillColor == Color.Transparent || fillColor == Color.Empty)) {
if (drawShadow) {
int basealpha = 100;
int alpha = basealpha;
int steps = 5;
int currentStep = 1;
while (currentStep <= steps) {
int offset = currentStep;
Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + offset, Top + offset, Width, Height);
Rectangle shadowRect = GuiRectangle.GetGuiRectangle(drawingRectange.Left + offset, drawingRectange.Top + offset, drawingRectange.Width, drawingRectange.Height);
if (lineThickness > 0) {
shadowRect.Inflate(-textOffset, -textOffset);
}
using (Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100))) {
graphics.DrawString(_text, _font, fontBrush, shadowRect, stringFormat);
graphics.DrawString(text, font, fontBrush, shadowRect, stringFormat);
currentStep++;
alpha = alpha - basealpha / steps;
}
}
}
DrawText(graphics, rect, null);
}
protected void DrawText(Graphics graphics, Rectangle drawingRectange, StringFormat stringFormat) {
UpdateFormat();
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
Rectangle fontRect = drawingRectange;
int textOffset = (lineThickness > 0) ? (int)Math.Ceiling(lineThickness / 2d) : 0;
if (lineThickness > 0) {
graphics.SmoothingMode = SmoothingMode.HighSpeed;
fontRect.Inflate(-textOffset, -textOffset);
drawingRectange.Inflate(-textOffset, -textOffset);
}
graphics.SmoothingMode = SmoothingMode.HighQuality;
using (Brush fontBrush = new SolidBrush(lineColor)) {
graphics.DrawString(_text, _font, fontBrush, fontRect);
using (Brush fontBrush = new SolidBrush(fontColor)) {
if (stringFormat != null) {
graphics.DrawString(_text, _font, fontBrush, fontRect, stringFormat);
graphics.DrawString(text, font, fontBrush, drawingRectange, stringFormat);
} else {
graphics.DrawString(_text, _font, fontBrush, fontRect);
graphics.DrawString(text, font, fontBrush, drawingRectange);
}
}
}