File: commonui\System\Drawing\Advanced\CustomLineCap.cs
Project: ndp\fx\src\System.Drawing.csproj (System.Drawing)
//------------------------------------------------------------------------------
// <copyright file="CustomLineCap.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Drawing.Drawing2D {
 
    using Microsoft.Win32;
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing;
    using System.Drawing.Internal;
    using System.Runtime.InteropServices;
    using System.Globalization;
    using System.Runtime.Versioning;
 
    /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap"]/*' />
    /// <devdoc>
    ///    Encapsulates a custom user-defined line
    ///    cap.
    /// </devdoc>
    public class CustomLineCap : MarshalByRefObject, ICloneable, IDisposable {
 
#if FINALIZATION_WATCH
        private string allocationSite = Graphics.GetAllocationStack();
#endif
 
 
        /*
         * Handle to native line cap object
         */
        internal SafeCustomLineCapHandle nativeCap = null;
 
        private bool disposed = false;
 
        // For subclass creation
        internal CustomLineCap() {}
        
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.CustomLineCap"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Drawing.Drawing2D.CustomLineCap'/> class with the specified outline
        ///       and fill.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public CustomLineCap(GraphicsPath fillPath,
                             GraphicsPath strokePath) :
            this(fillPath, strokePath, LineCap.Flat) {}
            
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.CustomLineCap1"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Drawing.Drawing2D.CustomLineCap'/> class from the
        ///       specified existing <see cref='System.Drawing.Drawing2D.LineCap'/> with the specified outline and
        ///       fill.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public CustomLineCap(GraphicsPath fillPath,
                             GraphicsPath strokePath,
                             LineCap baseCap) :
            this(fillPath, strokePath, baseCap, 0) {}
            
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.CustomLineCap2"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Drawing.Drawing2D.CustomLineCap'/> class from the
        ///       specified existing <see cref='System.Drawing.Drawing2D.LineCap'/> with the specified outline, fill, and
        ///       inset.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public CustomLineCap(GraphicsPath fillPath,
                             GraphicsPath strokePath,
                             LineCap baseCap,
                             float baseInset)
        {
            IntPtr nativeLineCap = IntPtr.Zero;
            
            int status = SafeNativeMethods.Gdip.GdipCreateCustomLineCap(
                                new HandleRef(fillPath, (fillPath == null) ? IntPtr.Zero : fillPath.nativePath),
                                new HandleRef(strokePath, (strokePath == null) ? IntPtr.Zero : strokePath.nativePath),
                                baseCap, baseInset, out nativeLineCap);    
                                
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            SetNativeLineCap(nativeLineCap);
        }
 
        internal CustomLineCap(IntPtr nativeLineCap)
        {
            SetNativeLineCap(nativeLineCap);
        }
        
        internal void SetNativeLineCap(IntPtr handle) {
            if (handle == IntPtr.Zero)
                throw new ArgumentNullException("handle");
 
            nativeCap = new SafeCustomLineCapHandle(handle);
        }
 
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.Dispose"]/*' />
        /// <devdoc>
        ///    Cleans up Windows resources for this
        /// <see cref='System.Drawing.Drawing2D.CustomLineCap'/>.
        /// </devdoc>
        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.Dispose2"]/*' />
        protected virtual void Dispose(bool disposing) {
            if (disposed)
                return;
 
#if FINALIZATION_WATCH
            if (!disposing && nativeCap != null)
                Debug.WriteLine("**********************\nDisposed through finalization:\n" + allocationSite);
#endif
            // propagate the explicit dispose call to the child
            if (disposing && nativeCap != null) {
                nativeCap.Dispose();
            }
 
            disposed = true;
        }
 
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.Finalize"]/*' />
        /// <devdoc>
        ///    Cleans up Windows resources for this
        /// <see cref='System.Drawing.Drawing2D.CustomLineCap'/>.
        /// </devdoc>
        ~CustomLineCap() {
            Dispose(false);
        }
 
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.Clone"]/*' />
        /// <devdoc>
        ///    Creates an exact copy of this <see cref='System.Drawing.Drawing2D.CustomLineCap'/>.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public object Clone()
        {
            IntPtr cloneCap = IntPtr.Zero;
 
            int status = SafeNativeMethods.Gdip.GdipCloneCustomLineCap(new HandleRef(this, nativeCap), out cloneCap);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
            
            return CustomLineCap.CreateCustomLineCapObject(cloneCap);
       }
       
       internal static CustomLineCap CreateCustomLineCapObject(IntPtr cap)
       {     
            CustomLineCapType capType = 0;
            
            int status = SafeNativeMethods.Gdip.GdipGetCustomLineCapType(new HandleRef(null, cap), out capType);
            
            if (status != SafeNativeMethods.Gdip.Ok)
            {
                SafeNativeMethods.Gdip.GdipDeleteCustomLineCap(new HandleRef(null, cap));
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
            
            switch (capType)
            {
            case CustomLineCapType.Default:
                return new CustomLineCap(cap);
                
            case CustomLineCapType.AdjustableArrowCap:
                return new AdjustableArrowCap(cap);
            }
            
            SafeNativeMethods.Gdip.GdipDeleteCustomLineCap(new HandleRef(null, cap));
            throw SafeNativeMethods.Gdip.StatusException(SafeNativeMethods.Gdip.NotImplemented);
        }
 
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.SetStrokeCaps"]/*' />
        /// <devdoc>
        ///    Sets the caps used to start and end lines.
        /// </devdoc>
        public void SetStrokeCaps(LineCap startCap, LineCap endCap)
        {
            int status = SafeNativeMethods.Gdip.GdipSetCustomLineCapStrokeCaps(new HandleRef(this, nativeCap), startCap, endCap);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
        }
 
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.GetStrokeCaps"]/*' />
        /// <devdoc>
        ///    Gets the caps used to start and end lines.
        /// </devdoc>
        public void GetStrokeCaps(out LineCap startCap, out LineCap endCap) 
        {
            int status = SafeNativeMethods.Gdip.GdipGetCustomLineCapStrokeCaps(new HandleRef(this, nativeCap), out startCap, out endCap);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
        }
 
        private void _SetStrokeJoin(LineJoin lineJoin)
        {
            int status = SafeNativeMethods.Gdip.GdipSetCustomLineCapStrokeJoin(new HandleRef(this, nativeCap), lineJoin);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
        }
                                         
        private LineJoin _GetStrokeJoin()
        {
            LineJoin lineJoin;
 
            int status = SafeNativeMethods.Gdip.GdipGetCustomLineCapStrokeJoin(new HandleRef(this, nativeCap), out lineJoin);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return lineJoin;
        }
 
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.StrokeJoin"]/*' />
        /// <devdoc>
        ///    Gets or sets the <see cref='System.Drawing.Drawing2D.LineJoin'/> used by this custom cap.
        /// </devdoc>
        public LineJoin StrokeJoin
        {
            get { return _GetStrokeJoin(); }
            set { _SetStrokeJoin(value); }
        }
        
        private void _SetBaseCap(LineCap baseCap)
        {
            int status = SafeNativeMethods.Gdip.GdipSetCustomLineCapBaseCap(new HandleRef(this, nativeCap), baseCap);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
        }
 
        private LineCap _GetBaseCap()
        {
            LineCap baseCap;
            int status = SafeNativeMethods.Gdip.GdipGetCustomLineCapBaseCap(new HandleRef(this, nativeCap), out baseCap);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return baseCap;
        }
 
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.BaseCap"]/*' />
        /// <devdoc>
        ///    Gets or sets the <see cref='System.Drawing.Drawing2D.LineCap'/> on which this <see cref='System.Drawing.Drawing2D.CustomLineCap'/> is based.
        /// </devdoc>
        public LineCap BaseCap
        {
            get { return _GetBaseCap(); }
            set { _SetBaseCap(value); }
        }
 
        private void _SetBaseInset(float inset)
        {
            int status = SafeNativeMethods.Gdip.GdipSetCustomLineCapBaseInset(new HandleRef(this, nativeCap), inset);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
        }
 
        private float _GetBaseInset()
        {
            float inset;
            int status = SafeNativeMethods.Gdip.GdipGetCustomLineCapBaseInset(new HandleRef(this, nativeCap), out inset);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return inset;
        }
 
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.BaseInset"]/*' />
        /// <devdoc>
        ///    Gets or sets the distance between the cap
        ///    and the line.
        /// </devdoc>
        public float BaseInset
        {
            get { return _GetBaseInset(); }
            set { _SetBaseInset(value); }
        }
        
        private void _SetWidthScale(float widthScale)
        {
            int status = SafeNativeMethods.Gdip.GdipSetCustomLineCapWidthScale(new HandleRef(this, nativeCap), widthScale);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
        }
 
        private float _GetWidthScale()
        {
            float widthScale;
            int status = SafeNativeMethods.Gdip.GdipGetCustomLineCapWidthScale(new HandleRef(this, nativeCap), out widthScale);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return widthScale;
        }
        
        /// <include file='doc\CustomLineCap.uex' path='docs/doc[@for="CustomLineCap.WidthScale"]/*' />
        /// <devdoc>
        ///    Gets or sets the amount by which to scale
        ///    the width of the cap.
        /// </devdoc>
        public float WidthScale
        {
            get { return _GetWidthScale(); }
            set { _SetWidthScale(value); }
        }
    }
}