/// /// Copyright © 2003-2008 JetBrains s.r.o. /// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder). /// using System; using System.Collections; using System.Drawing; using System.Drawing.Drawing2D; using System.Globalization; using System.IO; using System.Reflection; using System.Windows.Forms; using System.Xml; using JetBrains.Omea.Base; namespace JetBrains.Omea.GUIControls { /// /// A container for a set of colors which can be loaded from an XML file, /// which also provides pen and brush caching. /// public class ColorScheme { private abstract class SchemeElement: IDisposable { protected Brush _brush; protected Pen _pen; public abstract Color GetColor(); public virtual Color GetStartColor() { return GetColor(); } public virtual Color GetEndColor() { return GetColor(); } public abstract Brush GetBrush( Rectangle rc ); public abstract Pen GetPen(); public virtual void Dispose() { if ( _brush != null ) { _brush.Dispose(); _brush = null; } if ( _pen != null ) { _pen.Dispose(); _pen = null; } } } private class SolidColorElement: SchemeElement { private Color _color; public SolidColorElement( Color color ) { _color = color; } public override Color GetColor() { return _color; } public override Brush GetBrush( Rectangle rc ) { if ( _brush == null ) { _brush = new SolidBrush( _color ); } return _brush; } public override Pen GetPen() { if ( _pen == null ) { _pen = new Pen( _color ); } return _pen; } } private class GradientElement: SchemeElement { private Color _startColor; private Color _endColor; private LinearGradientMode _mode; private float[] _blendPositions; private float[] _blendFactors; private Rectangle _brushRect; public GradientElement( Color startColor, Color endColor, LinearGradientMode mode, float[] blendPositions, float[] blendFactors ) { _startColor = startColor; _endColor = endColor; _mode = mode; _blendPositions = blendPositions; _blendFactors = blendFactors; } public override Color GetColor() { return _startColor; } public override Color GetStartColor() { return _startColor; } public override Color GetEndColor() { return _endColor; } public override Brush GetBrush( Rectangle rc ) { if ( _brush != null ) { if ( _mode == LinearGradientMode.Vertical && rc.Top == _brushRect.Top && rc.Bottom == _brushRect.Bottom ) { return _brush; } if ( _mode == LinearGradientMode.Horizontal && rc.Left == _brushRect.Left && rc.Right == _brushRect.Right ) { return _brush; } _brush.Dispose(); } if ( rc.Width == 0 || rc.Height == 0 ) { _brush = new SolidBrush( _startColor ); } else { _brush = new LinearGradientBrush( rc, _startColor, _endColor, _mode ); if ( _blendPositions != null ) { Blend blend = new Blend(); blend.Positions = _blendPositions; blend.Factors = _blendFactors; (_brush as LinearGradientBrush).Blend = blend; } } _brushRect = rc; return _brush; } public override Pen GetPen() { if ( _pen == null ) { _pen = new Pen( _startColor ); } return _pen; } } private Assembly _resourceAssembly; private string _iconPrefix; private ColorDepth _colorDepth; private Hashtable _schemeElements = new Hashtable(); // string -> SchemeElement public ColorScheme( Assembly resourceAssembly, string iconPrefix, ColorDepth colorDepth ) { _resourceAssembly = resourceAssembly; _iconPrefix = iconPrefix; _colorDepth = colorDepth; } public void Load( Stream stream ) { XmlDocument doc = new XmlDocument(); doc.Load( stream ); Load( doc ); } public void Load( XmlDocument doc ) { XmlNode rootNode = doc.SelectSingleNode( "/colorscheme" ); if ( rootNode == null ) throw new Exception( "Omea color scheme not found in file" ); foreach( XmlNode node in rootNode.ChildNodes ) { LoadSchemeNode( node, "" ); } } private void LoadSchemeNode( XmlNode node, string prefix ) { string nodeName = prefix + node.Name; foreach( XmlNode childNode in node.ChildNodes ) { if ( childNode.Name == "color" ) { LoadColorNode( nodeName, childNode ); } else if ( childNode.Name == "gradient" ) { LoadGradientNode( nodeName, childNode ); } else if ( childNode.Name == "imagelist" ) { LoadImageListNode( nodeName, childNode ); } else { LoadSchemeNode( childNode, nodeName + "." ); } } } private void LoadColorNode( string key, XmlNode node ) { _schemeElements [key] = new SolidColorElement( LoadColorFromNode( node ) ); } private Color LoadColorFromNode( XmlNode node ) { XmlAttribute attrRef = node.Attributes ["ref"]; if ( attrRef != null ) { string xpath = attrRef.Value; XmlNode refNode = node.OwnerDocument.SelectSingleNode( xpath ); if ( refNode == null ) { throw new Exception( "Invalid node reference " + xpath ); } return LoadColorFromNode( refNode ); } Color baseColor; XmlAttribute attrName = node.Attributes ["name"]; if ( attrName != null ) { baseColor = Color.FromName( attrName.Value ); } else { int r = XmlTools.GetRequiredIntAttribute( node, "r" ); int g = XmlTools.GetRequiredIntAttribute( node, "g" ); int b = XmlTools.GetRequiredIntAttribute( node, "b" ); baseColor = Color.FromArgb( r, g, b ); } XmlAttribute attrMult = node.Attributes ["mult"]; if ( attrMult != null ) { float mult = (float) Double.Parse( attrMult.Value, CultureInfo.InvariantCulture ); return GdiPlusTools.GetColorMult( baseColor, mult ); } return baseColor; } private void LoadGradientNode( string key, XmlNode node ) { LinearGradientMode mode; XmlAttribute attrMode = node.Attributes ["mode"]; switch( attrMode.Value ) { case "vertical": mode = LinearGradientMode.Vertical; break; case "horizontal": mode = LinearGradientMode.Horizontal; break; case "forward-diagonal": mode = LinearGradientMode.ForwardDiagonal; break; case "backward-diagonal": mode = LinearGradientMode.BackwardDiagonal; break; default: throw new Exception( "Invalid or unspecified mode" ); } XmlNode gradStartNode = node.SelectSingleNode( "startcolor" ); if ( gradStartNode == null ) throw new Exception( "Gradient not specified" ); Color startColor = LoadColorFromNode( gradStartNode ); XmlNode gradEndNode = node.SelectSingleNode( "endcolor" ); if ( gradEndNode == null ) throw new Exception( "Gradient not specified" ); Color endColor = LoadColorFromNode( gradEndNode ); float[] blendPositions = null; float[] blendFactors = null; XmlNodeList blendNodes = node.SelectNodes( "blend" ); if( blendNodes.Count > 0 ) { blendPositions = new float [blendNodes.Count+2]; blendFactors = new float [blendNodes.Count+2]; blendPositions [0] = 0.0f; blendFactors [0] = 0.0f; blendPositions [blendNodes.Count+1] = 1.0f; blendFactors [blendNodes.Count+1] = 1.0f; for( int i=0; i position not specified" ); XmlAttribute attrFactor = blendNode.Attributes ["factor"]; if ( attrFactor == null ) throw new Exception( " factor not specified" ); blendPositions [i+1] = (float) Double.Parse( attrPosition.Value, CultureInfo.InvariantCulture ); blendFactors [i+1] = (float) Double.Parse( attrFactor.Value, CultureInfo.InvariantCulture ); } } _schemeElements [key] = new GradientElement( startColor, endColor, mode, blendPositions, blendFactors ); } private void LoadImageListNode( string key, XmlNode node ) { ImageList imageList = new ImageList(); imageList.ImageSize = new Size( XmlTools.GetRequiredIntAttribute( node, "width" ), XmlTools.GetRequiredIntAttribute( node, "height" ) ); imageList.ColorDepth = _colorDepth; foreach( XmlNode childNode in node.ChildNodes ) { if ( childNode.Name == "icon" ) { string name = XmlTools.GetRequiredAttribute( childNode, "name" ); Stream stream = _resourceAssembly.GetManifestResourceStream( _iconPrefix + name ); if ( stream == null ) { throw new Exception( "Invalid icon name " + name ); } imageList.Images.Add( new Icon( stream ) ); } } _schemeElements [key] = imageList; } public Color GetColor( string elementId ) { return GetSchemeElement( elementId ).GetColor(); } public Color GetStartColor( string elementId ) { return GetSchemeElement( elementId ).GetStartColor(); } public Color GetEndColor( string elementId ) { return GetSchemeElement( elementId ).GetEndColor(); } public Brush GetBrush( string elementId, Rectangle rc ) { return GetSchemeElement( elementId ).GetBrush( rc ); } public Pen GetPen( string elementId ) { return GetSchemeElement( elementId ).GetPen(); } public ImageList GetImageList( string elementId ) { return (ImageList) _schemeElements [elementId]; } private SchemeElement GetSchemeElement( string elementId ) { object anElement = _schemeElements [elementId]; if ( anElement == null ) { throw new ArgumentException( "Element " + elementId + " not found in scheme", "elementId" ); } if ( !(anElement is SchemeElement ) ) { throw new ArgumentException( "Element " + elementId + " is not a color element", "elementId" ); } return (SchemeElement) anElement; } public static Color GetColor( ColorScheme scheme, string elementId, Color defaultColor ) { if( scheme != null ) { return scheme.GetColor( elementId ); } return defaultColor; } public static Color GetStartColor( ColorScheme scheme, string elementId, Color defaultColor ) { if( scheme != null ) { return scheme.GetStartColor( elementId ); } return defaultColor; } public static Color GetEndColor( ColorScheme scheme, string elementId, Color defaultColor ) { if( scheme != null ) { return scheme.GetEndColor( elementId ); } return defaultColor; } public static Brush GetBrush( ColorScheme scheme, string elementId, Rectangle rc, Brush defaultBrush ) { if ( scheme != null ) { return scheme.GetBrush( elementId, rc ); } return defaultBrush; } public static Pen GetPen( ColorScheme scheme, string elementId, Pen defaultPen ) { if ( scheme != null ) { return scheme.GetPen( elementId ); } return defaultPen; } public static void DrawRectangle( Graphics g, ColorScheme scheme, string elementId, Rectangle rc, Pen defaultPen ) { g.DrawRectangle( GetPen( scheme, elementId, defaultPen ), rc ); } public static void FillRectangle( Graphics g, ColorScheme scheme, string elementId, Rectangle rc, Brush defaultBrush ) { g.FillRectangle( GetBrush( scheme, elementId, rc, defaultBrush ), rc ); } } public interface IColorSchemeable { ColorScheme ColorScheme { get; set; } } }