Click here to Skip to main content
15,885,782 members
Articles / Programming Languages / C#

User-driven applications

Rate me:
Please Sign up or sign in to vote.
4.88/5 (24 votes)
10 Apr 2010CPOL136 min read 33K   5   78  
User-driven applications are the programs in which full control is given to the users. Designers of such programs are responsible only for developing an instrument for solving some task, but they do not enforce users to work with this instrument according with a predefined scenario.
using System;
using System .Collections .Generic;
using System .ComponentModel;
using System .Drawing;
using System .Drawing .Drawing2D;
using System .Windows .Forms;
using System .IO;
using Microsoft .Win32;

using MoveGraphLibrary;

namespace UserDrivenApplications
{
    public class PrimitiveRing : GraphicalObject
    {
        int version = 606;
        PointF center;
        float rOuter;
        float rInner;

        double [] vals;
        List<Color> clrs = new List<Color> ();          // one color per each sector
        Rotation dirDrawing;
        double angle;
        double [] sweep;

        double compensation;
        bool bResize, bRotate;
        Color clrBorder;

        int nNodesOnOuter;
        int nNodesOnInner;

        // all these are used only for moving the border between two sectors
        int iBorderToMove;
        int iSector_Counterclock, iSector_Clockwise;
        double min_angle_Resectoring,       // clockwise from the moving border
               max_angle_Resectoring;       // counterclock from the moving border
        double two_sectors_sum_values;

        static int minInner = 10;
        static int minWidth = 15;
        int hSmall = 4;                 // this is half !!!     so the same hSmall is going inside and outside
        int distanceNeighbours = 10;

