using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
using CSRegisterHotkey;
using Ck_Objects;
using FileDialog_GUI;
using _ToolTip;
using Math3;

namespace GridMethod
{
    public partial class formGridMethod : Form
    {
        static public BinaryFormatter formatter = new BinaryFormatter();
        PictureBox picAbout = new PictureBox();
        groupBox grbControls = new groupBox();
        classLabelButton lbtnImage = new classLabelButton();
        classLabelButton lbtnGridColor = new classLabelButton();
        classLabelButton lbtnBackColor = new classLabelButton();
        
        Label lblGridSize = new Label();
        NumericUpDown nudGridWidth = new NumericUpDown();
        NumericUpDown nudGridHeight = new NumericUpDown();
        double dblRatio_X = 1.0;
        double dblRatio_Y = 1.0;

        Label lblRatio_X = new Label();
        Label lblRatio_Y = new Label();
        Ck_Objects.textBox_NumericInput_Double txtRatio_X = new textBox_NumericInput_Double();
        Ck_Objects.textBox_NumericInput_Double txtRatio_Y = new textBox_NumericInput_Double();

        CheckBox chkAutoSize = new CheckBox();
        Label lblCanvas_Width = new Label();
        Label lblCanvas_Height = new Label();
        Ck_Objects.textBox_NumericInput_Integer txtCanvas_Width = new textBox_NumericInput_Integer();
        Ck_Objects.textBox_NumericInput_Integer txtCanvas_Height = new textBox_NumericInput_Integer();

        PictureViewer.PictureViewer picViewer = new PictureViewer.PictureViewer();
        
        ContextMenu cMnu = new ContextMenu();

        Label lblOutput = new Label();

        public const string conExtension= "grd"; 
        
        public formGridMethod()
        {
            InitializeComponent();
            Hide();
            Controls.Add(grbControls);
            grbControls.Text = "Controls";
            grbControls.Name = "grbControls";
            toolTip.SetToolTip(grbControls, conDefaultToolTip);
            {
                grbControls.Controls.Add(lbtnImage);
                lbtnImage.Text = "Image";
                lbtnImage.Name = "lbtnImage";
                lbtnImage.AutoSize = true;
                lbtnImage.Click += LbtnImage_Click;
                toolTip.SetToolTip(lbtnImage, conDefaultToolTip);

                grbControls.Controls.Add(lbtnGridColor);
                lbtnGridColor.Text = "GridColor";
                lbtnGridColor.Name = "lbtnGridColor";
                lbtnGridColor.AutoSize = true;
                lbtnGridColor.Click += LbtnGridColor_Click;
                toolTip.SetToolTip(lbtnGridColor, conDefaultToolTip);

                lblGridSize.Text = "Grid:";
                lblGridSize.Name = "lblGridSize";
                lblGridSize.AutoSize = true;
                grbControls.Controls.Add(lblGridSize);
                toolTip.SetToolTip(lblGridSize, conDefaultToolTip);

                nudGridWidth.Minimum = 1;
                nudGridWidth.Maximum = 100;
                nudGridWidth.Width = 55;
                nudGridWidth.MouseWheel += nud_MouseWheel;
                nudGridWidth.ValueChanged += nud_Width_ValueChanged;
                nudGridWidth.Name = "nudGridWidth";
                toolTip.SetToolTip(nudGridWidth, conDefaultToolTip);
                grbControls.Controls.Add(nudGridWidth);

                nudGridHeight.Minimum = 1;
                nudGridHeight.Maximum = 100;
                nudGridHeight.Width = nudGridWidth.Width;
                nudGridHeight.MouseWheel += nud_MouseWheel;
                nudGridHeight.ValueChanged += nud_Height_ValueChanged;
                nudGridHeight.Name = "nudGridHeight";
                toolTip.SetToolTip(nudGridHeight, conDefaultToolTip);
                grbControls.Controls.Add(nudGridHeight);

                lblRatio_X.Text = "Ratio X:";
                lblRatio_X.Name = "lblRatio_X";
                lblRatio_X.AutoSize = true;
                grbControls.Controls.Add(lblRatio_X);
                toolTip.SetToolTip(lblRatio_X, conDefaultToolTip);

                txtRatio_X.Name = "txtRatio_X";
                txtRatio_X.Min = 0;
                txtRatio_X.Value = 1.0;
                txtRatio_X._eventValueChanged = eventTxtRatioX_valueChanged;
                grbControls.Controls.Add(txtRatio_X);
                toolTip.SetToolTip(txtRatio_X, conDefaultToolTip);

                lblRatio_Y.Text = "Ratio Y:";
                lblRatio_Y.Name = "lblRatio_Y";
                lblRatio_Y.AutoSize = true;
                grbControls.Controls.Add(lblRatio_Y);
                toolTip.SetToolTip(lblRatio_Y, conDefaultToolTip);

                txtRatio_Y.Name = "txtRatio_Y";
                txtRatio_Y.Min = 0;
                txtRatio_Y.Value = 1.0;
                txtRatio_Y._eventValueChanged = eventTxtRatioY_valueChanged;
                
                grbControls.Controls.Add(txtRatio_Y);
                toolTip.SetToolTip(txtRatio_Y, conDefaultToolTip);

                grbControls.Controls.Add(lbtnBackColor);
                lbtnBackColor.Text = "BackColor";
                lbtnBackColor.Name = "lbtnBackColor";
                lbtnBackColor.AutoSize = true;
                lbtnBackColor.Click += LbtnBackColor_Click;
                toolTip.SetToolTip(lbtnBackColor, conDefaultToolTip);

                grbControls.Controls.Add(chkAutoSize);
                chkAutoSize.Text = "Auto Size";
                chkAutoSize.Name = "chkAutoSize";
                chkAutoSize.AutoSize = true;
                chkAutoSize.CheckedChanged += ChkAutoSize_CheckedChanged;
                toolTip.SetToolTip(chkAutoSize, conDefaultToolTip);

                grbControls.Controls.Add(lblCanvas_Width);
                lblCanvas_Width.Text = "Canvas Width:";
                lblCanvas_Width.Name = "lblCanvas_Width";
                lblCanvas_Width.AutoSize = true;
                toolTip.SetToolTip(lblCanvas_Width, conDefaultToolTip);
                grbControls.Controls.Add(txtCanvas_Width);
                txtCanvas_Width.Name = "txtCanvas_Width";
                txtCanvas_Width.Min = 10;
                txtCanvas_Width._eventUserChangeMade += event_CanvasSize_Changed;
                toolTip.SetToolTip(txtCanvas_Width, conDefaultToolTip);

                grbControls.Controls.Add(lblCanvas_Height);
                lblCanvas_Height.Text = "Canvas Height:";
                lblCanvas_Height.Name = "lblCanvas_Height";
                lblCanvas_Height.AutoSize = true;
                toolTip.SetToolTip(lblCanvas_Height, conDefaultToolTip);
                grbControls.Controls.Add(txtCanvas_Height);
                txtCanvas_Height.Name = "txtCanvas_Height";
                txtCanvas_Height.Min = 10;
                txtCanvas_Height._eventUserChangeMade += event_CanvasSize_Changed;
                toolTip.SetToolTip(txtCanvas_Height, conDefaultToolTip);

                grbControls.BackColor
                    = lbtnImage.BackColor
                    = Color.White;

                grbControls.ForeColor
                    = lbtnImage.ForeColor
                    = Color.Black;

                grbControls.Click += GrbControls_Click;
            }

            Controls.Add(picAbout);
            picAbout.Image = (Bitmap)new Bitmap(Properties.Resources.About);
            picAbout.Width = picAbout.Image.Width;
            picAbout.Height = 10;
            picAbout.Click += PicAbout_Click;

            Controls.Add(picViewer);
            picViewer.Name = "picViewer";
            picViewer.Dock = DockStyle.Fill;
            picViewer.MouseWheel += PicViewer_MouseWheel;
            picViewer.MouseMove += PicViewer_MouseMove;
            picViewer.MouseDown += PicViewer_MouseDown;
            picViewer.MouseUp += PicViewer_MouseUp;
            picViewer.MouseLeave += PicViewer_MouseLeave;
            picViewer.MouseEnter += PicViewer_MouseEnter;
            toolTip.SetToolTip(picViewer, conDefaultToolTip);

            Controls.Add(lblOutput);
            lblOutput.Font = new Font("ms sans-serif", 12);
            lblOutput.AutoSize = true;
            lblOutput.BringToFront();

            cMnu.Popup += CMnu_Popup;
            cMnu.Collapse += CMnu_Collapse;

            CSRegisterHotkey.HotKeyRegister.hotKey_Register(this.Handle, Keys.Z, KeyModifiers.Control | KeyModifiers.Shift, HotKeyRegister_Event_ToggleSizelblOutput);

            Activated += FormGridMethod_Activated;
            SizeChanged += FormGridMethod_SizeChanged;
            LocationChanged += FormGridMethod_LocationChanged;
            Disposed += FormGridMethod_Disposed;

            ToolTip_SetUp();
        }


