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

View file

@ -52,6 +52,18 @@ namespace Greenshot.Drawing {
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
bool shadow = GetFieldValueAsBool(FieldType.SHADOW); 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)); bool lineVisible = (lineThickness > 0 && Colors.IsVisible(lineColor));
// draw shadow before anything else // draw shadow before anything else
if (shadow && (lineVisible || Colors.IsVisible(fillColor))) { if (shadow && (lineVisible || Colors.IsVisible(fillColor))) {
@ -62,7 +74,7 @@ namespace Greenshot.Drawing {
while (currentStep <= steps) { while (currentStep <= steps) {
using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) { using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) {
shadowPen.Width = lineVisible ? lineThickness : 1; 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); graphics.DrawEllipse(shadowPen, shadowRect);
currentStep++; currentStep++;
alpha = alpha - basealpha / steps; alpha = alpha - basealpha / steps;
@ -70,7 +82,6 @@ namespace Greenshot.Drawing {
} }
} }
//draw the original shape //draw the original shape
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
if (Colors.IsVisible(fillColor)) { if (Colors.IsVisible(fillColor)) {
using (Brush brush = new SolidBrush(fillColor)) { using (Brush brush = new SolidBrush(fillColor)) {
graphics.FillEllipse(brush, rect); graphics.FillEllipse(brush, rect);
@ -84,20 +95,35 @@ namespace Greenshot.Drawing {
} }
public override bool Contains(int x, int y) { public override bool Contains(int x, int y) {
double xDistanceFromCenter = x - (Left+Width/2); return EllipseContains(this, x, y);
double yDistanceFromCenter = y - (Top+Height/2); }
/// <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 // 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 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) { public override bool ClickableAt(int x, int y) {
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10;
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); 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 we clicked inside the rectangle and it's visible we are clickable at.
if (!Color.Transparent.Equals(fillColor)) { if (!Color.Transparent.Equals(fillColor)) {
if (Contains(x,y)) { if (rect.Contains(x, y)) {
return true; return true;
} }
} }

View file

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

View file

@ -42,12 +42,12 @@ namespace Greenshot.Drawing {
/// We set our own field values /// We set our own field values
/// </summary> /// </summary>
protected override void InitializeFields() { protected override void InitializeFields() {
AddField(GetType(), FieldType.LINE_THICKNESS, 4); AddField(GetType(), FieldType.LINE_THICKNESS, 0);
AddField(GetType(), FieldType.LINE_COLOR, Color.Blue); AddField(GetType(), FieldType.LINE_COLOR, Color.White);
AddField(GetType(), FieldType.SHADOW, true); AddField(GetType(), FieldType.SHADOW, false);
AddField(GetType(), FieldType.FONT_ITALIC, false); AddField(GetType(), FieldType.FONT_ITALIC, false);
AddField(GetType(), FieldType.FONT_BOLD, false); AddField(GetType(), FieldType.FONT_BOLD, true);
AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); AddField(GetType(), FieldType.FILL_COLOR, Color.LightBlue);
AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name); AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name);
AddField(GetType(), FieldType.FONT_SIZE, 20f); AddField(GetType(), FieldType.FONT_SIZE, 20f);
AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, HorizontalAlignment.Center); AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, HorizontalAlignment.Center);
@ -58,6 +58,7 @@ namespace Greenshot.Drawing {
base.TargetGripperMove(absX, absY); base.TargetGripperMove(absX, absY);
Invalidate(); Invalidate();
} }
/// <summary> /// <summary>
/// Called from Surface (the _parent) when the drawing begins (mouse-down) /// Called from Surface (the _parent) when the drawing begins (mouse-down)
/// </summary> /// </summary>
@ -156,15 +157,15 @@ namespace Greenshot.Drawing {
graphics.Restore(state); graphics.Restore(state);
} }
// Draw the text // cleanup the paths
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
DrawText(graphics, GuiRectangle.GetGuiRectangle(Left, Top, Width, Height), format);
// cleanup
bubble.Dispose(); bubble.Dispose();
tail.Dispose(); tail.Dispose();
// Draw the text
UpdateFormat();
DrawText(graphics, rect, lineThickness, lineColor, false, StringFormat, Text, Font);
} }
public override bool Contains(int x, int y) { 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. /// 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. /// To make sure that deleting recalculates, we check the location before every draw.
/// </summary> /// </summary>
[Serializable()] [Serializable]
public class StepLabelContainer : TextContainer { public class StepLabelContainer : DrawableContainer {
[NonSerialized]
private StringFormat _stringFormat = new StringFormat();
[NonSerialized]
private Font _font;
private bool drawAsRectangle = false;
public StepLabelContainer(Surface parent) : base(parent) { public StepLabelContainer(Surface parent) : base(parent) {
_defaultEditMode = EditStatus.IDLE;
parent.StepContainers.AddLast(this); parent.StepContainers.AddLast(this);
InitContent();
}
public override bool InitContent() {
_defaultEditMode = EditStatus.IDLE;
_stringFormat.Alignment = StringAlignment.Center;
_stringFormat.LineAlignment = StringAlignment.Center;
// Set defaults // Set defaults
Width = 40; Width = 40;
Height = 40; Height = 40;
} using (FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name)) {
_font = new Font(fam, 18, FontStyle.Regular, GraphicsUnit.Pixel);
public override void Dispose() { }
Parent.StepContainers.Remove(this); return true;
base.Dispose();
} }
/// <summary> /// <summary>
/// We set our own field values /// We set our own field values
/// </summary> /// </summary>
protected override void InitializeFields() { protected override void InitializeFields() {
AddField(GetType(), FieldType.LINE_COLOR, Color.White);
AddField(GetType(), FieldType.FILL_COLOR, Color.DarkRed); AddField(GetType(), FieldType.FILL_COLOR, Color.DarkRed);
AddField(GetType(), FieldType.FONT_SIZE, 21f); AddField(GetType(), FieldType.LINE_COLOR, Color.White);
AddField(GetType(), FieldType.LINE_THICKNESS, 0);
base.InitializeFields();
} }
/// <summary>
/// Make sure this element is no longer referenced from the surface
/// </summary>
public override void Dispose() {
Parent.StepContainers.Remove(this);
base.Dispose();
}
/// <summary> /// <summary>
/// Override the parent, calculate the label number, than draw /// Override the parent, calculate the label number, than draw
/// </summary> /// </summary>
@ -74,8 +92,26 @@ namespace Greenshot.Drawing {
number++; number++;
} }
} }
this.Text = number.ToString(); string text = number.ToString();
base.Draw(graphics, rm); 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 // 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 bool makeUndoable;
private Font _font; private Font _font;
public Font Font {
get {
return _font;
}
}
/// <summary> /// <summary>
/// The StringFormat object is not serializable!! /// The StringFormat object is not serializable!!
/// </summary> /// </summary>
[NonSerialized] [NonSerialized]
StringFormat stringFormat = new StringFormat(); StringFormat _stringFormat = new StringFormat();
public StringFormat StringFormat {
get {
return _stringFormat;
}
}
private string _text; private string _text;
// there is a binding on the following property! // there is a binding on the following property!
public string Text { public string Text {
@ -75,8 +83,8 @@ namespace Greenshot.Drawing {
public TextContainer(Surface parent) : base(parent) { public TextContainer(Surface parent) : base(parent) {
Init(); Init();
stringFormat = new StringFormat(); _stringFormat = new StringFormat();
stringFormat.Trimming = StringTrimming.EllipsisWord; _stringFormat.Trimming = StringTrimming.EllipsisWord;
} }
protected override void InitializeFields() { protected override void InitializeFields() {
@ -94,7 +102,7 @@ namespace Greenshot.Drawing {
[OnDeserialized] [OnDeserialized]
private void OnDeserialized(StreamingContext context) { private void OnDeserialized(StreamingContext context) {
stringFormat = new StringFormat(); _stringFormat = new StringFormat();
Init(); Init();
UpdateFormat(); UpdateFormat();
} }
@ -105,9 +113,9 @@ namespace Greenshot.Drawing {
_font.Dispose(); _font.Dispose();
_font = null; _font = null;
} }
if (stringFormat != null) { if (_stringFormat != null) {
stringFormat.Dispose(); _stringFormat.Dispose();
stringFormat = null; _stringFormat = null;
} }
if (textBox != null) { if (textBox != null) {
textBox.Dispose(); textBox.Dispose();
@ -205,7 +213,7 @@ namespace Greenshot.Drawing {
_parent.Controls.Remove(textBox); _parent.Controls.Remove(textBox);
} }
private void UpdateFormat() { protected void UpdateFormat() {
string fontFamily = GetFieldValueAsString(FieldType.FONT_FAMILY); string fontFamily = GetFieldValueAsString(FieldType.FONT_FAMILY);
bool fontBold = GetFieldValueAsBool(FieldType.FONT_BOLD); bool fontBold = GetFieldValueAsBool(FieldType.FONT_BOLD);
bool fontItalic = GetFieldValueAsBool(FieldType.FONT_ITALIC); bool fontItalic = GetFieldValueAsBool(FieldType.FONT_ITALIC);
@ -252,8 +260,8 @@ namespace Greenshot.Drawing {
throw; throw;
} }
stringFormat.Alignment = (StringAlignment)GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); _stringFormat.Alignment = (StringAlignment)GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT);
stringFormat.LineAlignment = (StringAlignment)GetFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT); _stringFormat.LineAlignment = (StringAlignment)GetFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT);
} }
private void UpdateTextBoxPosition() { private void UpdateTextBoxPosition() {
@ -311,47 +319,53 @@ namespace Greenshot.Drawing {
bool shadow = GetFieldValueAsBool(FieldType.SHADOW); bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); 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 // draw shadow before anything else
if (shadow && (fillColor == Color.Transparent || fillColor == Color.Empty)) { if (drawShadow) {
int basealpha = 100; int basealpha = 100;
int alpha = basealpha; int alpha = basealpha;
int steps = 5; int steps = 5;
int currentStep = 1; int currentStep = 1;
while (currentStep <= steps) { while (currentStep <= steps) {
int offset = currentStep; 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) { if (lineThickness > 0) {
shadowRect.Inflate(-textOffset, -textOffset); 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); graphics.DrawString(text, font, fontBrush, shadowRect, stringFormat);
currentStep++; currentStep++;
alpha = alpha - basealpha / steps; 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) { if (lineThickness > 0) {
graphics.SmoothingMode = SmoothingMode.HighSpeed; drawingRectange.Inflate(-textOffset, -textOffset);
fontRect.Inflate(-textOffset, -textOffset);
} }
graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.SmoothingMode = SmoothingMode.HighQuality;
using (Brush fontBrush = new SolidBrush(lineColor)) { using (Brush fontBrush = new SolidBrush(fontColor)) {
graphics.DrawString(_text, _font, fontBrush, fontRect);
if (stringFormat != null) { if (stringFormat != null) {
graphics.DrawString(_text, _font, fontBrush, fontRect, stringFormat); graphics.DrawString(text, font, fontBrush, drawingRectange, stringFormat);
} else { } else {
graphics.DrawString(_text, _font, fontBrush, fontRect); graphics.DrawString(text, font, fontBrush, drawingRectange);
} }
} }
} }