        // -------------------------------------------------
        public PrimitiveRing (PointF ptC, float rOut, float rIn, double angleDegree, double [] fVals)
        {
            bResize = true;
            bRotate = true;

            center = ptC;
            rInner = Math .Max (rIn, minInner);
            rOuter = Math .Max (rOut, rIn + minWidth);
            vals = CheckedValues (fVals);
            DefaultColors ();

            clrBorder = Color .DarkGray;

            dirDrawing = Rotation .Clockwise;
            angle = Auxi_Convert .DegreeToRadian (angleDegree);
            sweep = new double [vals .Length];
            SweepAngles ();
            NodesOnBorders ();
        }
        // -------------------------------------------------
        public PrimitiveRing (PointF ptC, float rOut, float rIn, Color clr)
            : this (ptC, rOut, rIn, 0, new double [] { 5 })
        {
            clrs [0] = clr;
        }
        // -------------------------------------------------
        public override sealed bool ShowCover
        {
            get { return (false); }
        }
        // -------------------------------------------------        NodesOnBorders
        private void NodesOnBorders ()
        {
            if (bResize)
            {
                nNodesOnOuter = Convert .ToInt32 ((2 * Math .PI * rOuter) / distanceNeighbours);
                nNodesOnInner = Convert .ToInt32 ((2 * Math .PI * rInner) / distanceNeighbours);
            }
            else
            {
                nNodesOnOuter = 0;
                nNodesOnInner = 0;
            }
        }
        // -------------------------------------------------        CheckedValues
        private double [] CheckedValues (double [] fVals)
        {
            if (fVals == null || fVals .Length < 1 || Auxi_Common .SumArray (fVals, true) == 0.0)
            {
                return (new double [] { 1, 2, 3, 4 });
            }
            else
            {
                double [] vs = new double [fVals .Length];
                for (int i = 0; i < vs .Length; i++)
                {
                    vs [i] = Math .Abs (fVals [i]);
                }
                return (vs);
            }
        }
        // -------------------------------------------------        DefaultColors
        public void DefaultColors ()
        {
            clrs .Clear ();
            for (int i = 0; i < vals .Length; i++)
            {
                clrs .Add (Auxi_Colours .ColorPredefined (i + 1));
            }
        }
        // -------------------------------------------------        SmoothColorLine
        public void SmoothColorLine (Color clr_0, Color clr_1)
        {
            clrs = Auxi_Colours .SmoothColorsList (vals .Length, clr_0, clr_1);
        }
        // -------------------------------------------------        SweepAngles
        private void SweepAngles ()
        {
            double fSum = Auxi_Common .SumArray (vals, false);
            for (int i = 0; i < vals .Length; i++)
            {
                sweep [i] = 2 * Math .PI * vals [i] / fSum;
            }
            if (dirDrawing == Rotation .Clockwise)
            {
                for (int i = 0; i < vals .Length; i++)
                {
                    sweep [i] *= -1;
                }
            }
        }
        // -------------------------------------------------        SectorFromPointAngle
        public int SectorFromPointAngle (Point pt)
        {
            double angleToPoint = Auxi_Geometry .Line_Angle (center, pt);
            int iSector = 0;

            double [] angleBorder = new double [sweep .Length + 1];
            if (dirDrawing == Rotation .Counterclock)
            {
                if (angle < 0)
                {
                    angleBorder [0] = angle + 2 * Math .PI;
                }
                else
                {
                    angleBorder [0] = angle;
                }
                for (int i = 0; i < sweep .Length; i++)
                {
                    angleBorder [i + 1] = angleBorder [i] + sweep [i];
                }
                while (angleToPoint < angleBorder [0])
                {
                    angleToPoint += 2 * Math .PI;
                }
                for (iSector = 0; iSector < sweep .Length; iSector++)
                {
                    if (angleToPoint < angleBorder [iSector + 1]) 
                    {
                        break;
                    }
                }
            }
            else
            {
                if (angle > 0)
                {
                    angleBorder [0] = angle - 2 * Math .PI;
                }
                else
                {
                    angleBorder [0] = angle;
                }
                for (int i = 0; i < sweep .Length; i++)
                {
                    angleBorder [i + 1] = angleBorder [i] + sweep [i];
                }
                while (angleToPoint > angleBorder [0])
                {
                    angleToPoint -= 2 * Math .PI;
                }
                for (iSector = 0; iSector < sweep .Length; iSector++)
                {
                    if (angleToPoint > angleBorder [iSector + 1]) 
                    {
                        break;
                    }
                }
            }
            iSector = Math .Min (iSector, vals .Length - 1);
            return (iSector);
        }
        // -------------------------------------------------        Center
        public PointF Center
        {
            get { return (center); }
        }
        // -------------------------------------------------        InnerRadius
        public float InnerRadius
        {
            get { return (rInner); }
        }
        // -------------------------------------------------        OuterRadius
        public float OuterRadius
        {
            get { return (rOuter); }
        }
        // -------------------------------------------------        MinimumInnerRadius
        static public int MinimumInnerRadius
        {
            get { return (minInner); }
        }
        // -------------------------------------------------        MinimumWidth
        static public int MinimumWidth
        {
            get { return (minWidth); }
        }
        // -------------------------------------------------        RectAround
        new public RectangleF RectAround
        {
            get { return (new RectangleF (center .X - rOuter, center .Y - rOuter, 2 * rOuter, 2 * rOuter)); }
        }
        // -------------------------------------------------        Angle
        public double Angle
        {
            get { return (angle); }
            set
            {
                angle = Auxi_Common .LimitedRadian (value);
                DefineCover ();
            }
        }
        // -------------------------------------------------        SetSectorColor
        public void SetSectorColor (int iSector, Color color)
        {
            if (0 <= iSector && iSector < clrs .Count)
            {
                clrs [iSector] = color;
            }
        }
        // -------------------------------------------------        DrawingDirection
        public Rotation DrawingDirection
        {
            get { return (dirDrawing); }
            set
            {
                dirDrawing = value;
                SweepAngles ();
            }
        }
        // -------------------------------------------------        ChangeDrawingDirection
        public void ChangeDrawingDirection ()
        {
            dirDrawing = (dirDrawing == Rotation .Clockwise) ? Rotation .Counterclock : Rotation .Clockwise;
            SweepAngles ();
        }
        // -------------------------------------------------        Values
        public double [] Values
        {
            get { return (vals); }
        }
        // -------------------------------------------------        Colors
        public List<Color> Colors
        {
            get { return (clrs); }
        }
        // -------------------------------------------------        Draw
        public void Draw (Graphics grfx)
        {
            Rectangle rcIn = new Rectangle (Convert .ToInt32 (center .X - rInner), Convert .ToInt32 (center .Y - rInner),
                                            Convert .ToInt32 (2 * rInner), Convert .ToInt32 (2 * rInner));
            Rectangle rcOut = new Rectangle (Convert .ToInt32 (center .X - rOuter), Convert .ToInt32 (center .Y - rOuter),
                                             Convert .ToInt32 (2 * rOuter), Convert .ToInt32 (2 * rOuter));
            Pen penBorder = new Pen (clrBorder);
            Point pt0, pt1;
            SolidBrush brush;
            GraphicsPath path = new GraphicsPath ();
            // for Drawing fStart[] and fSweep[] are used in Microsoft way, which means changing of sign
            float fStartDegree, fSweepDegree;
            fStartDegree = -(float) Auxi_Convert .RadianToDegree (angle);
            for (int i = 0; i < vals .Length; i++)
            {
                brush = new SolidBrush (clrs [i]);
                fSweepDegree = -(float) Auxi_Convert .RadianToDegree (sweep [i]);

                path .AddArc (rcIn, fStartDegree, fSweepDegree);
                path .AddArc (rcOut, fStartDegree + fSweepDegree, -fSweepDegree);
                grfx .FillPath (brush, path);
                path .Reset ();

                grfx .DrawArc (penBorder, rcIn, fStartDegree, fSweepDegree);
                grfx .DrawArc (penBorder, rcOut, fStartDegree, fSweepDegree);
                pt0 = Auxi_Geometry .EllipsePoint (rcIn, -fStartDegree, 1);
                pt1 = Auxi_Geometry .EllipsePoint (rcOut, -fStartDegree, 1);
                grfx .DrawLine (penBorder, pt0, pt1);

                fStartDegree += fSweepDegree;
            }
        }
        // -------------------------------------------------        StartRotation
        public void StartRotation (Point ptMouse)
        {
            double angleMouse = Auxi_Geometry .Line_Angle (center, ptMouse);
            compensation = Auxi_Common .LimitedRadian (angleMouse - angle);
        }
        // -------------------------------------------------        StartRotation
        public void SectorsUnderChange (out int iCounterClock, out int iClockwise)
        {
            iCounterClock = iSector_Counterclock;
            iClockwise = iSector_Clockwise;
        }
        // -------------------------------------------------        StartResectoring
        public void StartResectoring (int iNode)
        {
            iBorderToMove = iNode - (nNodesOnOuter + nNodesOnInner);
            double angleCaughtBorder = angle;
            for (int i = 0; i < iBorderToMove; i++)
            {
                angleCaughtBorder += sweep [i];
            }
            if (dirDrawing == Rotation .Clockwise)
            {
                iSector_Clockwise = iBorderToMove;
                min_angle_Resectoring = angleCaughtBorder + sweep [iSector_Clockwise];
                iSector_Counterclock = (iSector_Clockwise == 0) ? (vals .Length - 1) : (iSector_Clockwise - 1);
                max_angle_Resectoring = angleCaughtBorder - sweep [iSector_Counterclock];
            }
            else
            {
                iSector_Counterclock = iBorderToMove;
                max_angle_Resectoring = angleCaughtBorder + sweep [iSector_Counterclock];
                iSector_Clockwise = (iSector_Counterclock == 0) ? (vals .Length - 1) : (iSector_Counterclock - 1);
                min_angle_Resectoring = angleCaughtBorder - sweep [iSector_Clockwise];
            }
            two_sectors_sum_values = vals [iSector_Clockwise] + vals [iSector_Counterclock];
        }