        void TestFirstRun()
        {
            bolFirstRun = (System.IO.File.Exists(strFilenameFirstRun));
            System.IO.File.WriteAllText(strFilenameFirstRun, "done");
        }
        static bool bolFirstRun = false;
        static public bool FirstRun
        {
            get { return bolFirstRun; }
        }
        string strFilenameFirstRun
        {
            get
            {
                string strRetVal = System.IO.Directory.GetCurrentDirectory() + "\\FirstRun.txt";
                return strRetVal;
            }
        }

        void event_CanvasSize_Changed(object sender, EventArgs e)
        {

            Canvas_Width = txtCanvas_Width.Value;
            Canvas_Height = txtCanvas_Height.Value;
            _bmpAutoSized = null;

            bmpAutoSized_Set();
            drawGrid();
        }

        bool bolAbout = false;
        bool About
        { 
            get { return bolAbout; }
            set 
            {
                bolAbout = value;
                if (bolAbout)
                {
                    picAbout.Height = picAbout.Image.Height;
                }
                else
                {
                    picAbout.Height = 10;
                }
            }
        }

        private void PicAbout_Click(object sender, EventArgs e)
        {
            About = !About;
        }

        #region Tooltip
        /// <summary>
        /// warns developer tooltip for an object has not been defined
        /// </summary>
        public const string conDefaultToolTip = "Tips defined in : ToolTip_SetUp()";

        /// <summary>
        /// manages all tool tips in SpriteEditor_2017
        /// </summary>
        public ToolTip toolTip = new ToolTip();

        /// <summary>
        /// classToolTip allows multiple tips to be assigned to each control
        /// </summary>
        public  classToolTip cTTips = new classToolTip();

