/*============================================================================= Project: SharpImage Module: siTransferFunctionPartGradient.cs Language: C# Author: Dan Mueller Date: $Date: 2007-07-06 10:57:00 +1000 (Fri, 06 Jul 2007) $ Revision: $Revision: 2 $ Copyright (c) Queensland University of Technology (QUT) 2007. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =============================================================================*/ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Diagnostics; namespace SharpImage.Rendering { public class siTransferFunctionPartGradient : siTransferFunctionPartRectangle { #region Constants //===================================================================== protected static readonly Color DEFAULT_COLOR1 = Color.Red; protected static readonly Color DEFAULT_COLOR2 = Color.White; //===================================================================== #endregion #region Construction and Disposal //===================================================================== /// /// Default constructor. This part will be drawn on all layers. /// /// public siTransferFunctionPartGradient() : this(null, null) { } /// /// Constructor taking a layer key. /// /// Uses the parent.Image for creating a default sized part. /// The name of layer this part is to be drawn on. public siTransferFunctionPartGradient(siTransferFunction parent, string layer) : base(parent, layer) { } //===================================================================== #endregion #region Properties //===================================================================== #region BackColor //===================================================================== /// /// Get/set the RGB components of the back color. /// [System.ComponentModel.Browsable(false)] [System.ComponentModel.Category("Color")] [System.Xml.Serialization.XmlIgnore] public override Color BackColorRGB { get { return Color.FromArgb(base.BackColor.R, base.BackColor.G, base.BackColor.B); } set { base.BackColor = Color.FromArgb(base.BackColor.A, value); this.RaiseModified(); } } /// /// Get/set the Alpha component of the back color. /// [System.ComponentModel.Browsable(false)] [System.ComponentModel.Category("Color")] [System.Xml.Serialization.XmlIgnore] public override int BackColorAlpha { get { return base.BackColor.A; } set { base.BackColor = Color.FromArgb(value, base.BackColor); this.RaiseModified(); } } /// /// This property is needed for serialization. /// It is not intended for general use. /// [System.ComponentModel.Browsable(false)] [System.ComponentModel.Category("Color")] [System.Xml.Serialization.XmlIgnore] public override string SerializableBackColor { get { return siColorHelper.SerializeColor(base.BackColor); } set { base.BackColor = siColorHelper.DeserializeColor(value); this.RaiseModified(); } } //===================================================================== #endregion #region Colors //===================================================================== private int m_NumberOfColors = 3; private Color[] m_Colors = new Color[] { DEFAULT_COLOR1, DEFAULT_COLOR2, DEFAULT_COLOR2 }; private int[] m_Alphas = new int[] { 255, 255, 255 }; [System.ComponentModel.Browsable(true)] [System.ComponentModel.Category("Color")] public int NumberOfColors { get { return this.m_NumberOfColors; } set { if (value < 3) value = 3; this.m_NumberOfColors = value; // Save the old values Color[] oldColors = this.m_Colors; int[] oldAlphas = this.m_Alphas; // Create new empty values this.m_Colors = new Color[value]; this.m_Alphas = new int[value]; this.m_Positions = new float[value]; // Populate new values for (int i = 0; i < value; i++) { this.m_Colors[i] = (oldColors.Length > i) ? oldColors[i] : DEFAULT_COLOR2; this.m_Alphas[i] = (oldAlphas.Length > i) ? oldAlphas[i] : 255; this.m_Positions[i] = (float)i*(1.0f / (this.NumberOfColors - 1)); } // Enforce some positions values this.m_Positions[0] = 0.0f; this.m_Positions[value - 1] = 1.0f; if (value == 3) this.m_Positions[1] = 1.0f; // Raise modified this.RaiseModified(); } } /// /// The colours in the gradient. /// [System.ComponentModel.Browsable(true)] [System.ComponentModel.Category("Color")] [System.Xml.Serialization.XmlIgnore] public Color[] Colors { get { return this.m_Colors; } } /// /// This property is needed for serialization. /// It is not intended for general use. /// [System.ComponentModel.Browsable(false)] public String SerializableColors { get { String result = String.Empty; foreach (Color color in this.Colors) result += siColorHelper.SerializeColor(color) + "; "; return result.TrimEnd(';', ' '); } set { String[] split = value.Split(new char[] { ';' }); this.m_Colors = new Color[split.Length]; for (int i = 0; i < split.Length; i++) this.m_Colors[i] = siColorHelper.DeserializeColor(split[i]); } } /// /// The alpha values in the gradient. /// [System.ComponentModel.Browsable(true)] [System.ComponentModel.Category("Color")] [System.Xml.Serialization.XmlIgnore] public int[] Alphas { get { return m_Alphas; } } /// /// This property is needed for serialization. /// It is not intended for general use. /// [System.ComponentModel.Browsable(false)] public String SerializableAlphas { get { String result = String.Empty; foreach (int alpha in this.Alphas) result += alpha.ToString() + "; "; return result.TrimEnd(';', ' '); } set { String[] split = value.Split(new char[] { ';' }); this.m_Alphas = new int[split.Length]; for (int i = 0; i < split.Length; i++) this.m_Alphas[i] = Int32.Parse(split[i]); } } //===================================================================== #endregion #region Positions //===================================================================== private float[] m_Positions = new float[] { 0.0f, 1.0f, 1.0f }; /// /// The blend positions for the gradient. /// [System.ComponentModel.Browsable(false)] [System.ComponentModel.Category("Color")] [System.Xml.Serialization.XmlIgnore] public float[] Positions { get { return m_Positions; } } /// /// This property is needed for serialization. /// It is not intended for general use. /// [System.ComponentModel.Browsable(false)] public String SerializablePositions { get { String result = String.Empty; foreach (float position in this.Positions) result += position.ToString() + "; "; return result.TrimEnd(';', ' '); } set { String[] split = value.Split(new char[] { ';' }); this.m_Positions = new float[split.Length]; for (int i = 0; i < split.Length; i++) this.m_Positions[i] = Single.Parse(split[i]); } } //===================================================================== #endregion #region GradientMode //============================================================================ private LinearGradientMode m_GradientMode; /// /// Gets/sets the mode for drawing the gradient. /// [System.ComponentModel.Browsable(true)] [System.ComponentModel.Category("Color")] public LinearGradientMode GradientMode { get { return this.m_GradientMode; } set { this.m_GradientMode = value; this.RaiseModified(); } } //============================================================================ #endregion #region ControlPoints //===================================================================== /// /// Get the control points. This property accessor builds the list /// from private member information each time it is called. /// [System.ComponentModel.Browsable(false)] [System.Xml.Serialization.XmlIgnore] public override RectangleF[] ControlPoints { get { RectangleF[] result = new RectangleF[4 + (this.NumberOfColors - 2)]; RectangleF[] baseResult = base.ControlPoints; for (int i = 0; i< 4; i++) result[i] = baseResult[i]; for (int j=0; j < (this.NumberOfColors - 2); j++) result[4 + j] = new RectangleF(this.BoundingBoxX + this.Positions[j + 1] * this.BoundingBoxWidth - CONTROL_POINT_WIDTH / 2.0f, this.BoundingBoxY, CONTROL_POINT_WIDTH, this.BoundingBoxHeight); return result; } } //===================================================================== #endregion //===================================================================== #endregion #region Public Methods //===================================================================== public override string ToString() { return "Gradient: " + this.Layer + " " + this.BoundingBox.ToString(); } //===================================================================== #endregion #region Paint Methods //===================================================================== protected override void OnPaintControlPoints(siTransferFunction parent, siTransferFunctionPaintEventArgs e) { // Set smoothing mode to none SmoothingMode oldSmoothingMode = e.Graphics.SmoothingMode; e.Graphics.SmoothingMode = SmoothingMode.None; // Paint the gradient controls Pen penGradient = new Pen(Color.FromArgb(100, Color.Gray), 1.0f); RectangleF[] cpts = this.ControlPoints; const float HALF_WIDTH = CONTROL_POINT_WIDTH/2.0f; for (int i = 4; i < cpts.Length; i++) { e.Graphics.DrawLine(penGradient, cpts[i].X + HALF_WIDTH, cpts[i].Y, cpts[i].X + HALF_WIDTH, cpts[i].Y + cpts[i].Height); } // Paint the corners base.OnPaintControlPoints(parent, e); // Reset smoothing mode e.Graphics.SmoothingMode = oldSmoothingMode; } protected override void OnPaintFillFunction(siTransferFunction parent, siTransferFunctionPaintEventArgs e) { // Create the brush RectangleF rectangleFill = new RectangleF(this.BoundingBoxX-1, this.BoundingBoxY-1, this.BoundingBoxWidth+1, this.BoundingBoxHeight+1); LinearGradientBrush brushFill = new LinearGradientBrush(rectangleFill, Colors[0], Colors[1], this.GradientMode); // Set the color blend Color[] colors = new Color[this.NumberOfColors]; for (int i=0; i < this.NumberOfColors; i++) colors[i] = Color.FromArgb(this.Alphas[i], this.Colors[i]); ColorBlend colorblend = new ColorBlend(this.NumberOfColors); colorblend.Colors = colors; colorblend.Positions = this.Positions; brushFill.InterpolationColors = colorblend; // Fill the part e.Graphics.FillRectangle(brushFill, this.BoundingBox); } //===================================================================== #endregion #region Mouse Methods //===================================================================== /// /// Get the cursor for the given control point index. /// /// /// protected override Cursor GetControlPointCursor(int cpIndex) { if (cpIndex >= 4) return Cursors.SizeWE; else return base.GetControlPointCursor(cpIndex); } //===================================================================== #endregion #region Translate and Resize Methods //===================================================================== /// /// Resize the part by the given amount. /// /// public override void Resize(siTransferFunction parent, PointF change) { // Dispatch the resize for the rectangle int cindex = (int)this.Metadata["CurrentControlPointIndex"]; if (cindex < 4) { base.Resize(parent, change); } else { this.Positions[cindex - 3] += (change.X / this.BoundingBoxWidth); if (this.Positions[cindex - 3] < 0.0) this.Positions[cindex - 3] = -0.0001f; if (this.Positions[cindex - 3] > 1.0) this.Positions[cindex - 3] = 1.0f; this.RaiseModified(); } } //===================================================================== #endregion } }