        // -------------------------------------------------        RedefineCover
        public void RedefineCover ()
        {
            if (bResize)
            {
                NodesOnBorders ();
                DefineCover ();
            }
        }
        // -------------------------------------------------        DefineCover
        public override void DefineCover ()
        {
            PointF [] pts = new PointF [4];
            CoverNode [] nodes;  
            if (bResize)
            {
                // order of nodes:  outer border - inner border
                //                - strips on sectors' borders - inner circle (Transparent) - outer circle
                nodes = new CoverNode [nNodesOnOuter + nNodesOnInner + vals .Length + 2];
                float rBelow, rAbove;

                rBelow = rOuter - hSmall;
                rAbove = rOuter + hSmall;
                pts [0] = Auxi_Geometry .PointToPoint (center, 0, rBelow);
                pts [1] = Auxi_Geometry .PointToPoint (center, 0, rAbove);
                for (int i = 0; i < nNodesOnOuter; i++)                         // nodes on outer border
                {
                    pts [2] = Auxi_Geometry .PointToPoint (center, 2 * Math .PI * (i + 1) / nNodesOnOuter, rAbove);
                    pts [3] = Auxi_Geometry .PointToPoint (center, 2 * Math .PI * (i + 1) / nNodesOnOuter, rBelow);
                    nodes [i] = new CoverNode (i, pts, Cursors .Hand);
                    pts [0] = pts [3];
                    pts [1] = pts [2];
                }
                rBelow = rInner - hSmall;
                rAbove = rInner + hSmall;
                pts [0] = Auxi_Geometry .PointToPoint (center, 0, rBelow);
                pts [1] = Auxi_Geometry .PointToPoint (center, 0, rAbove);
                for (int i = 0; i < nNodesOnInner; i++)                         // nodes on inner border
                {
                    pts [2] = Auxi_Geometry .PointToPoint (center, 2 * Math .PI * (i + 1) / nNodesOnInner, rAbove);
                    pts [3] = Auxi_Geometry .PointToPoint (center, 2 * Math .PI * (i + 1) / nNodesOnInner, rBelow);
                    nodes [nNodesOnOuter + i] = new CoverNode (nNodesOnOuter + i, pts, Cursors .Hand);
                    pts [0] = pts [3];
                    pts [1] = pts [2];
                }
                int nSmallNodes = nNodesOnOuter + nNodesOnInner;
                PointF ptIn, ptOut;
                double angleForLine = angle;
                for (int i = 0; i < vals .Length; i++)                         // nodes on borders between sectors
                {
                    ptIn = Auxi_Geometry .PointToPoint (center, angleForLine, rInner);
                    ptOut = Auxi_Geometry .PointToPoint (center, angleForLine, rOuter);
                    nodes [nSmallNodes + i] = new CoverNode (nSmallNodes + i, ptIn, ptOut);
                    angleForLine += sweep [i];
                }
                int j = nodes .Length - 2;
                nodes [j] = new CoverNode (j, center, rInner, MovementFreedom .Transparent);
                nodes [j + 1] = new CoverNode (j + 1, center, rOuter, Cursors .SizeAll);
            }
            else
            {
                nodes = new CoverNode [2];
                nodes [0] = new CoverNode (0, center, rInner, MovementFreedom .Transparent);
                nodes [1] = new CoverNode (1, center, rOuter, Cursors .SizeAll);
            }
            cover = new Cover (nodes);
        }
        // -------------------------------------------------
        public override void Move (int dx, int dy)
        {
            center += new Size (dx, dy);
        }
        // -------------------------------------------------        MoveNode
        public override bool MoveNode (int i, int dx, int dy, Point ptM, MouseButtons catcher)
        {
            bool bRet = false;

            if (catcher == MouseButtons .Left)
            {
                if (bResize)
                {
                    if (i == cover .NodesCount - 1)
                    {
                        Move (dx, dy);
                    }
                    else if (i < nNodesOnOuter + nNodesOnInner)
                    {
                        // small node on either outer or inner border
                        if (i < nNodesOnOuter)
                        {
                            int newOuter = Convert .ToInt32 (Auxi_Geometry .Distance (center, ptM));
                            if (rInner + minWidth <= newOuter)
                            {
                                rOuter = newOuter;
                                bRet = true;
                            }
                        }
                        else
                        {
                            int newInner = Convert .ToInt32 (Auxi_Geometry .Distance (center, ptM));
                            if (minInner <= newInner && newInner <= rOuter - minWidth)
                            {
                                rInner = newInner;
                                bRet = true;
                            }
                        }
                    }
                    else
                    {
                        // border between two sectors
                        double angleMouse = Auxi_Geometry .Line_Angle (center, ptM);
                        if (angleMouse > max_angle_Resectoring)
                        {
                            angleMouse -= 2 * Math .PI;
                        }
                        else if (angleMouse < min_angle_Resectoring)
                        {
                            angleMouse += 2 * Math .PI;
                        }
                        if (min_angle_Resectoring + 0.05 < angleMouse && angleMouse < max_angle_Resectoring - 0.05)
                        {
                            double part_Counterclock = (max_angle_Resectoring - angleMouse) / (max_angle_Resectoring - min_angle_Resectoring);
                            if (iBorderToMove == 0)
                            {
                                angle = angleMouse;
                            }
                            vals [iSector_Counterclock] = two_sectors_sum_values * part_Counterclock;
                            vals [iSector_Clockwise] = two_sectors_sum_values - vals [iSector_Counterclock];
                            SweepAngles ();
                        }
                    }
                }
                else
                {
                    Move (dx, dy);
                }
            }
            else if (catcher == MouseButtons .Right && bRotate)
            {
                double angleMouse = Auxi_Geometry .Line_Angle (center, ptM);
                angle = angleMouse - compensation;
                bRet = true;
            }
            return (bRet);
        }