        /// <summary>
        /// initializes an instance of classToolTip with all the tips for each control
        /// </summary>
        void ToolTip_SetUp()
        {
            cTTips.Tip_Clear_All();

            // Set up the delays for the ToolTip.
            toolTip.AutoPopDelay = 5000;
            toolTip.InitialDelay = 1000;
            toolTip.ReshowDelay = 100;
            toolTip.UseAnimation = true;
            toolTip.Popup += ToolTip_Popup;

            // Force the ToolTip text to be displayed whether or not the form is active.
            toolTip.ShowAlways = true;

            string[] strTips = {
                "Ctrl-Shift-Z changes size of cursor position label"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(grbControls.Name, strTips[intCounter]);
            
            strTips = new string[] {
                "you can load a new image by clicking this button",
                "select the image you want to draw with the File Dialog that appears when you click this button"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(lbtnImage.Name, strTips[intCounter]);

            strTips = new string[]  {
                "click here to change the color of the grid",
                "you can change the type of grid by using the context menu on your picture",
                "if you don't see a grid, use the right-mouse button display the context-menu and select 'grid' option"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(lbtnGridColor.Name, strTips[intCounter]);

            strTips = new string[] {
                "click here to change the color of the canvas outside your image",
                "back color is only visible when you're using auto-size"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(lbtnBackColor.Name, strTips[intCounter]);

            strTips = new string[] {
                "you can change the number of rows and columns in your grid here",
                "use the numeric boxes to the right to change the number of rows and columns in your grid"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(lblGridSize.Name, strTips[intCounter]);

            strTips = new string[]  {
                "this controls the number of columns that are in your image's grid",
                "you can either type the number in or use the mouse wheel to set your preference"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(nudGridWidth.Name, strTips[intCounter]);

            strTips = new string[]  {
                "this controls the number of rows that are in your image's grid",
                "you can either type the number in or use the mouse wheel to set your preference"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(nudGridHeight.Name, strTips[intCounter]);

            strTips = new string[] {
                "Ratio-X is a ratio between your canvas' width and the number of pixels in the source image's width",
                "this ratio is set automatically when you use auto-size"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(lblRatio_X.Name, strTips[intCounter]);

            strTips = new string[] {
                "Ratio-Y is a ratio between your canvas' height and the number of pixels in the source image's height",
                "this ratio is set automatically when you use auto-size"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(lblRatio_Y.Name, strTips[intCounter]);

            strTips = new string[]  {
                "you can set the ratio between your canvas's width and the image's width here",
                "when auto-size is set - the ratio will be set automatically",
                "you should keep the X-ratio equal to the Y-ratio at all times",
                "manually setting your X-ratio separately from the Y-Ratio will alter your project's aspect ratio and distort the image",
                "a better way to change the aspect ratio of your project is to stretch the source image in a photo-shop"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(txtRatio_X.Name, strTips[intCounter]);

            strTips = new string[]  {
                "you can set the ratio between your canvas's height and the image's height here",
                "when auto-size is set - the ratio will be  set automatically",
                "you should keep the X-ratio equal to the Y-ratio at all times",
                "manually setting your Y-ratio separately from the X-Ratio will alter your project's aspect ratio and distort the image",
                "a better way to change the aspect ratio of your project is to stretch the source image in a photo-shop"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(txtRatio_Y.Name, strTips[intCounter]);

            strTips = new string[]  {
                "Auto-size feature allows you to enter the size of your canvas",
                "knowing the size of the canvas helps GridMethod center your project onto your canvas"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(chkAutoSize.Name, strTips[intCounter]);

            strTips = new string[]  {
                "enter the Width of your canvas into the text box on the right",
                "if you're using standard units of measure be sure to use inches here"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(lblCanvas_Width.Name, strTips[intCounter]);

            strTips = new string[]  {
                "enter the Height of your canvas into the text box on the right",
                "if you're using standard units of measure be sure to use inches here"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(lblCanvas_Height.Name, strTips[intCounter]);

            strTips = new string[]  {
                "enter the Width of your canvas here",
                "if you're using standard units of measure be sure to use inches here"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(txtCanvas_Width.Name, strTips[intCounter]);

            strTips = new string[]  {
                "enter the height of your canvas here",
                "if you're using standard units of measure be sure to use inches here"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(txtCanvas_Height.Name, strTips[intCounter]);

            strTips = new string[]  {
                "use the mouse wheel to change the source image zoom and focus",
                "by left clicking the image you will center the grid beneath the mouse cursor",
                "use the right-mouse button the summon the context menu",
                "press down on the mouse-wheel button before scroll to change the info-label's position relative to the cursor",
                "Ctrl-Shift-Z changes size of cursor position label"};
            for (int intCounter = 0; intCounter < strTips.Length; intCounter++)
                cTTips.Tip_set(picViewer.Name, strTips[intCounter]);
        }

        /// <summary>
        /// prevents tool tip from giving the same control a tip every mousemove over that control
        /// </summary>
        object objAssociatedControl = null;
        /// <summary>
        /// stops edits tool tip with the multiple tips available for a given control
        /// </summary>
        private void ToolTip_Popup(object sender, PopupEventArgs e)
        {
            if (e.AssociatedControl == objAssociatedControl
                || e.AssociatedControl == null
                || e.AssociatedControl.Name.Length == 0) return;
            objAssociatedControl = e.AssociatedControl;
            string strName = e.AssociatedControl.Name;
            string strTip = cTTips.Tip_get(strName);

            if (strTip.Length > 0)
                toolTip.SetToolTip(e.AssociatedControl, strTip);
        }

        #endregion

        bool _bolLblOutputLarge = false;
        bool bolLblOutputLarge
        {
            get { return _bolLblOutputLarge; }
            set
            {
                _bolLblOutputLarge = value;
                lblOutput.Font = new Font("ms sans-serif", _bolLblOutputLarge ? 48 : 12);
                placeLabel();
            }
        }
        void HotKeyRegister_Event_ToggleSizelblOutput(object sender, EventArgs e)
        {
            bolLblOutputLarge = !bolLblOutputLarge;
        }

        Bitmap _bmpAutoSized = null;
        Bitmap _bmpSource = null;
        Bitmap bmpSource
        {
            get
            {
                if (chkAutoSize.Checked)
                {
                    if (_bmpAutoSized == null)
                        bmpAutoSized_Set();
                    return _bmpAutoSized;
                }
                else
                {
                    return _bmpSource;
                }
            }
        }




        private void ChkAutoSize_CheckedChanged(object sender, EventArgs e)
        {
            txtRatio_X.Enabled
                = txtRatio_Y.Enabled
                = !chkAutoSize.Checked;
            
            txtCanvas_Width.Visible
                = txtCanvas_Height.Visible
                = chkAutoSize.Checked;
            if (chkAutoSize.Checked)
                event_CanvasSize_Changed((object)txtCanvas_Height, new EventArgs());
            else
            {
                _bmpAutoSized = null;
                drawGrid();
            }
        }
        /*
                int intCanvas_width = 10;
                int Canvas_Width
                {
                    get { return intCanvas_width; }
                    set { intCanvas_width = value; }
                }

                int intCanvas_Height = 10;
                int Canvas_Height
                {
                    get { return intCanvas_Height; }
                    set { intCanvas_Height = value; }
                }
        */


        public static int Canvas_Height
        { 
            get { return szCanvas.Height; }
            set { szCanvas = new Size(szCanvas.Width, value); }
        }
        
        public static int Canvas_Width
        { 
            get { return szCanvas.Width; }
            set { szCanvas = new Size(value, szCanvas.Height); }
        }

        
        static Size _szCanvas = new Size(100,100);
        static Size _szCanvas_DefaultSize = new Size(100, 100);
        const double dblRatioLimit = 25.0;
        public static Size szCanvas
        {
            get { return _szCanvas; }
            set 
            {
                _szCanvas = value;
            
            }
        }


        void CanvasSize_Test()
        {
            double dblRatio = (double)_szCanvas.Width / (double)_szCanvas.Height;
            if (dblRatioLimit < 1.0 / dblRatioLimit || dblRatio > dblRatioLimit)
            { // sz Canvas is out of range
                _szCanvas = new Size(_szCanvas.Width, _szCanvas_DefaultSize.Height);
            }
            bolCanvasSize_Changed = false;
        }

 



        void bmpAutoSized_Set()
        {

            double dblAspectRatio_Source = (double)_bmpSource.Height / (double)_bmpSource.Width;
            double dblAspectRatio_Canvas = (double)szCanvas.Height / (double)szCanvas.Width;
            if (dblAspectRatio_Canvas < dblAspectRatio_Source)
            {
                // limiting factor is the height
                int intCanvas_Bmp_Height = _bmpSource.Height;
                int intCanvas_Bmp_Width = (int)((double)intCanvas_Bmp_Height / dblAspectRatio_Canvas);




                _bmpAutoSized = new Bitmap(intCanvas_Bmp_Width, intCanvas_Bmp_Height);
                using (Graphics g = Graphics.FromImage(_bmpAutoSized))
                {
                    SolidBrush brBackground = new SolidBrush(lbtnBackColor.BackColor);
                    g.FillRectangle(brBackground, new RectangleF(0, 0, _bmpAutoSized.Width, _bmpAutoSized.Height));
                    g.DrawRectangle(new Pen(lbtnGridColor.BackColor), new Rectangle(0, 0, _bmpAutoSized.Width - 1, _bmpAutoSized.Height - 1));
                    Rectangle recSource = new Rectangle(0, 0, _bmpSource.Width, _bmpSource.Height);
                    Rectangle recDest = new Rectangle((intCanvas_Bmp_Width - _bmpSource.Width) / 2, 0, _bmpSource.Width, _bmpSource.Height);
                    g.DrawImage(_bmpSource, recDest, recSource, GraphicsUnit.Pixel);
                }
            }
            else
            {
                // limiting factor is the width
                int intCanvas_Bmp_Width = _bmpSource.Width;
                int intCanvas_Bmp_Height = (int)((double)intCanvas_Bmp_Width * dblAspectRatio_Canvas);
                _bmpAutoSized = new Bitmap(intCanvas_Bmp_Width, intCanvas_Bmp_Height);
                using (Graphics g = Graphics.FromImage(_bmpAutoSized))
                {
                    SolidBrush brBackground = new SolidBrush(lbtnBackColor.BackColor);
                    g.FillRectangle(brBackground, new RectangleF(0, 0, _bmpAutoSized.Width, _bmpAutoSized.Height));
                    g.DrawRectangle(new Pen(lbtnGridColor.BackColor), new Rectangle(0, 0, _bmpAutoSized.Width - 1, _bmpAutoSized.Height - 1));

                    Rectangle recSource = new Rectangle(0, 0, _bmpSource.Width, _bmpSource.Height);
                    Rectangle recDest = new Rectangle(0, (intCanvas_Bmp_Height - _bmpSource.Height) / 2, _bmpSource.Width, _bmpSource.Height);
                    g.DrawImage(_bmpSource, recDest, recSource, GraphicsUnit.Pixel);
                }
            }

            // set draw ratio
            txtRatio_X.Value = (double)((double)txtCanvas_Width.Value / (double)bmpSource.Width);
            txtRatio_Y.Value = txtRatio_X.Value;
        }

        private void nud_MouseWheel(object sender, MouseEventArgs e)
        {
            HandledMouseEventArgs handledArgs = e as HandledMouseEventArgs;
            handledArgs.Handled = true;
            NumericUpDown nudSender = (NumericUpDown)sender;
            int intNewValue =(int)( nudSender.Value + (handledArgs.Delta > 0 ? 1 : -1));
            if (intNewValue >= nudSender.Minimum && intNewValue <= nudSender.Maximum)
                nudSender.Value = intNewValue;
        }

        bool bolShowControls = true;
        private void GrbControls_Click(object sender, EventArgs e)
        {
            bolShowControls = !bolShowControls;
            if (bolShowControls)
                grbControls.Height = txtCanvas_Height.Bottom + 15;
            else
                grbControls.Height = 20;
        }

        private void nud_Width_ValueChanged(object sender, EventArgs e)
        {
            placeObjects();
            drawGrid();
        }
        
        private void nud_Height_ValueChanged(object sender, EventArgs e)
        {
            placeObjects();
            drawGrid();
        }

        void eventTxtRatioX_valueChanged(object sender, EventArgs e)
        {
            dblRatio_X = txtRatio_X.Value;
        }
        
        void eventTxtRatioY_valueChanged(object sender, EventArgs e)
        {
            dblRatio_Y = txtRatio_Y.Value;
        }


        bool bolMenuVisible = false;
        private void CMnu_Collapse(object sender, EventArgs e)
        {
            bolMenuVisible = false;
        }

        private void CMnu_Popup(object sender, EventArgs e)
        {
            bolMenuVisible = true;
        }

        bool bolMetric = true;
        bool Metric
        { 
            get { return bolMetric; }
            set { bolMetric = value; }
        }

        bool bolToolTip_Enable = true;
        bool ToolTip_Enable
        {
            get { return bolToolTip_Enable; }
            set
            {
                bolToolTip_Enable = value;
                toolTip.Active = value;
                cMnu_Build();
            }
        }

        void mnuToolTip_click(object sender, EventArgs e)
        {
            ToolTip_Enable = !ToolTip_Enable;    
        }

        void cMnu_Build()
        {

            cMnu.MenuItems.Clear();

            MenuItem mnuFile = new MenuItem("File");
            {
                MenuItem mnuFile_Load = new MenuItem("Load", mnuFileLoad_click);
                mnuFile.MenuItems.Add(mnuFile_Load);

                MenuItem mnuFile_Save = new MenuItem("Save", mnuFileSave_click);
                mnuFile.MenuItems.Add(mnuFile_Save);

                MenuItem mnuFile_Quit = new MenuItem("Quit", mnuFileQuit_click);
                mnuFile.MenuItems.Add(mnuFile_Quit);

            }
            cMnu.MenuItems.Add(mnuFile);

            MenuItem mnuGrid = new MenuItem("grid");
            {
                for (int intGridStyleCounter = 0; intGridStyleCounter < (int)enuGridStyle._num; intGridStyleCounter++)
                {
                    enuGridStyle eGridStyleCounter = (enuGridStyle)intGridStyleCounter;
                    MenuItem mnuGridStyle = new MenuItem(eGridStyleCounter.ToString(), event_GridStyle_click);
                    mnuGridStyle.Tag = (object)eGridStyleCounter;
                    mnuGrid.MenuItems.Add(mnuGridStyle);
                }
            }
            cMnu.MenuItems.Add(mnuGrid);

            cMnu.MenuItems.Add(new MenuItem("Toggle Draw Ruler : " + (DrawRuler ? "On" : "Off"), mnuToggleDrawRuler_click));

            MenuItem mnuRuler = new MenuItem("Ruler Measure from Edge", event_Ruler_click);
            mnuRuler.Checked = RulerMeasureFromEdge;
            cMnu.MenuItems.Add(mnuRuler);
            
            MenuItem mnuQuadrant = new MenuItem("Draw Quadrant info", event_DrawQuadrantInfo_click);
            mnuQuadrant.Checked = QuadrantInfo_IsDrawn;
            cMnu.MenuItems.Add(mnuQuadrant);

            MenuItem mnuMetric = new MenuItem("Metric", event_DrawMetricInfo_click);
            mnuMetric.Checked = Metric;
            cMnu.MenuItems.Add(mnuMetric);

            MenuItem mnuToolTip = new MenuItem("ToolTip", mnuToolTip_click);
            mnuToolTip.Checked = ToolTip_Enable;
            cMnu.MenuItems.Add(mnuToolTip);

            MenuItem mnuControls = new MenuItem("Controls", mnuControls_click);
            cMnu.MenuItems.Add(mnuControls);

            ContextMenu = cMnu;
        }

        void mnuToggleDrawRuler_click(object sender, EventArgs e)
        {
            DrawRuler = !DrawRuler;
            drawGrid();
            cMnu_Build();
        }

        void event_DrawMetricInfo_click(object sender, EventArgs e)
        {
            Metric = !Metric;
            cMnu_Build();
        }

        bool bolQuadrantInfo_IsDrawn = true;
        bool QuadrantInfo_IsDrawn
        {
            get { return bolQuadrantInfo_IsDrawn; }
            set
            {
                if (bolQuadrantInfo_IsDrawn != value)
                {
                    bolQuadrantInfo_IsDrawn = value;
                    drawGrid();
                }
            }
        }

        void event_DrawQuadrantInfo_click(object sender, EventArgs e)
        {
            QuadrantInfo_IsDrawn = !QuadrantInfo_IsDrawn;
            cMnu_Build();
        }

        bool bolRulerMeasureFromEdge = false;
        bool RulerMeasureFromEdge
        {
            get { return bolRulerMeasureFromEdge; }
            set { bolRulerMeasureFromEdge = value; }
        }

        void event_Ruler_click(object sender, EventArgs e)
        {
            RulerMeasureFromEdge = !RulerMeasureFromEdge;
            cMnu_Build();
        }

        void event_GridStyle_click(object sender, EventArgs e)
        {
            MenuItem mnuSender = (MenuItem)sender;
            eGridStyle = (enuGridStyle)mnuSender.Tag;
        }

        void mnuControls_click(object sender, EventArgs e)
        {
            grbControls.Visible = !grbControls.Visible;
        }

        void mnuFileLoad_click(object sender, EventArgs e)
        {
            //OpenFileDialog_GUI ofd = new OpenFileDialog_GUI();
            //ofd.GUI_Load(OFD_GUI_Filename);
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Grid Method Projects|*." + conExtension;
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                GridMethodProject_Load(ofd.FileName);
            }
        }
        
        void mnuFileSave_click(object sender, EventArgs e)
        {
            //SaveFileDialog_GUI sfd = new SaveFileDialog_GUI();
            //sfd.GUI_Load(OFD_GUI_Filename);
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "Grid Method Projects|*" + conExtension;
            sfd.DefaultExt = conExtension;
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                GridMethodProject_Save(sfd.FileName);
            }
        }

        void GridMethodProject_Load(string strFilename)
        {
            if (!System.IO.File.Exists(strFilename)) return;

            FileStream fs = new FileStream(strFilename, FileMode.Open);

            try
            {
                //                                          bitmap
                _bmpSource = (Bitmap)formatter.Deserialize(fs);
                picViewer.lstRegions[0].bmpSource = new Bitmap(bmpSource);

                //                                          back color
                {
                    int intR = (int)((byte)formatter.Deserialize(fs));
                    int intG = (int)((byte)formatter.Deserialize(fs));
                    int intB = (int)((byte)formatter.Deserialize(fs));
                    clrBackcolor
                        = lbtnBackColor.BackColor
                        = Color.FromArgb(intR, intG, intB);
                }

                //                                          grid
                {
                    //                                          grid size
                    nudGridWidth.Value = (int)formatter.Deserialize(fs);
                    nudGridHeight.Value = (int)formatter.Deserialize(fs);

                    //                                          grid style   
                    eGridStyle = (enuGridStyle)((byte)formatter.Deserialize(fs));

                    //                                          grid color
                    int intR = (int)((byte)formatter.Deserialize(fs));
                    int intG = (int)((byte)formatter.Deserialize(fs));
                    int intB = (int)((byte)formatter.Deserialize(fs));

                    lbtnGridColor.BackColor
                        = clrGridColor
                        = Color.FromArgb(intR, intG, intB);
                }

                //                                          ratio-X
                txtRatio_X.Value = (double)formatter.Deserialize(fs);
                //                                          ratio-Y
                txtRatio_Y.Value = (double)formatter.Deserialize(fs);

                //                                          Ruler from edge
                RulerMeasureFromEdge = (bool)formatter.Deserialize(fs);
                //                                          draw quadrant info
                QuadrantInfo_IsDrawn = (bool)formatter.Deserialize(fs);

                //                                          auto size
                chkAutoSize.Checked = (bool)formatter.Deserialize(fs);
                //                                          canvas width
                txtCanvas_Width.Value = (int)formatter.Deserialize(fs);
                //                                          canvas height
                txtCanvas_Height.Value = (int)formatter.Deserialize(fs);

                //                                  metric 
                Metric = (bool)formatter.Deserialize(fs);

                //
                DrawRuler = (bool)formatter.Deserialize(fs);

                //                                  tool-tip enabled
                ToolTip_Enable = (bool)formatter.Deserialize(fs);

                //                                      picViewer
                //                                  zoom
                picViewer.lstRegions[0].Zoom = (double)formatter.Deserialize(fs);
                //                                  focus 
                int intX = (int)formatter.Deserialize(fs);
                int intY = (int)formatter.Deserialize(fs);
                picViewer.lstRegions[0].ptFocus = new Point(intX, intY);

                //                                      form
                byte bytWindowState = (byte)formatter.Deserialize(fs);
                switch (bytWindowState)
                {
                    case 0:
                        WindowState = FormWindowState.Normal;
                        break;

                    case 1:
                        WindowState = FormWindowState.Minimized;
                        break;

                    case 2:
                        WindowState = FormWindowState.Maximized;
                        break;

                    default:
                        WindowState = FormWindowState.Normal;
                        break;
                }
                Left = (int)formatter.Deserialize(fs);
                Top = (int)formatter.Deserialize(fs);
                Width = (int)formatter.Deserialize(fs);
                Top = (int)formatter.Deserialize(fs);


                fs.Close();
            }
            catch (Exception)
            {
                _bmpSource = (Bitmap)Properties.Resources.Error_Loading_Grid_Method;
                fs.Close();
            }
            
            drawGrid();
        }

        void GridMethodProject_Save(string strFilename)
        {
            FileStream fs = new FileStream(strFilename, FileMode.Create);
            //                                          bitmap
            formatter.Serialize(fs, _bmpSource);

            //                                          back color
            {
                //                                                          grid-color
                formatter.Serialize(fs, (byte)clrBackcolor.R);
                formatter.Serialize(fs, (byte)clrBackcolor.G);
                formatter.Serialize(fs, (byte)clrBackcolor.B);
            }

            //                                          grid
            {
                //                                                          grid-size
                formatter.Serialize(fs, (int)nudGridWidth.Value);
                formatter.Serialize(fs, (int)nudGridHeight.Value);
                //                                                          grid-style
                formatter.Serialize(fs, (byte)eGridStyle);
                //                                                          grid-color
                formatter.Serialize(fs, (byte)clrGridColor.R);
                formatter.Serialize(fs, (byte)clrGridColor.G);
                formatter.Serialize(fs, (byte)clrGridColor.B);
            }

            //                                         ratio-X
            formatter.Serialize(fs, (double)txtRatio_X.Value);
            //                                         ratio-Y
            formatter.Serialize(fs, (double)txtRatio_Y.Value);

            //                                          ruler from edge
            formatter.Serialize(fs, (bool)RulerMeasureFromEdge);
            //                                          draw quadrant info
            formatter.Serialize(fs, (bool)QuadrantInfo_IsDrawn);

            //                                          auto-size
            formatter.Serialize(fs, (bool)chkAutoSize.Checked);
            //                                          canvas width
            formatter.Serialize(fs, (int)Canvas_Width );
            //                                          canvas height
            formatter.Serialize(fs, (int)Canvas_Height);

            //                                          Metric
            formatter.Serialize(fs, (bool)Metric);

            //                                          draw ruler
            formatter.Serialize(fs, (bool)DrawRuler);

            //                                          tool-tip enabled
            formatter.Serialize(fs, (bool)ToolTip_Enable);

            //                                      picViewer
            //                                  zoom
            formatter.Serialize(fs, (double)dblZoom);
            //                                  focus
            formatter.Serialize(fs, (int)ptFocus.X);
            formatter.Serialize(fs, (int)ptFocus.Y);

            //                                      form
            switch (frmWindowState)
            {
                case FormWindowState.Normal:
                    formatter.Serialize(fs, (byte)0);
                    break;

                case FormWindowState.Minimized:
                    formatter.Serialize(fs, (byte)1);
                    break;

                case FormWindowState.Maximized:
                    formatter.Serialize(fs, (byte)2);
                    break;
            
            }
            formatter.Serialize(fs, (int)ptLocation.X);
            formatter.Serialize(fs, (int)ptLocation.Y);
            formatter.Serialize(fs, (int)szForm.Width);
            formatter.Serialize(fs, (int)szForm.Height);

            fs.Close();
        }

        void mnuFileQuit_click(object sender, EventArgs e)
        {
            Dispose();
        }

        string OFD_GUI_Filename
        {
            get
            {
                return Directory + "\\FileDialog_EaselfdGUI.fdGUI";

            }
        }

        private void LbtnImage_Click(object sender, EventArgs e)
        {
            //OpenFileDialog_GUI ofd = new OpenFileDialog_GUI();
            //ofd.GUI_Load(OFD_GUI_Filename);
           
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Images | *.jpg; *.gif; *.bmp; *.png; *.jpeg";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                _bmpAutoSized = null;
                _bmpSource = (Bitmap)Bitmap.FromFile(ofd.FileName);
                picViewer.lstRegions[0].bmpSource = new Bitmap(bmpSource);
            }
        }
        Color clrGridColor = Color.Black;
        void LbtnGridColor_Click(object sender, EventArgs e)
        {
            ColorDialog cd = new ColorDialog();
            if (cd.ShowDialog() == DialogResult.OK)
            {
                lbtnGridColor.BackColor 
                    = clrGridColor
                    = cd.Color;
                int intR = (int)((lbtnGridColor.BackColor.R + 128) % 256);
                int intG = (int)((lbtnGridColor.BackColor.G + 128) % 256);
                int intB = (int)((lbtnGridColor.BackColor.B + 128) % 256);
                lbtnGridColor.ForeColor = Color.FromArgb(intR, intG, intB);
                drawGrid();
            }
        }

        Color clrBackcolor = Color.White;
        void LbtnBackColor_Click(object sender, EventArgs e)
        {
            ColorDialog cd = new ColorDialog();
            if (cd.ShowDialog() == DialogResult.OK)
            {
                lbtnBackColor.BackColor 
                    = clrBackcolor
                    = cd.Color;
                int intR = (int)((lbtnBackColor.BackColor.R + 128) % 256);
                int intG = (int)((lbtnBackColor.BackColor.G + 128) % 256);
                int intB = (int)((lbtnBackColor.BackColor.B + 128) % 256);
                lbtnBackColor.ForeColor = Color.FromArgb(intR, intG, intB);
                bmpAutoSized_Set();
                drawGrid();
            }
        }

        Size szForm = new Size();
        private void FormGridMethod_SizeChanged(object sender, EventArgs e)
        {
            lblOutput.BringToFront();
            lblOutput.Location = new Point((Width - lblOutput.Width) / 2, Height - lblOutput.Height -45);
            szForm = new Size(Width, Height);
            placeObjects();
        }
        Point ptLocation = new Point();
        private void FormGridMethod_LocationChanged(object sender, EventArgs e)
        {
            ptLocation = new Point(Left, Top);
            frmWindowState = WindowState;
        }
        FormWindowState frmWindowState = FormWindowState.Normal;

string RulerText
{
    get
    {
        if (RulerMeasureFromEdge)
        {
                    
            if (Metric)
            {
                double dblX = (double)((double)picViewer.lstRegions[0].ptMousePosition.X * Ratio_X);
                double dblY = (double)((double)picViewer.lstRegions[0].ptMousePosition.Y * Ratio_Y);

                return "("
                        + dblX.ToString(".0")
                        + ", "
                        + dblY.ToString(".0")
                        + ")";
            }
            else
            {
                float fltX = (float)((double)picViewer.lstRegions[0].ptMousePosition.X * Ratio_X);
                float fltY = (float)((double)picViewer.lstRegions[0].ptMousePosition.Y * Ratio_Y);

                string strX = Math3.classMath3.FeetDecimalToFraction(fltX/12f);
                string strY = Math3.classMath3.FeetDecimalToFraction(fltY/12f);
                return "(" + strX + ", " + strY + ")";
            }
        }
        else
        {
            double dblX = ((double)picViewer.lstRegions[0].ptMousePosition.X);
            double dblGridWidth = GridWidth;
            while (dblX > dblGridWidth)
                dblX -= dblGridWidth;

            double dblY = (double)picViewer.lstRegions[0].ptMousePosition.Y;
            double dblGridHeight = GridHeight;
            while (dblY > dblGridHeight)
                dblY -= dblGridHeight;
            if (Metric)
                return "("
                        + (dblX * Ratio_X).ToString(".0")
                        + ", "
                        + (dblY * Ratio_Y).ToString(".0")
                        + ")";
            else
            {
                string strX = Math3.classMath3.FeetDecimalToFraction( (float)((dblX / dblGridWidth * txtCanvas_Width.Value / (double)nudGridWidth.Value) / 12.0));
                string strY = Math3.classMath3.FeetDecimalToFraction( (float)((dblY / dblGridHeight * txtCanvas_Height.Value / (double)nudGridHeight.Value) / 12.0));
                return "(" + strX + ", " + strY + ")";
            }
        }
    }
}

        Point QuadrantMouseOver()
        {
            Point ptRetVal = new Point();
            double dblX = ((double)picViewer.lstRegions[0].ptMousePosition.X);
            double dblGridWidth = GridWidth;
            while (dblX > dblGridWidth)
            {
                dblX -= dblGridWidth;
                ptRetVal.X++;
            }
            double dblY = (double)picViewer.lstRegions[0].ptMousePosition.Y;
            double dblGridHeight = GridHeight;
            while (dblY > dblGridHeight)
            {
                dblY -= dblGridHeight;
                ptRetVal.Y++;
            }

            return ptRetVal;
        }
        private void PicViewer_MouseEnter(object sender, EventArgs e)
        {
            lblOutput.Show();
        }
        private void PicViewer_MouseLeave(object sender, EventArgs e)
        {
            picViewer.IgnoreMouseWheel = false;
            lblOutput.Hide();
        }
        private void PicViewer_MouseUp(object sender, MouseEventArgs e)
        {
            bolGrab = false;
            picViewer.IgnoreMouseWheel = false;
        }
        Point ptGrab = new Point();
        bool bolGrab = false;
        private void PicViewer_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Middle)
            {
                picViewer.IgnoreMouseWheel = true;
                ptGrab = new Point( ptMouseScreen.X, ptMouseScreen.Y);
                bolGrab = true;
            }

            if (bolMenuVisible || e.Button != MouseButtons.Left) return;

            Point ptQuadrantSelected = QuadrantMouseOver();
            Point ptCorner = new Point((int)(((double)ptQuadrantSelected.X + .5) * GridWidth),
                                       (int)(((double)ptQuadrantSelected.Y + .5) * GridHeight));
            if (DrawRuler)
                drawGrid();
            picViewer.lstRegions[0].ptFocus = ptCorner;
            picViewer.lstRegions[0].Refreshed = false;
            picViewer.Display ();

        }

        private void PicViewer_MouseMove(object sender, MouseEventArgs e)
        {
            ptMouseScreen = new Point(e.X, e.Y);
            if (bolGrab)
            {
                Point ptShift = new Point((int)((ptGrab.X- ptMouseScreen.X)* picViewer.lstRegions[0].Zoom),
                                          (int)((ptGrab.Y- ptMouseScreen.Y)* picViewer.lstRegions[0].Zoom));
                picViewer.lstRegions[0].ptFocus = Math3.classMath3.AddTwoPoints(picViewer.lstRegions[0].ptFocus, ptShift);
                picViewer.lstRegions[0].Refreshed = false;
                picViewer.Display();
                ptGrab = new Point(e.X, e.Y);
            }
            else
            {
                lblOutput.Text = RulerText;
                placeLabel();
            }
        }

        Point ptFocus = new Point();
        double dblZoom = 1.0;
        private void PicViewer_MouseWheel(object sender, MouseEventArgs e)
        {
            ptFocus = picViewer.lstRegions[0].ptFocus;
            dblZoom = picViewer.lstRegions[0].Zoom;
            if (!picViewer.IgnoreMouseWheel)
                return;
            if (e.Delta > 0)
                lblShift_RotateLeft();
            else
                lblShift_RotateRight();
            placeLabel();
        }

        Point ptMouseScreen = new Point();
        int intGap = 25;
        Point ptLblShifted
        {
            get 
            {
                switch (_intLblShift)
                {
                    case 0:     // Bottom-Left
                        return new Point(ptMouseScreen.X - intGap - lblOutput.Width,
                                         ptMouseScreen.Y + intGap);

                    case 1:     // top - left
                        return new Point(ptMouseScreen.X - intGap - lblOutput.Width,
                                         ptMouseScreen.Y - intGap - lblOutput.Height);
                    case 2:     // Top-Right
                        return new Point(ptMouseScreen.X + intGap,
                                         ptMouseScreen.Y - intGap - lblOutput.Height);

                    default:     // Bottom-Right
                        return new Point(ptMouseScreen.X + intGap,
                                         ptMouseScreen.Y + intGap);
                }
            }
        }
        
        int _intLblShift = 0;

        void lblShift_RotateRight()
        {
            _intLblShift = (_intLblShift + 1) % 4;
        }
        void lblShift_RotateLeft()
        {
            _intLblShift = (_intLblShift + 3) % 4;
        }

        void placeLabel()
        { 
            Rectangle recLabel = new Rectangle( ptLblShifted, lblOutput.Size);
            int intCounter = 0;
            while (intCounter < 4 
                    &&  (recLabel.Right > picViewer.Width 
                            || 
                         recLabel.Bottom > picViewer.Height
                            ||
                         recLabel.Top <0
                            ||
                         recLabel.Left <0))
            {
                lblShift_RotateRight();
                recLabel = new Rectangle(ptLblShifted, lblOutput.Size);
                intCounter++;
            }
            lblOutput.Location = recLabel.Location;
        }

        public double Ratio_X
        {
            get { return dblRatio_X; }
            set
            {
                dblRatio_X = value;
            }
        }
        
        public double Ratio_Y
        {
            get { return dblRatio_Y; }
            set
            {
                dblRatio_Y = value;
            }
        }

        void event_Ratio_X_changed(object sender, EventArgs e)
        {
            placeObjects();
        }

        
        void event_Ratio_Y_changed(object sender, EventArgs e)
        {
            placeObjects();
        }

        void event_Grid_Changed(object sender, EventArgs e)
        {
            drawGrid();
        }

        bool _bolDrawRuler = false;
        bool DrawRuler
        {
            get { return _bolDrawRuler; }
            set { _bolDrawRuler = value; }
        }

        public enum enuGridStyle 
        {
            none, 
            corners, 
            dash, 
            dot, 
            dashDot, 
            dashDotDot, 
            full, 
            _num 
        };

        enuGridStyle _eGridStyle = enuGridStyle.corners;
        public enuGridStyle eGridStyle
        { 
        get { return _eGridStyle; }
        set 
            {
                if (_eGridStyle != value)
                {
                    _eGridStyle = value;
                    drawGrid();
                }
            }
        }


        System.Drawing.Drawing2D.DashStyle[] dashStyle = null;

        double GridHeight
        {
            get
            {
                return ((double)bmpSource.Height / (double)nudGridHeight.Value + 1);
            }
        }

        double GridWidth
        {
            get
            {
                return ((double)bmpSource.Width / (double)nudGridWidth.Value + 1);
            }
        }

        Point GridCorner(Point ptGrid) { return GridCorner(ptGrid.X, ptGrid.Y); } 
        Point GridCorner(int intX, int intY)
        {
            return new Point((int)(GridWidth * intX),(int)( GridHeight * intY));
        }

        void drawQuadrantInfo(ref Graphics g)
        {
            if (bmpSource == null || !QuadrantInfo_IsDrawn) return;

            SolidBrush brQInfo = new SolidBrush(lbtnGridColor.BackColor);

            Font fnt = new Font("ms sans-serif", 10);
            int intShift = 5;
            for (int intX = 0; intX < nudGridWidth.Value; intX++)
            {
                for (int intY = 0; intY < nudGridHeight.Value; intY++)
                {
                    Point ptCorner = GridCorner(intX, intY);
                    Point ptDraw = new Point(ptCorner.X + intShift, ptCorner.Y + intShift);
                    string strQInfo = "(" + intX.ToString() + ", " + intY.ToString() + ")";
                    g.DrawString(strQInfo, fnt, brQInfo, ptDraw);
                }
            }
        }
        void drawRuler(ref Graphics g)
        {
            if (bmpSource == null || !QuadrantInfo_IsDrawn) return;

            Pen pRuler = new Pen(lbtnGridColor.BackColor, 1);
            int intDash_Short = 5;
            int intDash_Long = 15;

            Point ptQuadrantSelected = QuadrantMouseOver();
            Point ptTL = GridCorner(ptQuadrantSelected.X, ptQuadrantSelected.Y);
            Point ptBR = new Point(ptTL.X + (int)GridWidth,
                                   ptTL.Y + (int)GridHeight);
            if (ptBR.X > bmpSource.Width)
                ptBR.X = bmpSource.Width-2;
            if (ptBR.Y > bmpSource.Height)
                ptBR.Y = bmpSource.Height-2;

            bool bolDebug = false;
            if (bolMetric)
            {
                Font fnt = new Font("ms sans-serif", 10);
                SolidBrush brNumber = new SolidBrush(lbtnGridColor.BackColor);

                double dblWidth_Centimeters = ((double)szCanvas.Width / (double)nudGridWidth.Value + 1)/10;
                int intY_Short = intDash_Short / 2;
                int intY_Long = intDash_Long / 2;
                
                int intX_Short = intDash_Short / 2;
                int intX_Long = intDash_Long / 2;

                for (int intX = 0; intX < dblWidth_Centimeters; intX++)
                {
                    int intXCentimeter = ptTL.X + (int)((double)intX * GridWidth / dblWidth_Centimeters);

                    bool bolLong = intX % 5 == 0;

                    // top row
                    Point ptTop_Top = new Point(intXCentimeter, bolLong
                                                                    ? ptTL.Y - intY_Long
                                                                    : ptTL.Y - intY_Short);
                    Point ptBottom_Top = new Point(intXCentimeter, bolLong
                                                                    ? ptTL.Y + intY_Long
                                                                    : ptTL.Y + intY_Short);
                    g.DrawLine(pRuler, ptTop_Top, ptBottom_Top);

                    // bottom row
                    Point ptTop_Bottom = new Point(intXCentimeter, bolLong
                                                                    ? ptBR.Y - intY_Long
                                                                    : ptBR.Y - intY_Short);

                    Point ptBottom_Bottom = new Point(intXCentimeter, bolLong
                                                                        ? ptBR.Y + intY_Long
                                                                        : ptBR.Y + intY_Short);
                    g.DrawLine(pRuler, ptTop_Bottom, ptBottom_Bottom);

                    if (bolLong)
                    {
                        string strNumber = intX.ToString();
                        Size szNumber = TextRenderer.MeasureText(strNumber, fnt);

                        Point ptStringTop = new Point((int)((double)intXCentimeter - (double)szNumber.Width / 2.0),
                                                      (int)((double)ptTL.Y - (double)szNumber.Height * 1.1));
                        g.DrawString(strNumber, fnt, brNumber, ptStringTop);

                        Point ptStringBottom = new Point(ptStringTop.X, (int)((double)ptTL.Y + GridHeight + (double)szNumber.Height * 1.1));
                        g.DrawString(strNumber, fnt, brNumber, ptStringBottom);
                    }

                    if (bolDebug)
                        bmpSource.Save(@"c:\debug\bmpSource.bmp");
                }

                double dblHeight_Centimeters = ((double)szCanvas.Height / (double)nudGridHeight.Value + 1)/10;
                for (int intY = 0; intY < dblHeight_Centimeters; intY++)
                {
                    int intYCentimeter = ptTL.Y + (int)((double)intY * GridHeight / dblHeight_Centimeters);
                    bool bolLong = intY % 5 == 0;
                    // left column
                    {
                        Point ptLeft_Left = new Point(bolLong
                                                    ? ptTL.X - intX_Long
                                                    : ptTL.X - intX_Short,
                                                  intYCentimeter);

                        Point ptRight_Left = new Point(bolLong
                                                        ? ptTL.X + intX_Long
                                                        : ptTL.X + intX_Short,
                                                      intYCentimeter);

                        g.DrawLine(pRuler, ptLeft_Left, ptRight_Left);
                    }
                    // right column
                    {
                        Point ptRight_Left = new Point(bolLong
                                                        ? ptBR.X - intX_Long
                                                        : ptBR.X - intX_Short,
                                                  intYCentimeter);
                
                        Point ptRight_Right = new Point(bolLong
                                                            ? ptBR.X + intX_Long
                                                            : ptBR.X + intX_Short,
                                                       intYCentimeter);

                        g.DrawLine(pRuler, ptRight_Left, ptRight_Right);
                    }

                    if (bolLong)
                    {
                        string strNumber = intY.ToString();
                        Size szNumber = TextRenderer.MeasureText(strNumber, fnt);
                        Point ptString_Left = new Point((int)((double)ptTL.X - (double)szNumber.Width *1.1),
                                                        (int)((double)intYCentimeter - (double)szNumber.Height /2));
                        g.DrawString(strNumber, fnt, brNumber, ptString_Left);

                        Point ptString_Right = new Point((int)((double)ptBR.X + (double)szNumber.Width *1.1),
                                                         (int)((double)intYCentimeter - (double)szNumber.Height /2));
                        g.DrawString(strNumber, fnt, brNumber, ptString_Right);


                    }


                    if (bolDebug)
                        bmpSource.Save(@"c:\debug\bmpSource.bmp");
                }
            }
        }


        bool bolCanvasSize_Changed = false;
        void drawGrid()
        {
            if (bmpSource == null) return;

            if (bolCanvasSize_Changed)
                CanvasSize_Test();

            picViewer.lstRegions[0].bmpSource  = new Bitmap(bmpSource);
            
            Pen pGrid = new Pen(lbtnGridColor.BackColor);
            int intCrossSize = 10;
            Graphics g = Graphics.FromImage(picViewer.lstRegions[0].bmpSource);
            {
                switch (eGridStyle)
                {
                    case enuGridStyle.corners:
                        {
                            for (int intX = 1; intX < nudGridWidth.Value; intX++)
                                for (int intY = 1; intY < nudGridHeight.Value; intY++)
                                {
                                    Point ptCorner = GridCorner(intX, intY);
                                    g.DrawLine(pGrid, new Point(ptCorner.X - intCrossSize, ptCorner.Y), new Point(ptCorner.X + intCrossSize, ptCorner.Y));
                                    g.DrawLine(pGrid, new Point(ptCorner.X, ptCorner.Y - intCrossSize), new Point(ptCorner.X, ptCorner.Y + intCrossSize));
                                }
                        }
                        break;

                    case enuGridStyle.dash:
                    case enuGridStyle.dot:
                    case enuGridStyle.dashDot:
                    case enuGridStyle.dashDotDot:
                    case enuGridStyle.full:
                        {
                            if (dashStyle == null)
                            {
                                dashStyle = new System.Drawing.Drawing2D.DashStyle[(int)enuGridStyle._num];
                                dashStyle[(int)enuGridStyle.corners]
                                        = dashStyle[(int)enuGridStyle.full]
                                        = dashStyle[(int)enuGridStyle.none]
                                        = System.Drawing.Drawing2D.DashStyle.Solid;

                                dashStyle[(int)enuGridStyle.dash] = System.Drawing.Drawing2D.DashStyle.Dash;
                                dashStyle[(int)enuGridStyle.dashDot] = System.Drawing.Drawing2D.DashStyle.DashDot;
                                dashStyle[(int)enuGridStyle.dashDotDot] = System.Drawing.Drawing2D.DashStyle.DashDotDot;
                                dashStyle[(int)enuGridStyle.dot] = System.Drawing.Drawing2D.DashStyle.Dot;
                            }
                            pGrid.DashStyle = dashStyle[(int)eGridStyle];

                            for (int intX = 1; intX < nudGridWidth.Value; intX++)
                            {
                                int intLeft = (int)(intX * GridWidth);
                                g.DrawLine(pGrid, new Point(intLeft, 0), new Point(intLeft, bmpSource.Height));
                            }

                            for (int intY = 1; intY < nudGridHeight.Value; intY++)
                            {
                                int intTop = (int)(intY * GridHeight);
                                g.DrawLine(pGrid, new Point(0, intTop), new Point(bmpSource.Width, intTop));
                            }
                        }
                        break;

                    default:
                    case enuGridStyle.none:
                        { }
                        break;
                }

                if (DrawRuler)
                {
                    drawRuler(ref g);
                }
                drawQuadrantInfo(ref g);
            }
            g.Dispose();
            
            picViewer.lstRegions[0].Refreshed = false;
            picViewer.Display();

        }


        bool bolActivated = false;

        string strFilename = "\\GridMethod.bin";
        string Filename
        { 
            get 
            {
                return Directory + strFilename;
            }
        }

        string Directory
        {
            get 
            {
                string strRetVal = (System.IO.Directory.GetCurrentDirectory()).ToUpper();
                string strBinDebug = "\\BIN\\DEBUG";
                if (strRetVal.Length < strBinDebug.Length || string.Compare(strRetVal.Substring(strRetVal.Length - strBinDebug.Length), strBinDebug) != 0)
                    return System.IO.Directory.GetCurrentDirectory();
                else
                {
                    strRetVal = System.IO.Directory.GetCurrentDirectory();
                    int intIndex_LastRightSlash = strRetVal.LastIndexOf('\\');
                    if (intIndex_LastRightSlash > 0)
                    {
                        strRetVal = strRetVal.Substring(0, intIndex_LastRightSlash);
                        intIndex_LastRightSlash = strRetVal.LastIndexOf('\\');
                        if (intIndex_LastRightSlash > 0)
                        {
                            strRetVal = strRetVal.Substring(0, intIndex_LastRightSlash) ;
                            return strRetVal;
                        }
                    }
                }
                return System.IO.Directory.GetCurrentDirectory();
            }
        }
        private void FormGridMethod_Disposed(object sender, EventArgs e)
        {
            GridMethodProject_Save(Filename);
        }

        formFlash frmFlash = null;// new formFlash();

        private void FormGridMethod_Activated(object sender, EventArgs e)
        {
            //Top = 0;
            if (bolActivated) return;
            Hide();
            frmFlash = new formFlash();
            frmFlash.Show();
            frmFlash.Left = (Screen.PrimaryScreen.WorkingArea.Width - frmFlash.Width) / 2;
            frmFlash.Top = (Screen.PrimaryScreen.WorkingArea.Height - frmFlash.Height) / 2;

            placeObjects();
            GridMethodProject_Load(Filename);
            cMnu_Build();

            frmFlash.Hide();
            frmFlash.Dispose();
            frmFlash = null;
            Show();
            
            bolActivated = true;
        }

        void placeObjects()
        {
            int intBorder = 15;
            int intSpacer = 3;
            lbtnImage.Location = new Point(intBorder, intBorder);
            lbtnGridColor.Location = new Point(lbtnImage.Left, lbtnImage.Bottom + intSpacer);

            lbtnBackColor.Location = new Point(intBorder, lbtnGridColor.Bottom + intSpacer);
            
            lblGridSize.Location = new Point(lbtnImage.Left, lbtnBackColor.Bottom + intSpacer);
            nudGridWidth.Location = new Point(lblGridSize.Right + intSpacer, lblGridSize.Top);
            nudGridHeight.Location = new Point(nudGridWidth.Right + intSpacer , lblGridSize.Top);

            lblRatio_X.Location = new Point(lblGridSize.Left, nudGridHeight.Bottom + intSpacer);
            txtRatio_X.Location = new Point(lblRatio_X.Right + intSpacer, lblRatio_X.Top);

            lblRatio_Y.Location = new Point(lblGridSize.Left, txtRatio_X.Bottom + intSpacer);
            txtRatio_Y.Location = new Point(lblRatio_Y.Right + intSpacer, lblRatio_Y.Top);

            chkAutoSize.Location = new Point(lblGridSize.Left, txtRatio_Y.Bottom + intSpacer);

            lblCanvas_Width.Location = new Point(lblGridSize.Left, chkAutoSize.Bottom + intSpacer);
            txtCanvas_Width.Location = new Point(lblCanvas_Width.Right + intSpacer, lblCanvas_Width.Top);

            lblCanvas_Height.Location = new Point(lblGridSize.Left, txtCanvas_Width.Bottom + intSpacer);
            txtCanvas_Height.Location = new Point(lblCanvas_Height.Right + intSpacer, lblCanvas_Height.Top);

            grbControls.Width = txtCanvas_Height.Right+ 15;
            grbControls.Height = txtCanvas_Height.Bottom + intSpacer + 15;

            picAbout.Location = new Point(Width - 15 - picAbout.Width, grbControls.Top);
            picAbout.BringToFront();
        }
    }

    public class formFlash : FileDialog_GUI.PerPixelForm._PerPixelAlphaForm
    {
        public formFlash()
        {
            TopMost = true;
            ShowInTaskbar = false;
            Draw();
        }

        public void Draw()
        {
            Bitmap bmpFlash = (Bitmap)new Bitmap(Properties.Resources.Flash);
            bmpFlash.MakeTransparent(bmpFlash.GetPixel(0, 0));
            byte bytOpacity = (byte)(((int)(Opacity * 255.0)) % 256);
            SetBitmap(bmpFlash, bytOpacity);
        }

    }
    
}