        const string nameMain = "PrimRing_";
        const string nameValues = "PrimRingValues_";
        const string nameColors = "PrimRingClrs_";
        // -------------------------------------------------        IntoRegistry
        public void IntoRegistry (RegistryKey regkey, string strB)
        {
            try
            {
                regkey .SetValue (nameMain + strB, new string [] {version .ToString (),             // 0
                                                                  id .ToString (),                  // 1
                                                                  center .X .ToString (),           // 2
                                                                  center .Y .ToString (),           // 3
                                                                  rOuter .ToString (),              // 4 
                                                                  rInner .ToString (),              // 5
                                                                  angle .ToString (),               // 6
                                                                  ((int) DrawingDirection) .ToString (),  // 7
                                                               },
                                                   RegistryValueKind .MultiString);
                string [] strVal = new string [vals .Length];
                for (int i = 0; i < vals .Length; i++)
                {
                    strVal [i] = vals [i] .ToString ();
                }
                regkey .SetValue (nameValues + strB, strVal, RegistryValueKind .MultiString);

                string [] strClrs = new string [clrs .Count * 4];
                for (int i = 0; i < clrs .Count; i++)
                {
                    strClrs [i * 4] = ((int) (clrs [i] .A)) .ToString ();
                    strClrs [i * 4 + 1] = ((int) (clrs [i] .R)) .ToString ();
                    strClrs [i * 4 + 2] = ((int) (clrs [i] .G)) .ToString ();
                    strClrs [i * 4 + 3] = ((int) (clrs [i] .B)) .ToString ();
                }
                regkey .SetValue (nameColors + strB, strClrs, RegistryValueKind .MultiString);
            }
            catch
            {
            }
            finally
            {
            }
        }
        // -------------------------------------------------        FromRegistry
        public static PrimitiveRing FromRegistry (RegistryKey regkey, string strB)
        {
            try
            {
                string [] strMain = (string []) regkey .GetValue (nameMain + strB);
                string [] strVal = (string []) regkey .GetValue (nameValues + strB);

                if (strMain == null ||
                    strMain .Length != 8 ||
                    Convert .ToInt32 (strMain [0]) != 606 ||
                    strVal == null ||
                    strVal .Length < 2)
                {
                    return (null);
                }
                //int nVer = Convert .ToInt32 (strGeneral [0]);

                double [] fVals = new double [strVal .Length];
                for (int i = 0; i < strVal .Length; i++)
                {
                    fVals [i] = Convert .ToDouble (strVal [i]);
                }
                PrimitiveRing ring = new PrimitiveRing (Auxi_Convert .ToPointF (strMain, 2), 
                                                        Convert .ToSingle (strMain [4]),
                                                        Convert .ToSingle (strMain [5]),
                                                        Auxi_Convert .RadianToDegree (Convert .ToDouble (strMain [6])), 
                                                        fVals);
                if (ring == null)
                {
                    return (null);
                }
                ring .ID = Convert .ToInt64 (strMain [1]);
                ring .DrawingDirection = (Rotation) (Convert .ToInt32 (strMain [7]));

                string [] strClrs = (string []) regkey .GetValue (nameColors + strB);
                if (fVals .Length == strClrs .Length / 4)
                {
                    for (int i = 0; i < fVals .Length; i++)
                    {
                        ring .SetSectorColor (i, Auxi_Convert .ToColor (strClrs, i * 4));
                    }
                }
                return (ring);
            }
            catch
            {
                return (null);
            }
            finally
            {
            }
        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions